Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
129 commits
Select commit Hold shift + click to select a range
71562c9
feat(layout-v2): rework sidebar rail and add-action affordances
tsahimatsliah Jun 18, 2026
f6ca603
feat(layout-v2): move Happening Now from Profile to Explore panel
tsahimatsliah Jun 18, 2026
b119dc7
feat(layout-v2): show discovery hub sections in the Explore panel
tsahimatsliah Jun 18, 2026
3cede73
feat(layout-v2): move bookmarks into the Profile panel
tsahimatsliah Jun 20, 2026
41cd170
feat(layout-v2): rail tweaks — add rows, header cleanup, recent state
tsahimatsliah Jun 20, 2026
a0edae1
feat(layout-v2): fill Home icon when active, move Feed settings to Pr…
tsahimatsliah Jun 20, 2026
8e2ab57
feat(layout-v2): fold ⌘K hint into Search tooltip, drop avatar below …
tsahimatsliah Jun 20, 2026
1fe5596
feat(layout-v2): open collapsed peek only from panel-bearing icons
tsahimatsliah Jun 20, 2026
68b2273
feat(layout-v2): compass Explore icon + restore explore hub page headers
tsahimatsliah Jun 20, 2026
ebdcc90
feat(layout-v2): hover open-link on panel links, align profile header…
tsahimatsliah Jun 20, 2026
4523941
feat(layout-v2): keep selected indicator on hover; rail polish; trim …
tsahimatsliah Jun 20, 2026
609d3be
feat(layout-v2): opt-in open-link icon; group panel options with divi…
tsahimatsliah Jun 20, 2026
14ae640
feat(layout-v2): standard title headers, refined compass, profile ali…
tsahimatsliah Jun 20, 2026
add44e1
feat(layout-v2): explore sort options as tabs instead of a dropdown
tsahimatsliah Jun 20, 2026
06d775c
fix(layout-v2): scope open-link icon hover to its own row
tsahimatsliah Jun 20, 2026
3d24c8a
feat(layout-v2): quests settings divider; new-post divider below Live…
tsahimatsliah Jun 20, 2026
3ab7ce4
fix(layout-v2): settings panel not showing on nav + section collapse
tsahimatsliah Jun 20, 2026
c3f4ebc
fix(layout-v2): use the official library Compass icon SVGs
tsahimatsliah Jun 20, 2026
6a4c35b
feat(layout-v2): explore tabs use the directory pill navbar style
tsahimatsliah Jun 20, 2026
f8e4310
feat(layout-v2): squad/new-post panel tweaks; keep New Post panel whi…
tsahimatsliah Jun 20, 2026
c6affec
feat(layout-v2): rename profile panel/tooltip to "You"; widen gap bel…
tsahimatsliah Jun 20, 2026
a48ac37
feat(layout-v2): folder/squad add-row placement, focus ring, recent i…
tsahimatsliah Jun 20, 2026
71ced66
feat(layout-v2): API access in profile panel; align panel title; Best…
tsahimatsliah Jun 20, 2026
3f9013e
refactor(layout-v2): ExploreHubHeader resolves title from asPath first
tsahimatsliah Jun 20, 2026
97662e9
feat(layout-v2): explore order, hover clearing, keep panel on post pages
tsahimatsliah Jun 20, 2026
99278b0
refactor(layout-v2): track last non-post category in an effect, not d…
tsahimatsliah Jun 20, 2026
c2bbef3
fix(layout-v2): rail clicks no longer blocked by safe-zone; non-Plus …
tsahimatsliah Jun 20, 2026
8779e94
feat(layout-v2): typed Recent icons + active profile header
tsahimatsliah Jun 20, 2026
9c9812f
feat(layout-v2): drag-to-reorder rail tabs; segment-based category ro…
tsahimatsliah Jun 21, 2026
001ded9
Merge remote-tracking branch 'origin/main' into claude/keen-hopper-42…
tsahimatsliah Jun 21, 2026
979650f
feat(layout-v2): real avatars in Recent; move New post below Search
tsahimatsliah Jun 21, 2026
41b987a
feat(layout-v2): replace Game Center rail tab with a Streak tab
tsahimatsliah Jun 21, 2026
3fb0f6e
style(layout-v2): match rail separator color to sidebar borders; wide…
tsahimatsliah Jun 21, 2026
04c53c3
feat(layout-v2): avatar tab matches category tabs; Streak tab shows s…
tsahimatsliah Jun 21, 2026
c3aa5d5
refactor(layout-v2): reorganize streak/quests panel for clearer hiera…
tsahimatsliah Jun 21, 2026
6a3bca0
feat(layout-v2): drop the @handle from the profile panel header
tsahimatsliah Jun 21, 2026
47a1bd3
feat(layout-v2): square avatars, state-aware streak tab, redesigned s…
tsahimatsliah Jun 21, 2026
64fc1ec
feat(layout-v2): streak tab ring with dashed border; 30-day dotted ca…
tsahimatsliah Jun 21, 2026
77e07af
feat(layout-v2): big-number streak widget at top of streak panel
tsahimatsliah Jun 21, 2026
0edff84
feat(layout-v2): compact, borderless daily-quest list in streak panel
tsahimatsliah Jun 21, 2026
0bee526
style(layout-v2): smaller streak calendar dots with more spacing; rin…
tsahimatsliah Jun 21, 2026
81df785
style(layout-v2): smaller streak hero type (number, stats, date/timez…
tsahimatsliah Jun 21, 2026
4a7b450
feat(layout-v2): square streak tab matching other tabs; links above q…
tsahimatsliah Jun 21, 2026
5be6fcf
feat(layout-v2): customizable shortcuts dock in the sidebar
tsahimatsliah Jun 21, 2026
dcdb814
feat(layout-v2): make the avatar (You) tab draggable/reorderable
tsahimatsliah Jun 21, 2026
3cb9a10
fix(layout-v2): make shortcut dock drag/remove work; clearer remove a…
tsahimatsliah Jun 21, 2026
d6c2a68
feat(layout-v2): Phase 1 — drag any panel row into the shortcuts dock…
tsahimatsliah Jun 21, 2026
e7d73a3
fix(layout-v2): stop tooltips/panels overlapping the drag ghost (shar…
tsahimatsliah Jun 21, 2026
c84f401
style(layout-v2): dock add button uses a horizontal three-dots (more)…
tsahimatsliah Jun 21, 2026
d8fdadb
style(layout-v2): uniform rail spacing (gap-1 everywhere)
tsahimatsliah Jun 21, 2026
844f30d
fix(layout-v2): streak read-dot weight, row title truncation, profile…
tsahimatsliah Jun 21, 2026
3826eb7
feat(layout-v2): smarter shortcut icons; 3-dots on top; Support-style…
tsahimatsliah Jun 21, 2026
dc378af
style(layout-v2): equal, symmetric spacing for both rail separators
tsahimatsliah Jun 21, 2026
1f5d18c
fix(layout-v2): drag-out-to-remove now fires (pointerWithin collision)
tsahimatsliah Jun 22, 2026
08d35e6
feat(layout-v2): hide dock customize button until hover when empty
tsahimatsliah Jun 22, 2026
99f52de
feat(layout-v2): polished, brand-tinted dock drag indicators
tsahimatsliah Jun 22, 2026
d3c1993
feat(layout-v2): scrollable lower rail + fold shortcuts/tabs into More
tsahimatsliah Jun 22, 2026
c27c810
feat(layout-v2): sidebar toasts always run the auto-dismiss timer
tsahimatsliah Jun 22, 2026
d89e5fc
fix(layout-v2): restore empty-dock add menu; macOS-dock drag visuals
tsahimatsliah Jun 22, 2026
cea23d8
style(layout-v2): grey oval reorder marker; dashed brand drop box
tsahimatsliah Jun 22, 2026
6684d8c
fix(layout-v2): smooth shortcut reorder, no spring-back glitch
tsahimatsliah Jun 22, 2026
80d84bf
polish(layout-v2): tactile press, animated tray, tabular nums, reduce…
tsahimatsliah Jun 22, 2026
cc11562
polish(layout-v2): Remove pill scales+fades in across the drag boundary
tsahimatsliah Jun 22, 2026
b507384
Merge branch 'main' into claude/keen-hopper-4265af
tsahimatsliah Jun 22, 2026
710ea37
chore: re-trigger Vercel preview deploy (transient infra failures)
tsahimatsliah Jun 22, 2026
69fbc51
fix(layout-v2): customize tray clipped by scrollable rail — portal it
tsahimatsliah Jun 22, 2026
aff8f71
style(layout-v2): reorder line (not oval), solid remove chip, dashed …
tsahimatsliah Jun 22, 2026
898bda7
style(layout-v2): remove-drag chip shows the shortcut's own icon
tsahimatsliah Jun 22, 2026
e3eba89
style(layout-v2): float-coloured landing slot when reordering shortcuts
tsahimatsliah Jun 22, 2026
5d4d118
style(layout-v2): 1px dashed borders for add drop-zone and add ghost
tsahimatsliah Jun 22, 2026
16f9d92
style(layout-v2): show drop-area + landing skeleton while reordering too
tsahimatsliah Jun 22, 2026
24b8a93
fix(layout-v2): remove only when the whole icon clears the rail
tsahimatsliah Jun 22, 2026
5b009a9
feat(layout-v2): better dock drag feedback (drag image, live reorder,…
tsahimatsliah Jun 22, 2026
f7da1f9
style(layout-v2): panel-row drag image matches the dock add-ghost chip
tsahimatsliah Jun 22, 2026
1f65792
fix(layout-v2): stop runaway duplicate shortcuts on reorder
tsahimatsliah Jun 22, 2026
1f9cd50
fix(layout-v2): pin a squad/source with its image — no placeholder flash
tsahimatsliah Jun 22, 2026
2ec4fcc
chore: re-run CI (flaky test_shared; full suite green locally)
tsahimatsliah Jun 22, 2026
938760d
fix(layout-v2): stop folding shortcuts into More — scroll instead
tsahimatsliah Jun 22, 2026
a8d5530
feat(layout-v2): hybrid shortcut overflow + tray chrome matches Support
tsahimatsliah Jun 22, 2026
eded491
feat(layout-v2): fix tabs + bottom utilities, scroll only the shortcu…
tsahimatsliah Jun 22, 2026
23ca418
feat(layout-v2): drop a panel option at a chosen position in one shot
tsahimatsliah Jun 22, 2026
5c06be3
feat(layout-v2): squad Pin adds to sidebar shortcuts; drop Pinned sec…
tsahimatsliah Jun 22, 2026
cc536bf
style(layout-v2): separators frame the scrollable dock (don't scroll)
tsahimatsliah Jun 22, 2026
0c50a32
feat(layout-v2): drop tray items at a chosen slot; tray scrolls + flips
tsahimatsliah Jun 22, 2026
da255c9
feat(layout-v2): collapse tabs into a click More menu on tiny viewports
tsahimatsliah Jun 22, 2026
9639666
feat(layout-v2): one Streaks & gamification settings page; trim strea…
tsahimatsliah Jun 22, 2026
e837385
style(layout-v2): rail dropdowns open at the same X/width as Support
tsahimatsliah Jun 22, 2026
99034df
feat(layout-v2): one collapse — tabs + shortcuts fold into More together
tsahimatsliah Jun 22, 2026
a333ef3
style(layout-v2): uniform streak calendar dots regardless of state
tsahimatsliah Jun 22, 2026
c043434
style(layout-v2): streak stats on two rows; standard "Daily quests" h…
tsahimatsliah Jun 22, 2026
c49758f
feat(layout-v2): progressive rail overflow — tabs peel into More one …
tsahimatsliah Jun 22, 2026
e2063dc
fix(layout-v2): size read streak dot to match the others
tsahimatsliah Jun 22, 2026
97aca37
feat(layout-v2): give rail dropdowns a polished, consistent open anim…
tsahimatsliah Jun 22, 2026
c61eeb2
feat(layout-v2): staggered dropdown rows + sliding selected-tab pill
tsahimatsliah Jun 22, 2026
7f42d25
revert(layout-v2): drop per-row dropdown stagger; keep open/close tra…
tsahimatsliah Jun 22, 2026
4fe4e65
feat(layout-v2): compact streak date (e.g. "Jun 23"), full date on hover
tsahimatsliah Jun 23, 2026
899720b
feat(layout-v2): consistent tactile press on all rail icons
tsahimatsliah Jun 23, 2026
38d5c73
feat(layout-v2): XP reward color purple (was green) in the streak panel
tsahimatsliah Jun 23, 2026
349a120
Merge branch 'main' into claude/keen-hopper-4265af
tsahimatsliah Jun 23, 2026
49a4756
fix(layout-v2): streak panel crash — stable DOM trigger for date tooltip
tsahimatsliah Jun 23, 2026
5c293c7
feat(layout-v2): 1px ring around the rail avatar when selected
tsahimatsliah Jun 23, 2026
439a423
docs(storybook): StreakBadge stories with all streak states
tsahimatsliah Jun 23, 2026
4ce1f8b
feat(layout-v2): move Recent pages into the "You" tab
tsahimatsliah Jun 23, 2026
1406cdc
feat(layout-v2): streak tab follows gamification settings
tsahimatsliah Jun 23, 2026
cf989fc
fix(layout-v2): New post press feedback + no panel flicker on click
tsahimatsliah Jun 23, 2026
6f51d01
style(layout-v2): full quest titles; XP reward white + normal weight
tsahimatsliah Jun 23, 2026
a15a598
chore(layout-v2): drop redundant "Streaks" settings nav entry
tsahimatsliah Jun 23, 2026
f5a35c9
style(layout-v2): daily quest titles wrap fully (flex-1 + break-words)
tsahimatsliah Jun 23, 2026
4e03269
feat(layout-v2): redesign StreakBadge states
tsahimatsliah Jun 23, 2026
41cd6be
Merge remote-tracking branch 'origin/main' into claude/keen-hopper-42…
tsahimatsliah Jun 23, 2026
fdda0ff
style(layout-v2): read-today streak badge back to empty tile + pink f…
tsahimatsliah Jun 23, 2026
5eac580
fix(layout-v2): empty-dock customize button, quest details, today ring
tsahimatsliah Jun 23, 2026
99e786b
feat(layout-v2): single quests toggle; streak panel titles
tsahimatsliah Jun 23, 2026
7776868
feat(layout-v2): pink selected/hover for streak tab; today ring on top
tsahimatsliah Jun 23, 2026
bb0bec2
docs(storybook): StreakMonthCalendar stories (today ring over read day)
tsahimatsliah Jun 23, 2026
b82c4fc
feat(layout-v2): restructure daily quest rows (full-width title, circ…
tsahimatsliah Jun 23, 2026
84fbd79
feat(layout-v2): quest row — small radial bottom-right, steps on its …
tsahimatsliah Jun 23, 2026
23b81db
feat(layout-v2): streak badge border gray→white(hover)→pink(selected)…
tsahimatsliah Jun 23, 2026
9b315fc
fix(layout-v2): streak calendar today ring as an outer halo
tsahimatsliah Jun 23, 2026
fb8f9b2
feat(layout-v2): quest rows match panel hover (rounded pill, chevron …
tsahimatsliah Jun 23, 2026
241a35f
style(layout-v2): today ring a clean 2px border hugging the day (no gap)
tsahimatsliah Jun 23, 2026
109194c
chore: re-trigger Vercel preview (transient daily-webapp deploy failure)
tsahimatsliah Jun 23, 2026
831537b
style(layout-v2): radial in bottom strip with rewards; today ring 1px
tsahimatsliah Jun 23, 2026
7c6ed93
fix(layout-v2): show dock separators when empty so adding a shortcut …
tsahimatsliah Jun 23, 2026
f70a1e8
style(layout-v2): streak tab hover uses default surface-hover (not pink)
tsahimatsliah Jun 24, 2026
29dc5cb
feat(layout-v2): quest list fills panel height; empty-dock separator …
tsahimatsliah Jun 24, 2026
0a0d31c
style(layout-v2): streak tab uses neutral pill/label like other tabs
tsahimatsliah Jun 24, 2026
3047936
Merge branch 'main' into claude/keen-hopper-4265af
tsahimatsliah Jun 24, 2026
933f70e
feat(layout-v2): richer Recent icons — source logos + page-specific g…
tsahimatsliah Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions packages/shared/src/components/MainFeedLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import { ClientQuestEventType } from '../graphql/quests';
import { ProfileEmptyScreen } from './profile/ProfileEmptyScreen';
import { Origin } from '../lib/log';
import { ExploreTabs, tabToUrl, urlToTab } from './header';
import { FeedExploreTabs } from './header/FeedExploreTabs';
import { QueryStateKeys, useQueryState } from '../hooks/utils/useQueryState';
import { useSearchResultsLayout } from '../hooks/search/useSearchResultsLayout';
import useCustomDefaultFeed from '../hooks/feed/useCustomDefaultFeed';
Expand All @@ -85,8 +86,6 @@ import { isDevelopment, isProductionAPI, webappUrl } from '../lib/constants';
import { checkIsExtension } from '../lib/func';
import { useTrackQuestClientEvent } from '../hooks/useTrackQuestClientEvent';
import { useLayoutVariant } from '../hooks/layout/useLayoutVariant';
import { ExploreSectionTabs } from './header/ExploreSectionTabs';
import { ExploreSortDropdown } from './header/ExploreSortDropdown';

const FeedExploreHeader = dynamic(
() =>
Expand Down Expand Up @@ -250,7 +249,6 @@ export default function MainFeedLayout({
isPopular,
isAnyExplore,
isExploreLatest,
isDiscussed,
isSortableFeed,
isCustomFeed,
isSearch: isSearchPage,
Expand Down Expand Up @@ -707,14 +705,11 @@ export default function MainFeedLayout({
);
}, [isLaptop, onTabChange, tab]);

// v2 hoists the explore section tabs into the floating card's
// page-header strip (matching the SquadDirectoryLayout pattern). The
// inline FeedExploreComponent is suppressed below to avoid showing
// the same tabs twice.
// The Discussions feed (/discussed) is part of the Explore hub — show the
// same section tabs there so the hub persists. The Sort dropdown is only
// for the actual Explore sorts, so it stays gated on isAnyExplore.
const showExploreV2PageHeader = (isAnyExplore || isDiscussed) && isV2;
// v2 reaches the Explore hub sections (Explore, Tags, Sources, Leaderboard,
// Discussions) from the sidebar's Explore panel, so the page header no longer
// carries a section-tab strip. The header now only hosts the Explore sort
// dropdown, so it's gated on isAnyExplore.
const showExploreV2PageHeader = isAnyExplore && isV2;

// v2 also hoists the regular page-header strip up here, OUTSIDE
// `FeedPageLayoutComponent`, so it can span the full floating-card
Expand Down Expand Up @@ -753,8 +748,9 @@ export default function MainFeedLayout({
<>
{showExploreV2PageHeader && (
<header className={classNames(pageHeaderClassName, '!py-0')}>
<ExploreSectionTabs />
{isAnyExplore && <ExploreSortDropdown />}
{/* Sort options as pill tabs — same navbar as the Tags / Squad
directory pages, not the underlined TabContainer. */}
<FeedExploreTabs />
</header>
)}
{showFeedV2PageHeader && (
Expand Down
28 changes: 22 additions & 6 deletions packages/shared/src/components/header/ExploreHubHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
import type { ReactElement, ReactNode } from 'react';
import React from 'react';
import { useRouter } from 'next/router';
import { PageHeader } from '../layout/PageHeader';
import { ExploreSectionTabs } from './ExploreSectionTabs';

// Shared v2 header for the Explore hub's directory pages (Tags, Sources,
// Leaderboard, Best of). Keeps the section-tab strip and its height
// (`!py-0`) consistent in one place. Optional children render as header
// actions (e.g. the "Suggest source" button).
// The Explore hub sections live in the sidebar's Explore panel, so the page
// header is just the standard title strip (same as Analytics / Settings) —
// no breadcrumb, no icon. The title is derived from the route.
const hubTitles: { match: (path: string) => boolean; label: string }[] = [
{ match: (path) => path.startsWith('/posts/best-of'), label: 'Best of' },
{ match: (path) => path.startsWith('/sources'), label: 'Sources' },
{ match: (path) => path.startsWith('/users'), label: 'Leaderboard' },
{ match: (path) => path.startsWith('/discussed'), label: 'Discussions' },
{ match: (path) => path.startsWith('/posts'), label: 'Explore' },
];

// Shared v2 header for the Explore hub's directory pages (Sources, Leaderboard,
// Best of). Optional children render as header actions (e.g. "Suggest source").
export function ExploreHubHeader({
children,
}: {
children?: ReactNode;
}): ReactElement {
const router = useRouter();
// asPath-first (the resolved URL) — consistent with FeedExploreTabs and
// correct for dynamic routes where pathname is the template.
const path = (router.asPath || router.pathname || '').split('?')[0];
const title =
hubTitles.find((entry) => entry.match(path))?.label ?? 'Explore';

return (
<PageHeader title={<ExploreSectionTabs />} className="!py-0">
<PageHeader title={title} className="!py-0">
{children}
</PageHeader>
);
Expand Down
70 changes: 0 additions & 70 deletions packages/shared/src/components/header/ExploreSectionTabs.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions packages/shared/src/components/header/FeedExploreHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import { useRouter } from 'next/router';
import classNames from 'classnames';
import { BreadCrumbs } from './BreadCrumbs';
import { CalendarIcon, HotIcon } from '../icons';
import { CalendarIcon, CompassIcon } from '../icons';
import { IconSize } from '../Icon';
import TabList from '../tabs/TabList';
import { Tab, TabContainer } from '../tabs/TabContainer';
Expand Down Expand Up @@ -91,7 +91,7 @@ export function FeedExploreHeader({
isListMode && 'tablet:pt-4 laptop:pt-5',
)}
>
<HotIcon size={IconSize.XSmall} secondary /> Explore
<CompassIcon size={IconSize.XSmall} secondary /> Explore
</BreadCrumbs>
)}
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -1,68 +1,67 @@
import type { ReactElement } from 'react';
import React from 'react';
import { useRouter } from 'next/router';
import { ButtonSize, ButtonVariant } from '../buttons/Button';
import {
SquadDirectoryNavbar,
SquadDirectoryNavbarItem,
} from '../squads/layout/SquadDirectoryNavbar';
import { Dropdown } from '../fields/Dropdown';
import { CalendarIcon } from '../icons';
import { IconSize } from '../Icon';
import { ButtonSize, ButtonVariant } from '../buttons/Button';
import { ExploreTabs, tabToUrl, urlToTab } from './FeedExploreHeader';
import { ExploreTabs, urlToTab } from './FeedExploreHeader';
import { QueryStateKeys, useQueryState } from '../../hooks/utils/useQueryState';
import { periodTexts } from '../layout/common';

const sortLabels = Object.values(ExploreTabs);
const sortsWithPeriod: ExploreTabs[] = [
ExploreTabs.MostUpvoted,
ExploreTabs.BestDiscussions,
];

// v2 Explore: switch the feed's ranking via a "Sort" dropdown rather than a
// second row of tabs — sorting a feed isn't navigating to a sibling page, so
// a dropdown reads cleaner (Reddit/GitHub pattern). Each sort is still its
// own route, so selecting one navigates.
export function ExploreSortDropdown(): ReactElement {
// Explore sort tabs rendered with the same pill navbar as the Tags / Squad
// directory pages (SquadDirectoryNavbar), instead of the underlined TabContainer
// — so the look-and-feel matches the rest of the v2 directory headers. The
// date-range filter stays as a compact icon dropdown for the applicable sorts.
export function FeedExploreTabs(): ReactElement {
const router = useRouter();
const currentPath = (router.asPath || router.pathname).split('?')[0];
const activeTab = urlToTab[currentPath] ?? ExploreTabs.Popular;
const selectedIndex = Math.max(0, sortLabels.indexOf(activeTab));
const [period, setPeriod] = useQueryState({
key: [QueryStateKeys.FeedPeriod],
defaultValue: 0,
});

return (
<span className="ml-auto flex items-center gap-2">
<div className="flex w-full min-w-0 items-center gap-2">
<SquadDirectoryNavbar
aria-label="Explore sort"
className="!mx-0 min-w-0 flex-1 !border-0 !px-0"
>
{Object.entries(urlToTab).map(([url, label]) => (
<SquadDirectoryNavbarItem
key={label}
buttonSize={ButtonSize.Small}
isActive={currentPath === url}
label={label}
path={url}
ariaLabel={`Show ${label}`}
/>
))}
</SquadDirectoryNavbar>
{sortsWithPeriod.includes(activeTab) && (
<Dropdown
iconOnly
shouldIndicateSelected
icon={<CalendarIcon size={IconSize.Small} />}
buttonSize={ButtonSize.Small}
buttonVariant={ButtonVariant.Float}
// Render the date filter as a true icon-only square button (the
// shared Dropdown otherwise lays its trigger out as a full-width
// value field). Matches the design system's icon-only Small spec
// (`IconOnlySizeToClassName`) and the v2 layout's compact icon
// buttons: 32px square, rounded-10, no padding.
className={{ button: '!size-8 !rounded-10 !p-0' }}
selectedIndex={period}
options={periodTexts}
onChange={(_, index) => setPeriod(index)}
buttonAriaLabel="Filter by date range"
/>
)}
<Dropdown
selectedIndex={selectedIndex}
options={sortLabels}
buttonSize={ButtonSize.Small}
buttonVariant={ButtonVariant.Float}
buttonAriaLabel="Sort posts"
onChange={(value) => {
const url = tabToUrl[value as ExploreTabs];
if (url) {
router.push(url).catch(() => undefined);
}
}}
/>
</span>
</div>
);
}
8 changes: 8 additions & 0 deletions packages/shared/src/components/icons/Compass/filled.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions packages/shared/src/components/icons/Compass/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { ReactElement } from 'react';
import React from 'react';
import type { IconProps } from '../../Icon';
import Icon from '../../Icon';
import OutlinedIcon from './outlined.svg';
import FilledIcon from './filled.svg';

export const CompassIcon = (props: IconProps): ReactElement => (
<Icon {...props} IconPrimary={OutlinedIcon} IconSecondary={FilledIcon} />
);

export default CompassIcon;
5 changes: 5 additions & 0 deletions packages/shared/src/components/icons/Compass/outlined.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/shared/src/components/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export * from './Codeberg';
export * from './CodePen';
export * from './Coin';
export * from './CommunityPicksIcon';
export * from './Compass';
export * from './Cookie';
export * from './Copy';
export * from './Core';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,15 @@ function NotificationsBell({
<a
href={`${webappUrl}notifications`}
aria-label="Notifications"
// It's a tab in the rail tablist; the role makes `aria-selected`
// valid and lets the v2 rail's shared sliding pill track this tab
// like the others (the pill renders the selected background, so here
// we only own the active text color).
role="tab"
aria-selected={atNotificationsPage}
className={classNames(
railTabClass,
atNotificationsPage && 'bg-background-default !text-text-primary',
atNotificationsPage && '!text-text-primary',
)}
onClick={onNavigateNotifications}
>
Expand All @@ -84,7 +90,7 @@ function NotificationsBell({
)}
</span>
{!railHideLabel && (
<span className={railTabLabelClass}>Alerts</span>
<span className={railTabLabelClass}>Activity</span>
)}
</a>
</Link>
Expand Down
21 changes: 14 additions & 7 deletions packages/shared/src/components/notifications/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,11 @@ const Toast = ({
return;
}

// Auto-dismiss (and the countdown ring) only when the setting is on and the
// toast isn't explicitly persistent; otherwise it stays until dismissed.
const shouldAutoDismiss = autoDismissNotifications && !toast.persistent;
// Auto-dismiss (and the countdown ring) when the setting is on — or a toast
// forces it — and the toast isn't explicitly persistent; otherwise it stays
// until dismissed.
const shouldAutoDismiss =
(autoDismissNotifications || toast.forceAutoDismiss) && !toast.persistent;

if (!toastRef.current) {
toastRef.current = toast;
Expand Down Expand Up @@ -133,9 +135,13 @@ const Toast = ({
return;
}

// No running countdown when auto-dismiss is off or the toast is persistent,
// so clear directly; otherwise let the timed animation play out.
if (!autoDismissNotifications || acted.persistent) {
// No running countdown when auto-dismiss is off (and not forced) or the
// toast is persistent, so clear directly; otherwise let the timed animation
// play out.
if (
(!autoDismissNotifications && !acted.forceAutoDismiss) ||
acted.persistent
) {
toastRef.current = null;
client.setQueryData(TOAST_NOTIF_KEY, null);
return;
Expand Down Expand Up @@ -192,7 +198,8 @@ const Toast = ({
// The dismiss ring is the auto-dismiss countdown made visible, so it shows
// exactly when the toast will auto-dismiss (setting on + not persistent).
// dashoffset drains 0→100 as the remaining time elapses.
const shouldAutoDismiss = autoDismissNotifications && !isPersistentToast;
const shouldAutoDismiss =
(autoDismissNotifications || toast.forceAutoDismiss) && !isPersistentToast;
const showRing = shouldAutoDismiss && toast.timer > 0;
const remaining = toast.timer > 0 ? (timer / toast.timer) * 100 : 0;
const dashoffset = Math.min(100, Math.max(0, 100 - remaining));
Expand Down
Loading
Loading