← Cycles
Design · c88

Global Filter

activecreated 2026-09-15· last activity 2026-09-18· mode: archaeology → assemblage — surfacing a pattern from production use, then composing a new form from existing pieces

Extract app.qpoint.io's global filter into q-nuxt-layer as presentational components (Phase 1), then design and build a v2 segmented-bar redesign (Phase 2).

New in this cycle: Filter v2 — a display-only segmented bar with negation, plus FilterTriggerBar for contextual quick-filtering

Why

app.qpoint.io's filter bar (teleported into the top nav across ~25 pages) is a proven, working component that predates the shared layer. Phase 1 gets the existing implementation into the layer so v2 has a real foundation to iterate on. Phase 2 implements the v2 redesign from mockups, including a new FilterTriggerBar component for contextual quick-filtering and the v2 Filter bar as a segmented control with negation support.

Objective

Phase 1: Extract the presentational Filter namespace and FilterDatasetViewSelector from app.qpoint.io into q-nuxt-layer as Ux-auto-named components (via the components/filter/ directory convention), keeping business logic (route/authStore sync, domain composables) local to app.qpoint.io.

Phase 2: Redesign the Filter bar as a segmented control (empty "Add Filter" pill → populated state as continuous bar with ADD trigger, two-row FilterItem pills, Config button) and build supporting v2 components (FilterItem with negation glyph, FilterInlineEdit restyled, FilterTriggerBar for contextual quick-filtering). Document the full namespace on the design site.

Scope

Phase 1 (Extraction — 2026-09-15):

Source files (app.qpoint.io):

  • app/components/filter/*.vue: index, Item, InlineEdit, Manage, Embed, Timeframe, ManageItem, DatasetViewSelector
  • app/components/ux/TagAutocomplete.vue
  • app/utils/filters.js

Destination (q-nuxt-layer):

  • components/filter/*.vue (all presentational components)
  • components/ux/TagAutocomplete.vue
  • A composable/util for filter-shape logic

Design site:

  • New compound /components page for the Filter namespace
  • Unregistered lab page design/app/pages/pages/phase2-global-filter.vue for v2

Phase 2 (v2 Redesign — 2026-09-16):

Source mockups (designs/):

  • global-filter.png (v2 segmented bar in populated state)
  • bar-trigger.png (FilterTriggerBar contextual variant)
  • filter-in-context.png (both components together)

Build output:

  • Phase 1 components moved to old/ namespace in q-nuxt-layer (components/filter/old/*.vue, auto-registered as FilterOld*, preserving original behavior for backward compat while v2 hardens)
  • New v2 components under live names: Filter (segmented bar), FilterItem (two-row pill with negation), FilterInlineEdit (restyled typeahead), FilterTriggerBar (new — contextual quick-filter bar)
  • Unchanged components: FilterDatasetViewSelector, leveraging existing FilterOldEmbed/FilterOldManage for Embed and Config modes (no v2 design yet)
  • New asset: FilterEndcapPlaceholder (checkerboard standins for manual SVG endcap art later)
  • Design site: demo files for all v2 and legacy components, updated /components with new filter-old group, lab page phase2-global-filter.vue demonstrating two-way sync pattern

Explicitly NOT in scope:

  • Swapping app.qpoint.io's live pages to consume the layer components (separate step after release)
  • v2 redesign of FilterManage modal (Config button still opens FilterOldManage; no design exists yet for modal v2)
  • Sticky positioning or collision-avoidance with NavJumpPills (strategy documented; implementation owned by consumer pages, not the component itself)

Key Changes

Phase 1 extraction (2026-09-15): All 8 components extracted into q-nuxt-layer/components/filter/: Filter, FilterItem, FilterInlineEdit, FilterManage, FilterEmbed, FilterTimeframe, FilterManageItem, FilterDatasetViewSelector — plus q-nuxt-layer/utils/filter.ts for filter-shape constants/types. During extraction, discovered FilterTimeframe and FilterManage embedded business logic (Pinia store, route/org composables) not visible from names alone; decoupled into props/emits, business logic left local. DatasetViewSelector similarly decoupled. TagAutocomplete.vue found to be dead code (hardcoded dummy component) and excluded rather than moved. All 8 documented on the design site with new filter group in component-registry.ts, demo files under app/pages/components/_demos/, live at /components/filter/*. Built v2 lab workspace page app/pages/pages/phase2-global-filter.vue (unregistered, composes real Phase-1 components). Verified via local dev server — all new pages render without console warnings/errors. Decisions recorded in plan.md.

Phase 2 redesign (2026-09-16): Implemented v2 segmented-bar Filter and supporting components per mockup set: Phase-1 components moved into q-nuxt-layer/components/filter/old/ namespace (auto-registered as FilterOld*, FilterOldDatasetViewSelector) with internal cross-references rewritten; new v2 Filter rebuilt as segmented control (empty "Add Filter" pill, populated state as continuous bar with ADD trigger, two-row FilterItem pills, Config button); new FilterItem with italic key + bold value split across two rows, replaced "!=" text with slash-circle negation glyph; FilterInlineEdit restyled into two-row chrome with same typeahead behavior; FilterDatasetViewSelector built unchanged under live name (unchanged component); new FilterTriggerBar component (contextual quick-filter bar with optional key-select dropdown + single-select value pills). Reused existing q-nuxt-layer assets for icons (gear.svg for Config, no.svg for negation glyph—no new icon assets needed). Updated app/data/component-registry.ts: new filter-old group (id, label "Filter (Legacy)", description), v2 entries added for Filter/FilterItem/FilterInlineEdit/FilterTriggerBar under filter group, Phase-1 entries renamed to FilterOld* under filter-old group. Created demo files: 8 Phase-1 demos renamed to FilterOld*.vue, FilterDatasetViewSelector.vue copied to FilterOldDatasetViewSelector.vue, new demos for Filter.vue/FilterItem.vue/FilterInlineEdit.vue/FilterTriggerBar.vue. Rewrote lab page phase2-global-filter.vue demonstrating v2 Filter alongside FilterTriggerBar wired to same shared keyValFilters ref, proving two-way sync pattern. Left for future: v2 redesign of FilterManage modal (Config still opens FilterOldManage), sticky positioning behavior (strategy recommendations captured; consumer-owned implementation). Verified all new/updated pages via local dev server — all render 200 with no console/icon-resolution errors, screengrabs captured to public/cycles/c88.global-filter/.

Phase 2 formalized as a site-wide bucket (2026-09-17): The design site's own /pages index had a single "Phase 2" card pointing at c85's unrelated phase2-chat-transcript.vue — a naming collision with this cycle's own "Phase 2 redesign" work. Resolved by relocating: c85's chat-transcript moved into app/pages/pages/phase1/chat-transcript.vue (registered phase: 'phase1', sessions group — it was always phase1-world-adjacent, not a v2 redesign), and this cycle's lab page moved from the flat phase2-global-filter.vue to app/pages/pages/phase2/global-filter.vue, the first page under a proper phase2 bucket. Added 'phase2' to PagePhase, a pageHref branch (/pages/phase2/<slug>), a phase2 pageGroup, and a new app/pages/pages/phase2/index.vue landing page (mirrors phase1/index.vue's tone, lists every phase: 'phase2' registry entry — no Linear-tracked plan needed since Phase 2 has none). /pages' Phase 2 card now points at /pages/phase2 and describes it as "v2 redesigns of components already extracted in Phase 1" rather than naming chat-transcript.

Outcome

Phase 1 and Phase 2 complete. The global filter has been successfully extracted into q-nuxt-layer with both legacy (FilterOld*) and new v2 components (Filter, FilterItem, FilterInlineEdit, FilterTriggerBar) fully implemented and documented on the design site.

Deliverables:

  • Phase-1 components archived in q-nuxt-layer/components/filter/old/ namespace, backward-compatible
  • v2 redesigned Filter bar (segmented control) shipping under live Filter name with negation support
  • New FilterTriggerBar component for contextual quick-filtering
  • All 12 components (8 legacy + 4 v2) with demo pages on /components/filter and /components/filter-old
  • Lab page at /pages/phase2/global-filter (2026-09-17: relocated from the flat phase2-global-filter.vue, now the seed of the formal /pages/phase2 landing page) demonstrating two-component integration and state-sync pattern

Next steps:

  • Merge v2 components into q-nuxt-layer release — shipped in q-nuxt-layer 0.9.13 (2026-09-18)
  • Swap app.qpoint.io's live pages to consume v2 Filter when layer is published
  • v2 redesign of FilterManage modal when design direction is set
  • Manual SVG endcap art to replace FilterEndcapPlaceholder checkerboard standins

Visual record

10 captures — heroes, page slices, and full-page renders. Click to view.

Filter v2 with the Config modal open — edits happen there, the bar stays display-only
Filter v2 with the Config modal open — edits happen there, the bar stays display-only open page →history · 2 moments →
FilterItem — one segment of the v2 bar
FilterItem — one segment of the v2 bar open page →history · 2 moments →
Phase 1 — the legacy filter extracted verbatim into filter/old/ (FilterOld*)
Phase 1 — the legacy filter extracted verbatim into filter/old/ (FilterOld*) open page →
Filter v2, first segmented-bar pass
Filter v2, first segmented-bar pass open page →history · 2 moments →
Filter v2, iteration 3
Filter v2, iteration 3 open page →history · 2 moments →
Filter v2, iteration 4
Filter v2, iteration 4 open page →history · 2 moments →
Filter v2, iteration 5
Filter v2, iteration 5 open page →history · 2 moments →
Filter v2, iteration 6
Filter v2, iteration 6 open page →history · 2 moments →
/pages/phase2/global-filter lab page — Filter + FilterTriggerBar integration and the state-sync pattern
/pages/phase2/global-filter lab page — Filter + FilterTriggerBar integration and the state-sync pattern open page →
FilterTriggerBar — contextual quick-filter strip wired to the same shared filter state
FilterTriggerBar — contextual quick-filter strip wired to the same shared filter state open page →

Artifacts

Qpoint Brand Style Guide