Skip to content

feat(shortcuts): redesign new-tab shortcuts hub#5903

Open
tsahimatsliah wants to merge 10 commits intomainfrom
feat/shortcuts-hub-redesign
Open

feat(shortcuts): redesign new-tab shortcuts hub#5903
tsahimatsliah wants to merge 10 commits intomainfrom
feat/shortcuts-hub-redesign

Conversation

@tsahimatsliah
Copy link
Copy Markdown
Member

@tsahimatsliah tsahimatsliah commented Apr 21, 2026

Summary

Replaces the legacy "My shortcuts vs Most visited" toggle with a unified hub where users can add, edit, remove and reorder their shortcuts directly on the new tab — and import from browser top sites or the bookmarks bar on demand.

  • New hub UI (ShortcutLinksHub) with draggable tiles, per-tile menu (edit/remove), dashed + add-tile, and a toolbar overflow menu (Add / Import from browser / Import from bookmarks / Hide / Manage).
  • Rich shortcut model with custom name, optional custom icon URL, and accent color fallback when no favicon is available (persisted via SettingsFlags.shortcutMeta).
  • Manage modal with capacity counter (N/12), inline reorder, edit/remove, empty state with three CTAs (Add / Most visited / Bookmarks), and revoke-permission buttons.
  • Edit modal with live tile preview, validated URL/name/icon fields, and a color palette.
  • Import flow (ShortcutImportFlow) that coordinates permission prompts, silent imports when capacity fits, and a picker modal (ImportPickerModal) when the list exceeds free slots.
  • One-time auto-migration (useShortcutsMigration) seeds existing top-sites users so they don't land on an empty hub.
  • Undo toast (6s) on remove, keyboard DnD support, aria-live reorder announcements, focus rings, motion-reduce-aware transitions.
  • bookmarks added to manifest optional_permissions (Chrome/Edge/Opera + Firefox).

Rollout

Ships behind the shortcuts_hub GrowthBook feature flag (featureShortcutsHub). Legacy code path is untouched and kept as the fallback. Existing ShortcutLinks.spec.tsx pins useConditionalFeature to false so the legacy UI stays covered.

Notable fixes (late in the branch)

  • useBrowserBookmarks now initialises bookmarks to undefined and only promotes to [] when the permission is actually granted, so the manage modal no longer falsely shows "Revoke bookmarks access" and the import flow correctly surfaces the permission prompt.
  • ShortcutImportFlow was rewritten as a small state machine: it distinguishes "no permission", "permission granted but empty", "fits capacity → silent import", and "exceeds capacity → picker". Permission modals are rendered inline so cancel/close actually resets showImportSource.
  • DnD click-through on tiles is guarded by PointerSensor activationConstraint: { distance: 5 }, a toolbar-level onClickCapture with a justDraggedRef, and a per-tile isDragging check so dragging never navigates.

Test plan

  • pnpm test -- --testPathPattern='ShortcutLinks' passes (10/10).
  • Lint clean on changed files.
  • With flag off: legacy UI unchanged on newtab.daily.dev and extension new tab.
  • With flag on: hub renders, add/edit/remove/reorder all round-trip to settings.
  • Import from browser: first click prompts for topSites permission; granting imports up to 12 sites (picker shown if > free slots); denying closes cleanly.
  • Import from bookmarks: first click prompts for bookmarks permission; granting imports bookmarks bar (picker if > free slots); empty bookmarks bar shows a toast.
  • Remove shows undo toast that restores the shortcut and its meta within 6s.
  • Reorder via drag-and-drop persists; clicking a tile after a drag never navigates mid-drag.
  • Reduced-motion users don't see the lift/hover transforms.
  • Existing users with customLinks see them preserved; existing top-sites-only users get a one-time migration into customLinks.

Made with Cursor

Preview domain

https://feat-shortcuts-hub-redesign.preview.app.daily.dev

Replaces the "My shortcuts vs Most visited" toggle with a hybrid hub where
users can add, edit, remove and reorder shortcuts directly, enrich them with
custom names/icons/accent colors, and import from browser top sites or the
bookmarks bar on demand.

The hub ships behind the `shortcuts_hub` GrowthBook flag. Legacy code paths
and tests are preserved; the spec mocks the flag to false to keep the
existing UI covered.

Made-with: Cursor
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Apr 21, 2026 2:40pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
storybook Ignored Ignored Apr 21, 2026 2:40pm

Request Review

Adds an ImageInput uploader to the shortcut edit modal so users can pick or
drag & drop an image file instead of hunting for an icon URL. The file is
uploaded via uploadContentImage and the returned CDN URL is stored in
shortcutMeta.iconUrl, keeping the persistence model unchanged.

