Skip to main content

Project Structure

A Sublime UI app keeps a shared core and platform-specific UI. You write screens per platform; you share everything underneath them.

my-app/
src/
components/ # SHARED — design-system quartets (Card, Button, …)
models/ # SHARED — your data models
theme/ # SHARED — design tokens
native/ # SHARED contracts — native services (main-only impl)
screens/
web/ # web screens
mobile/ # mobile screens
navigation/
storybook.web.ts # imports ../screens/web
storybook.native.ts # imports ../screens/mobile
navigation.tsx # generated
navigation.native.tsx # generated
web/ # web entry — mounts the web app
mobile/ # React Native entry
desktop/ # Electron Forge shell — renderer mounts the WEB ui
forge.config.ts, webpack.*.config.ts
src/main, src/renderer
sublime.config.json

What is shared vs platform-specific

  • Shared: components, models, theme, and native service contracts — the logic and the design system.
  • Platform-specific: every screen, and each platform's storybook/navigation. A mobile screen and a web screen are different files with different layouts; they both reach for the same shared <Card> / <Button> and the same models.
  • Desktop = web UI: the Forge renderer mounts the web screens and web navigation, adding only the native bridge. Mobile and web are the two UI families; desktop packages the web one.

Native services stay clean

src/native/printer.service.ts lives in the shared tree but is a main-process module. The renderer only does import type from it, which is erased at build — so its Node dependencies are bundled by the main Webpack build, never the renderer. desktop/src/main/main.ts imports the real implementation and calls registerNative([...]).