Skip to content

Teal theme and landing page - #106

Merged
Jberma23 merged 7 commits into
mainfrom
teal-theme-and-landing-page
Aug 6, 2026
Merged

Teal theme and landing page#106
Jberma23 merged 7 commits into
mainfrom
teal-theme-and-landing-page

Conversation

@Jberma23

@Jberma23 Jberma23 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Jberma23 and others added 7 commits August 6, 2026 04:12
https://reactnativereusables.com - shadcn/ui for React Native, on top of
NativeWind, which compiles Tailwind classes into React Native styles. The
components are checked into src/components/ui/ rather than installed, so they
are ours to edit, and `cli add` writes more of them there.

Fifteen to start with: alert, avatar, badge, button, card, checkbox, icon,
input, label, progress, separator, skeleton, switch, text and textarea. The rest
of the catalogue is one `add` away, which is the point of the library, so there
was no reason to pull all thirty in up front.

Setup notes:

- babel.config.js is new. babel-preset-expo's defaults were enough until now.
  The React Compiler is unaffected: it comes from the Metro caller, and
  `expo export` still reports it enabled.
- metro.config.js sets inlineRem to 16. NativeWind defaults to 14 and the
  components are sized against 16.
- src/global.css keeps the web font variables it already had and gains the
  design tokens. src/lib/theme.ts mirrors them for native props that want a
  colour string rather than a class, and the root layout takes its navigation
  theme from there so nav chrome and `bg-background` agree.
- The CSS import moved from src/constants/theme.ts to the root layout, which is
  where both Expo and NativeWind want it. The exported web CSS still carries
  --font-display.
- Two jest additions, or nothing under src/components/ui/ can be rendered in a
  test: @rn-primitives ships JSX and lucide-react-native ships ESM, so both need
  babel run over them, and react-native-reanimated needs the worklets mock its
  own Jest guide recommends.

Existing screens are untouched beyond the layout - ThemedText, ThemedView and
src/constants/theme.ts still drive them. Restyling is a separate job.

Verified with the CLI's own `doctor`, plus lint, typecheck, 24 passing tests and
iOS, Android and web bundles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The app opened on the Expo starter screen - "Welcome to Expo", the Expo
wordmark, a "Try editing src/app/index.tsx" hint - and had no palette of its
own. Both replaced.

The theme, defined once in src/global.css and derived from there by
src/lib/theme.ts and src/constants/theme.ts, so the tab bar and the screens
still on StyleSheet follow it rather than drifting.

On the teal. The brand colour is rgb(35, 170, 172), hsl(181 66% 41%), and it is
the primary in dark mode where it carries dark text at 6.4:1. In light mode the
primary is the same hue and saturation at 29% lightness. White on the brand teal
is 2.8:1 against the 4.5:1 WCAG AA asks for at this text size, and it misses the
3:1 for icons and focus rings too; deepened it reaches 5.2:1 for a white label
and 5.1:1 as ink on the background, so one teal covers buttons, links, icons and
rings instead of needing a shade for each. Every pair in both schemes clears AA,
which matters more than usual for people reading this tired, on a phone, in bad
light.

Also fills in --destructive-foreground, which tailwind.config.js has always
referenced and global.css never defined, and retints ThemedText's hardcoded
#3c87f7 link blue - itself only 3.3:1 on white - to the theme primary.

The landing page says what the app is for in plain words, gives three
reassurances, and offers a way in and a way to look around. It promises only
what the app does: no claim that entries are private, because the API behind
them does not guarantee that yet, and a line saying it is not medical advice.
"Start your journal" goes to /tasks, the placeholder resource the README
describes.

Icons are imported one at a time rather than off the lucide barrel. Metro does
not tree-shake, and three icons off the barrel cost 1.8MB - the iOS bundle went
5.6MB, then 3.8MB once the imports were narrowed. Same fix applied to the
generated checkbox.

Verified with lint, typecheck, 28 passing tests and iOS, Android and web
bundles. Every class the landing page uses was checked against the compiled
stylesheet, and both teal primaries appear in the shipped CSS.