The URL input is kept as a secondary fallback ("Or paste an image URL
instead") for power users. Save is disabled while an upload is in flight,
and the live tile preview shows the base64 preview immediately for
instant feedback.

Made-with: Cursor
The color was only visible in two edge cases (hover glow + letter chip
fallback when no favicon loads), which rarely surfaced in practice. The
picker added cognitive load to the edit form for negligible UX benefit.

Tiles still receive a deterministic color derived from the URL in
ShortcutTile, so the letter-chip fallback keeps its polish. Legacy
shortcutMeta.color values continue to be respected.

Made-with: Cursor
Previously the hub rendered every entry in customLinks, so legacy data,
cross-device sync, or a direct settings mutation holding > 12 links would
spill tiles across multiple rows and push the feed down.

Mirror Chrome's fixed-cap behaviour: slice the rendered list to
MAX_SHORTCUTS, append overflow during reorder so we never drop links
silently, and surface a "+N more" affordance that opens the Manage modal
where the user can see and remove the excess.

Made-with: Cursor
Replaces the rotated hamburger affordance on shortcut tiles and manage-
modal rows with a proper 6-dot grip icon, matching the daily.dev Figma
design system ("Shapes/<Drag>"). The new icon follows the standard
filled/outlined pattern used by every other icon in the library.

Made-with: Cursor
Introduces an explicit "My shortcuts" vs "Most visited sites" mode
(persisted as shortcutsMode in SettingsFlags) so users stop guessing
whether the hub is showing a live browser feed or their curated list:

- Hub renders topSites read-only in auto mode, customLinks editable in
  manual mode; switching lives in the overflow menu and in a Chrome-
  style radio group inside Manage.
- Auto mode with no topSites permission asks for access directly rather
  than piggy-backing on the import flow.
- Drop the prominent red "Revoke top sites access" buttons from Manage;
  revocation is now a quiet menu entry, gated on actually-granted
  permissions (topSites/bookmarks !== undefined) instead of "checked".
- Move the header "+ Add" into a dashed row at the top of the list so
  the add affordance sits next to the shortcuts it creates.
- Import flow is now self-describing: always opens the picker (no more
  silent imports), entries show counts and grant-access hints, and the
  picker explains which source it came from.
- Rename labels across the hub menu and CTAs to match Chrome vocabulary
  ("Most visited sites", "Bookmarks bar", "My shortcuts").

Made-with: Cursor
The old modal led with a boxed preview of a ShortcutTile on a gradient
backdrop, which duplicated the form inputs and looked odd when the URL
was still the placeholder. Replace it with an icon-first layout:

- Single 96px avatar at the top. Defaults to the live favicon derived
  from the URL field as the user types; falls back to EarthIcon when
  the URL is empty or invalid. Click opens the file picker; hover
  reveals an Upload/Replace band.
- Custom icon uploads use useFileInput + uploadContentImage directly
  (replacing ImageInput, which couldn't react to URL-driven favicon
  changes because of its internal state).
- Helper line under the avatar explains the current state in plain
  language ("Using site favicon — click to upload your own." /
  "Remove custom icon" / "Uploading…").
- Reorder fields to Image → Name → URL per design feedback. The
  "Or paste an image URL instead" escape hatch stays but moves below
  the main fields.

Made-with: Cursor
- Simplify overflow menu to 4 stable items with an inline mode toggle so
  it no longer reshuffles when the source flips.
- Move import, revoke, and restore-hidden actions into the Manage modal
  under a new Browser connections section.
- Add tile/icon/chip appearance modes with a live-preview picker in the
  Manage modal, wired through SettingsContext.
- Refactor Import picker to a tap-to-select list with favicon fallbacks,
  segmented capacity pips, and domain-only labels.
- Polish ShortcutTile, AddShortcutTile, and Edit modal for a calmer,
  higher-contrast visual language across themes.

Made-with: Cursor
The source-mode toggle row was taller and typographically different from
the other items, making the menu look uneven. Rebuild it on the same
primitives PostOptionButton uses (h-7, typo-footnote, MenuIcon wrapper)
and drop it into the standard DropdownMenuOptions list. Reuse the native
Switch with pointer-events-none so clicks fall through to the menu item,
keeping menu-open-after-toggle behavior. Remove the custom min-width so
the content uses the default DropdownMenuContentAction width.

Made-with: Cursor
…ngs style

Hub dropdown
- Hide "Add shortcut" in auto mode so the menu carries only relevant rows.
- Add a hairline separator below the source-mode toggle to signal it's a
  setting, not a quick action.

Manage modal
- Drop the header Import button; move import actions into Browser
  connections alongside revoke/restore so every browser-sourced concern
  lives in one place.
- Replace the heavy bordered mode cards with lean settings-style radio
  rows (ring-only selection, quiet hover).
- Use Subhead + Caption1 section titles and gap-5 spacing to mirror the
  Settings page rhythm; remove HorizontalSeparators between sections.
- Move "Your shortcuts" list under a proper Subhead and only render it in
  manual mode since auto mode is browser-populated.

Appearance picker
- Stronger selected state: cabbage border + corner check badge + bold
  label (felt like hover before).
- Fix illustration shapes: chip becomes rounded-rectangle instead of
  full pill, tile label becomes rounded-rectangle instead of oval.
- Remove long descriptions — titles carry enough meaning.

Edit modal
- Shrink the title from typo-title3 to Body+bold to match the Manage
  modal (was dominating the form).
- Compact avatar (size-16 + rounded-16), tighter gaps, terser helper
  copy.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant