From 29ee6720610b34f8df1c9b3ab2b3511a20bbf5ce Mon Sep 17 00:00:00 2001 From: Mir Bhatia Date: Wed, 6 May 2026 10:53:57 +0200 Subject: [PATCH] Add docs --- .../docs/patterns/10-quick-filters.md.erb | 39 +++++++++++++ .../op_primer/quick_filter_preview.rb | 56 +++++++++++++++++++ .../quick_filter_preview/boolean.html.erb | 10 ++++ .../quick_filter_preview/segmented.html.erb | 12 ++++ .../segmented_with_active_filter.html.erb | 12 ++++ 5 files changed, 129 insertions(+) create mode 100644 lookbook/docs/patterns/10-quick-filters.md.erb create mode 100644 lookbook/previews/op_primer/quick_filter_preview.rb create mode 100644 lookbook/previews/op_primer/quick_filter_preview/boolean.html.erb create mode 100644 lookbook/previews/op_primer/quick_filter_preview/segmented.html.erb create mode 100644 lookbook/previews/op_primer/quick_filter_preview/segmented_with_active_filter.html.erb diff --git a/lookbook/docs/patterns/10-quick-filters.md.erb b/lookbook/docs/patterns/10-quick-filters.md.erb new file mode 100644 index 00000000000..05840c2f635 --- /dev/null +++ b/lookbook/docs/patterns/10-quick-filters.md.erb @@ -0,0 +1,39 @@ +Quick filters are lightweight controls that let users toggle a single filter without opening the full filter panel. Each click can navigate to a new URL with updated `filters` and `sortBy` params, +preserving any other active filters. + +There are currently two variants: +* SegmentedComponent +* BooleanComponent + +## SegmentedComponent + +A general purpose segmented control that accepts any number of items via `with_item` slots. +Each item has a label and a filter value (`nil` means "no filter" and is useful for an "All" option). + +<%= embed OpPrimer::QuickFilterPreview, :segmented, panels: %i[source] %> + +Note: Clicking on buttons in the above preview will break it and redirect to the meetings index page. + +### With an active filter or order overrides + +When the query already has a matching filter value, the corresponding item is rendered as selected. +You can also pass `orders` to define the sort order per value. + +<%= embed OpPrimer::QuickFilterPreview, :segmented_with_active_filter, panels: %i[source] %> + +Note: Clicking on buttons in the above preview will break it and redirect to the meetings index page. + +## BooleanComponent + +A specialized subclass of `SegmentedComponent` for boolean (true/false) filters. +It always renders exactly two items using `t` and `f` as filter values. +Labels are provided via `true_label` and `false_label`. + +<%= embed OpPrimer::QuickFilterPreview, :boolean, panels: %i[source] %> + +Note: Clicking on buttons in the above preview will break it and redirect to the meetings index page. + +## Parameters + +* `BooleanComponent` requires `true_label` and `false_label`. +* `SegmentedComponent` accepts items via a block using `with_item(label:, value:)`. diff --git a/lookbook/previews/op_primer/quick_filter_preview.rb b/lookbook/previews/op_primer/quick_filter_preview.rb new file mode 100644 index 00000000000..bd680dd0858 --- /dev/null +++ b/lookbook/previews/op_primer/quick_filter_preview.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module OpPrimer + # @logical_path OpenProject/Primer + class QuickFilterPreview < Lookbook::Preview + def segmented + render_with_template(locals: { query: meeting_query }) + end + + def segmented_with_active_filter + query = meeting_query + query.where("time", "=", ["future"]) + render_with_template(locals: { query: }) + end + + def boolean + query = meeting_query + query.where("type", "=", ["t"]) + render_with_template(locals: { query: }) + end + + private + + def meeting_query + Queries::Meetings::MeetingQuery.new(user: User.current) + end + end +end diff --git a/lookbook/previews/op_primer/quick_filter_preview/boolean.html.erb b/lookbook/previews/op_primer/quick_filter_preview/boolean.html.erb new file mode 100644 index 00000000000..ac28d36fed7 --- /dev/null +++ b/lookbook/previews/op_primer/quick_filter_preview/boolean.html.erb @@ -0,0 +1,10 @@ +<%= render( + OpPrimer::QuickFilter::BooleanComponent.new( + name: "Recurring", + query: query, + filter_key: :type, + true_label: "Recurring", + false_label: "One-time", + path_args: [:meetings] + ) + ) %> diff --git a/lookbook/previews/op_primer/quick_filter_preview/segmented.html.erb b/lookbook/previews/op_primer/quick_filter_preview/segmented.html.erb new file mode 100644 index 00000000000..ca795c2a13b --- /dev/null +++ b/lookbook/previews/op_primer/quick_filter_preview/segmented.html.erb @@ -0,0 +1,12 @@ +<%= render( + OpPrimer::QuickFilter::SegmentedComponent.new( + name: "Meeting type", + query: query, + filter_key: :type, + path_args: [:meetings] + ) + ) do |component| + component.with_item(label: "All", value: nil) + component.with_item(label: "One-time", value: "f") + component.with_item(label: "Recurring", value: "t") + end %> diff --git a/lookbook/previews/op_primer/quick_filter_preview/segmented_with_active_filter.html.erb b/lookbook/previews/op_primer/quick_filter_preview/segmented_with_active_filter.html.erb new file mode 100644 index 00000000000..c87266f8f02 --- /dev/null +++ b/lookbook/previews/op_primer/quick_filter_preview/segmented_with_active_filter.html.erb @@ -0,0 +1,12 @@ +<%= render( + OpPrimer::QuickFilter::SegmentedComponent.new( + name: "Time", + query: query, + filter_key: :time, + orders: { "future" => { start_time: :asc }, "past" => { start_time: :desc } }, + path_args: [:meetings] + ) + ) do |component| + component.with_item(label: "Upcoming", value: "future") + component.with_item(label: "Past", value: "past") + end %>