Still Expo's: the launch logo and app icon, since splash-icon.png is a
byte-identical copy of expo-logo.png and there is no brand art in the tree. The
splash and adaptive-icon background colours are now the theme's. AnimatedIcon in
src/components/animated-icon.tsx is unused now that nothing renders the Expo
wordmark; AnimatedSplashOverlay beside it is still the launch animation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Setting the splash backgroundColor in app.json to the brand teal left the JS
overlay that continues it still on Expo's #208AEF, so launch went teal, flashed
blue, then showed the app. Same colour in both places now.

The overlay also loads splash-icon.png rather than expo-logo.png. They are the
same file today, but app.json's splash already points at splash-icon.png, so
real brand art dropped in at that one path will pick up in both places instead
of one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Web does not get the native tab bar. app-tabs.web.tsx draws a floating header
instead, absolutely positioned, and no screen left room for it: it is 78px tall
and the three screens padded 32, 16 and 64. Measured in a headless browser at
390x844, the landing page had 46px of its 64px logo behind the header and the
Tasks title was 44px under it.

The header now states its own height, from a WebHeaderInset constant the screens
pad by - the mirror of BottomTabInset, which already solves this for the tab bar
at the bottom on native. Zero on native, where there is no top header. Clearances
afterwards: landing +32px, tasks +16px, explore +64px.

Dark mode on web never worked. tailwind.config.js sets darkMode: 'class', so
every dark style hangs off a `dark` class on <html>; NativeWind resolves that
against Appearance on native, but on web the class is only added by an explicit
colorScheme.set() call, and nothing called it. Both schemes rendered the light
palette. A +html.tsx now sets the class from prefers-color-scheme before the
bundle loads - early enough for NativeWind to start on the right scheme and to
avoid a flash - and follows changes while the page is open.

Verified in the browser: light gives #FCFDFD with the #19797B primary, dark
gives #0E171B with #24ABAE, which is the palette as written. Plus lint,
typecheck, 28 tests, and iOS, Android and web bundles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Measured at 390x844 in a headless browser. The header could not fit: the brand
name, three tabs and the Docs link need about 510px and none of them shrink, so
the bar ran from -60 to 450 on a 390px screen with "Along With You" 28px past the
left edge. Below 600px it now drops the brand name and tightens its padding,
which brings the bar to 24..366 with no horizontal overflow. The landing page
says the name directly underneath anyway.

The bar also sat 8px wider than the content below it, at 16px inset against the
screens' px-6. Both are 24 now, so the bar and the text line up.

The landing page hero is centred rather than left aligned, and the rhythm is
tighter: the mark 64 to 56, gaps 8/5/3 to 6/4/2, the card's inner gap 6 to 5, and
the lead trimmed by a sentence rather than by font size - text size is the last
thing to shrink on an app for people reading it tired. Type sizes are unchanged.

That moves the primary call to action from 866 to 750, above the 844 fold on a
390x844 phone and above it at 430, 768 and 1280 too. The mark's centre matches
the viewport centre at every one of those widths.

Verified: lint, typecheck, 28 tests, iOS, Android and web bundles, all three
screens still clearing the header, and both colour schemes still resolving to the
palette.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both were sitting untracked in the working tree, one commit away from being
committed by accident.

The note at the top of this file is right that .DS_Store belongs in a global
ignore, but the same reasoning as the *:Zone.Identifier line above applies: the
repo gets mounted into a container from a Mac, and the file then shows up in
`git status` for whoever is working inside the container, where their global
ignore is not. mobile/.gitignore already had it; the root did not.

ui-review/ is where screenshots of the phone app land when looking over a UI
change - useful, but large binaries that go stale immediately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
main took the React Native Reusables branch as a squash (#105), so its content
arrived under a new commit while this branch still carried the original. Git saw
both sides creating lib/theme.ts and checkbox.tsx and both editing README.md,
global.css and constants/theme.ts, and could not tell they were the same change.

Resolved by keeping this branch's copies. main's version of all five files is
byte-identical to the commit this branch already contains, so ours is that plus
the teal theme work and nothing was dropped: the merged tree matches the branch's
tree before the merge exactly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Jberma23
Jberma23 merged commit e3ae80f into main Aug 6, 2026
6 checks passed
This was linked to issues Aug 7, 2026
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.

Create Landing Page Add UI Library

1 participant