Skip to content

Global Stylesheet #44

@bhuelsman

Description

@bhuelsman

Description
Establish a centralized global stylesheet and design token system for the CivicKit mobile app. Right now styles are scattered or inconsistent, this would create a single source for colors, typography, spacing, and shared component styles so the UI feels cohesive as the app grows.

Purpose
As Developer 2 builds screens like the Issue List and Issue Card, they need consistent values to pull from. Without a global stylesheet, every developer makes slightly different spacing/color choices and the app looks patchy.

Requirements:

  • Create mobile/src/styles/theme.ts with design tokens (colors, spacing, typography, border radius, shadows)
  • Create mobile/src/styles/globalStyles.ts with reusable style objects (containers, headings, cards, buttons, inputs)
  • Create mobile/src/styles/index.ts as a barrel export for clean imports
  • Tokens should cover at minimum:
    • Colors: primary, secondary, background, surface, text (primary/secondary/muted), error, success, warning
    • Spacing: xs (4), sm (8), md (16), lg (24), xl (32), xxl (48)
    • Typography: font sizes (sm/md/lg/xl/xxl), font weights, line heights
    • Border radius: sm, md, lg, full
  • All existing inline styles in the app should reference the theme instead of hardcoded values

Acceptance Criteria

  • theme.ts exports a colors, spacing, typography, and borderRadius object
  • globalStyles.ts exports reusable StyleSheet objects (e.g. container, card, heading, bodyText, input, button)
  • All existing screens/components use theme values, no hardcoded hex codes or magic numbers
  • TypeScript types are correct, no any
  • Another developer can add a new screen using only imports from styles/

Tech Notes

  • Use React Native's StyleSheet.create() — do not use plain objects (RN optimizes registered styles)
  • Keep theme.ts as plain JS objects (not StyleSheets) so values can be used both in StyleSheet.create() and inline logic
  • For dark mode support later, structure colors as semantic names (background, surface) rather than raw names (white, gray100) — this makes a future dark theme a swap, not a rewrite
  • Spacing scale of 4px base (4, 8, 16, 24, 32, 48) matches most design systems and plays nicely with React Native's layout system

Helpful Resources

Example Code

// mobile/src/styles/theme.ts
export const colors = {
  primary: '#2563EB',       // CivicKit blue
  primaryDark: '#1D4ED8',
  secondary: '#10B981',     // Success green
  background: '#F9FAFB',
  surface: '#FFFFFF',
  textPrimary: '#111827',
  textSecondary: '#6B7280',
  textMuted: '#9CA3AF',
  error: '#EF4444',
  warning: '#F59E0B',
  success: '#10B981',
  border: '#E5E7EB',
};

export const spacing = {
  xs: 4,
  sm: 8,
  md: 16,
  lg: 24,
  xl: 32,
  xxl: 48,
};

export const typography = {
  sizeSm: 12,
  sizeMd: 14,
  sizeLg: 16,
  sizeXl: 20,
  sizeXxl: 28,
  weightRegular: '400' as const,
  weightMedium: '500' as const,
  weightBold: '700' as const,
};

export const borderRadius = {
  sm: 4,
  md: 8,
  lg: 16,
  full: 9999,
};
// mobile/src/styles/globalStyles.ts
import { StyleSheet } from 'react-native';
import { colors, spacing, typography, borderRadius } from './theme';

export const globalStyles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: colors.background,
    padding: spacing.md,
  },
  card: {
    backgroundColor: colors.surface,
    borderRadius: borderRadius.md,
    padding: spacing.md,
    marginBottom: spacing.sm,
    borderWidth: 1,
    borderColor: colors.border,
  },
  heading: {
    fontSize: typography.sizeXl,
    fontWeight: typography.weightBold,
    color: colors.textPrimary,
  },
  bodyText: {
    fontSize: typography.sizeMd,
    color: colors.textSecondary,
    lineHeight: 22,
  },
});
// mobile/src/styles/index.ts
export { colors, spacing, typography, borderRadius } from './theme';
export { globalStyles } from './globalStyles';

Coding Journal Prompts

  1. Why is it better to use semantic color names (like textSecondary) rather than descriptive ones (like gray500)
  2. How does this decision affect the app long-term?
  3. What's the difference between a design token and a style? Why are they kept in separate files here?
  4. If a future designer gives you a new color palette, how many files would you need to change with this setup?
  5. What does that tell you about the value of centralization?

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions