Closes the remaining items from project-v1-plan.md:
- View mode switcher (List / Board) on project detail's related-issues:
- List mode regrouped into full BOARD_STATUSES (backlog / todo /
in_progress / in_review / done / blocked), replacing the mobile-only
"Open / Done" two-bucket rollup that silently diverged from web's
six-bucket grouping (parity violation, gap audit §3)
- Board mode: horizontal scroll, one status column per group, each
column is a FlatList of IssueRow (reuses existing primitive)
- View mode is local useState — no Zustand store (single component
scope, mobile/CLAUDE.md "no state unless required")
- Hex sweep → THEME tokens / NativeWind semantic classes (gap audit §5):
project-properties-section, project-resources-section, project/[id],
more/projects. Eliminates the last project-domain dark-mode breakage.
- Hand-drawn SVG icons → existing primitives (gap audit §6):
more/projects PlusButton → <IconButton name="add">
project-properties-section chevron → <Ionicons name="chevron-forward">
project-related-issues chevron → <Ionicons name="chevron-forward">
Drops react-native-svg where no longer used.
Items 1 / 2 / 4 (Tier B picker migration, progress section, new-project
draft persistence) landed in preceding commits c644e2a3, 7337206f,
2ff95c34. With this PR the full project-v1-plan is implemented and the
two planning docs (gap audit + implementation plan) are committed for
future reference.
Project detail's Status and Priority chips were the last two picker
chips still using the legacy centered-Modal pattern. The mixed gesture
(Status/Priority popped a centered card; Lead / Add Resource slid up a
formSheet) violated the picker-row consistency rule in CLAUDE.md
Lesson 6 — the four chips on the same row now all open the same way.
- New picker bodies under components/project/pickers/.
- New formSheet routes under app/(app)/[workspace]/project/[id]/picker/.
- Register both screens in workspace _layout.tsx using SHEET_OPTIONS.
- project/[id].tsx: drop the local state, swap chip onPress to
router.push, and remove the trailing 'still uses transparent-Modal'
apology comment.
- project/new.tsx is a draft modal so it can't push to a route (no
project exists yet to read from cache). Inline a tiny DraftPickerModal
shell that hosts the same picker bodies — documented in the file.
- Delete the obsolete ProjectStatusPickerSheet / ProjectPriorityPickerSheet
files and update rnr-migration.md to reflect that B.2 is closed.
Mobile now offers the full emoji set behind a 'More reactions' overflow
in the per-comment actions sheet, matching web's emoji-mart parity.
- Adopt rn-emoji-keyboard 1.7.0 (zero runtime deps, React 19 / RN 0.83
compatible, installed via expo install).
- New formSheet route at issue/[id]/comment/[commentId]/emoji-picker.tsx
embeds EmojiKeyboard inline so UISheetPresentationController retains
grabber, detents, and drag-to-dismiss.
- Quick-row overflow '+' button in comment actions pushes the new route.
- Delete the dead emoji-picker-sheet.tsx and the unused
emojiPickerOpen state in comment-card.tsx (never opened from
anywhere after the actions-route migration).
- Move QUICK_EMOJIS to lib/quick-emojis.ts since its old host file is
gone.
- Update rnr-migration.md B.4 to record the resolution.
Formalises the rendering decision (Path B — react-native-markdown-display +
Shiki + custom renderers) into a one-page ADR with A-tier source citations,
keeping the longer research log alongside it.
Adds a `selectable` opt-out to `CodeBlock` and `Markdown` so timeline
comments can disable RN's UIKit selection magnifier when an outer Pressable
already owns the long-press gesture, while issue descriptions and chat
messages keep the default selectable behaviour for copy-to-clipboard.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First wave of the RNR migration documented in apps/mobile/docs/
rnr-migration.md. The hand-written components/ui/ shell was producing a
steady stream of dark-mode and sheet-handling bugs; this commit
establishes the foundation that lets every subsequent screen pick up
RNR-shipped components and a real theme system instead.
Foundation (Phase 1):
- global.css + tailwind.config.js switch to shadcn neutral CSS variables
(light + dark) under :root and .dark:root, with Multica custom tokens
appended. tailwind utilities resolve to hsl(var(--...)).
- New lib/theme.ts mirrors the variables in TypeScript and exports
NAV_THEME for React Navigation chrome.
- New lib/use-color-scheme.ts wraps NativeWind's useColorScheme with
expo-secure-store persistence (preference key: theme-preference,
values: light/dark/system).
- components.json registers shadcn CLI paths so `npx @rnr/cli add` writes
to the expected aliases. metro.config.js gains inlineRem: 16.
- app/_layout.tsx wraps the tree in ThemeProvider(NAV_THEME[scheme]) and
mounts <PortalHost /> for RNR dialogs.
- Settings → Appearance picker (three rows: Light / Dark / System,
persisted) — the only product addition in this commit.
Component canary (Phase 2):
- button.tsx + text.tsx replaced by RNR's defaults via the CLI (uses
TextClassContext to flow text variants from Button into nested Text).
- 11 button call sites updated to wrap children in <Text> (the RNR
convention). The old `brand` variant had zero call sites and was
dropped without follow-up.
Bottom navigation:
- (tabs)/_layout.tsx tried NativeTabs first but rolled back to JS Tabs:
NativeTabs hard-codes canPreventDefault: false on tabPress events, so
the "More tap opens a sheet without navigating" pattern was
unreachable. The rolled-back layout uses useColorScheme + THEME to
derive active/inactive tint, fixing the dark-mode "dim selected tab"
bug.
- More tab intercepts tabPress and pushes /[workspace]/menu — a stack
route registered with presentation: "formSheet" +
sheetAllowedDetents: "fitToContents" so iOS sizes the sheet to the
menu's intrinsic height (UIKit handles drag handle, swipe dismiss,
blur backdrop).
- The formSheet route is named `menu.tsx` rather than `more.tsx` to
avoid the URL collision with (tabs)/more.tsx — both files would
otherwise resolve to /[workspace]/more because (tabs) is a transparent
route group.
- components/nav/global-nav-menu.tsx refactored from a self-managed
Modal into a plain ScrollView (no flex-1, so fitToContents can
measure). Closes via router.dismiss() instead of an onClose prop.
Docs / rules:
- apps/mobile/CLAUDE.md adds two hard rules: "defaults first" and "iOS
native > RNR > discuss" (the three-tier waterfall).
- apps/mobile/docs/rnr-migration.md captures the alternatives evaluated,
the three-tier component classification, the phased rollout, and the
pitfalls hit during this commit.
Out of scope for this wave (planned but not started):
- Tier A remaining primitives (input / card / text-field / textarea)
- Tier B sheets (the 18 hand-rolled Modal sheets — to be replaced one
PR at a time with ActionSheetIOS / native pickers / RNR Dialog)
- Tier C domain UI internal-token upgrades
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bundles the markdown rendering overhaul plus in-flight mobile feature
work as a single WIP for review.
Markdown work (the new direction):
- Swap internal Markdown component from hand-rolled marked walker to
react-native-enriched-markdown (Software Mansion, native md4c).
Public API <Markdown content={...} /> unchanged; consumers untouched.
Mention links degrade to colored links + onLinkPress routing.
- Pre-swap fixes that landed first: 3-layer inline code (later corrected),
Shiki via react-native-shiki-engine wired (now bypassed; code retained
for selective re-enable on code blocks), code block copy button with
expo-clipboard + expo-haptics, inline SVG copy/check icons, header
scale calibrated to Apple HIG, paragraph leading-6 for CJK, list
bullet column 24->16, lineBreakStrategyIOS="hangul-word" on outer
paragraph Text.
- Preprocess: <br> -> " \n" (CommonMark HardBreak) so md4c respects
intentional breaks without misreading bare \n.
- Drop the Expo Go compatibility constraint from CLAUDE.md and
markdown-renderer-research.md (project runs on dev client).
- New apps/mobile/docs/markdown-renderer-research.md captures the
RN nested-Text rendering constraints (#10775 / #45925 / #6728), the
CJK amplification mechanism, the typography scale calibration, and
every decision-log entry from the engine evolution.
Other in-flight mobile features included:
- Issue detail timeline polish, comment composer + action sheet,
mention suggestion bar, emoji picker sheet, reaction bar.
- Status / priority / assignee / label / due date picker sheets.
- My Issues filter sheet + view store.
- Realtime layer (ws-client, realtime-provider, use-inbox-realtime).
- Data layer additions (queries, mutations, schemas, attribute chips).
Cross-package:
- packages/core/api/schemas.ts: export IssueSchema for mobile use.
Build: native rebuild required after pulling (enriched-markdown is
a native Fabric module).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>