Skip to content

feat(mobile): NativeScript + Vue 3 scaffold (#484)#495

Merged
krantheman merged 6 commits into
frappe:mobile-appfrom
krantheman:mobile/484-scaffolding
May 29, 2026
Merged

feat(mobile): NativeScript + Vue 3 scaffold (#484)#495
krantheman merged 6 commits into
frappe:mobile-appfrom
krantheman:mobile/484-scaffolding

Conversation

@krantheman
Copy link
Copy Markdown
Member

@krantheman krantheman commented May 27, 2026

Summary

  • Adds mobile/ — full NativeScript + Vue 3 project with Pinia, TypeScript, Tailwind, ESLint/Prettier
  • Ports all Frappe UI design tokens (ink/surface/outline colors, typography, spacing) into a NativeScript-compatible tailwind.config.js
  • Adds packages/types/ (@mail/types workspace) with shared TypeScript types extracted from the frontend — no copy-pasting between apps
  • Sets up Pinia stores mirroring the web frontend shape: site (saved servers), session (OAuth tokens), user (accounts, mailboxes)
  • Adds a typed Frappe API client (utils/api.ts) that injects Authorization: Bearer headers
  • Adds pure formatting utilities (utils/format.ts) reusable across web and mobile
  • Includes minimal App_Resources/ for Android and iOS with OAuth redirect URI stubs
  • Documents generic vs. Mail-specific code in mobile/README.md for future frappe-nativescript extraction

Build & tooling

  • mobile is a yarn workspace off the repo root (root is marked private so workspaces are enabled); yarn install from the root resolves @mail/mobile and @mail/types
  • webpack.config.cjs (referenced via webpackConfigPath) — the root is type: module, so the NativeScript CLI's require() of a plain .js config fails; .cjs forces CommonJS
  • Android launcher icon uses the Frappe Mail logo via adaptive icons (vector background + foreground, single source of truth); minSdkVersion is 26

Test plan

  • yarn install from repo root resolves all workspace packages without errors
  • mobile/ type-checks with no errors (verified during ns build)
  • ns build android succeeds (resource linking + Gradle)
  • ns run android builds, installs, and boots the placeholder LandingPage on a device with the Frappe Mail launcher icon
  • ns run ios builds, installs, and boots on the simulator; app icon + launch screen render (white splash with centered blue-circle logo, matching Android)

Closes #484

🤖 Generated with Claude Code

- Add mobile/ with NativeScript + Vue 3 project structure
- Port Frappe UI design tokens (ink/surface/outline, typography, spacing)
  into a NativeScript-compatible Tailwind config
- Set up Pinia stores mirroring the web frontend shape (site, session, user)
- Add Frappe API client with Bearer token auth
- Add pure formatting utilities shared with the web app
- Extract shared TypeScript types into packages/types (@mail/types workspace)
- Add minimal App_Resources for Android and iOS
- Configure ESLint, Prettier, and TypeScript matching the frontend setup
- Document generic vs. Mail-specific code for future frappe-nativescript extraction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@krantheman krantheman requested a review from s-aga-r as a code owner May 27, 2026 08:14
krantheman and others added 5 commits May 29, 2026 16:11
Get the scaffolded NativeScript app actually building and launching on
a device, and replace the placeholder launcher icon with the Frappe
Mail logo.

- Enable yarn workspaces by marking the root package private, so the
  `mobile` workspace (and `@mail/types`) resolves via `yarn install`
- Add `webpack.config.cjs` + point `webpackConfigPath` at it; the root
  is `type: module`, so a plain `.js` config is loaded as ESM and the
  NativeScript CLI's `require()` cannot call its default export
- Set `main` to `app/app.ts` so webpack can resolve the entry point
- Add `shims-vue.d.ts` and `import type` for NativeScriptConfig to
  clear the type-check errors; drop the non-existent
  `dayjs/plugin/isThisYear` in favor of a year comparison
- Add adaptive launcher icons (vector background + foreground) and set
  `minSdkVersion 26`; no legacy raster icons, single source of truth

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Drop unused READ_/WRITE_EXTERNAL_STORAGE Android permissions; the app
  only needs INTERNET, and WRITE_EXTERNAL_STORAGE is ignored on API 26+
- Fix stale README: yarn (not bun) is the package manager, and the
  launcher icon is already an adaptive icon (no manual icon generation);
  drop the not-yet-existent components/ dir from the tree
- Disable vue/attribute-hyphenation — NativeScript view props are
  camelCase (e.g. flexDirection), so the HTML-oriented rule misfires
- Apply prettier formatting to clear the two outstanding lint errors
- Remove the inert eslint-disable header from nativescript.config.ts

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Consolidate the mobile workspace onto the root ESLint + Prettier setup
instead of maintaining parallel configs under mobile/.

- Add a mobile/** override to the root eslint.config.mjs (resolver alias
  for @ -> mobile/app and @mail/types, and vue/attribute-hyphenation off
  for NativeScript camelCase view props); set tsconfigRootDir so the
  parser stops erroring on the multiple tsconfig candidates
- Delete mobile/eslint.config.mjs and mobile/.prettierrc; the root
  .prettierrc already auto-detects each tailwind.config, so mobile files
  format identically
- Reformat mobile sources under the root rules (import ordering, tailwind
  class sorting)

Also fixes a pre-existing broken dependency this surfaced: the scaffold
pinned @nativescript/tailwind ^1.0.0, which does not exist on the
registry (a clean yarn install fails). Pin ^2.0.0 — the line built for
Tailwind 3, which this project uses — replacing the stale 4.0.9 that had
pulled in the Tailwind 4 postcss toolchain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Frappe Linter (pre-commit eslint) ran the root config over mobile's
build configs once the mobile-local config was removed, failing on:

- @typescript-eslint/no-require-imports in postcss.config.js,
  tailwind.config.js, and webpack.config.cjs — these are CommonJS by
  necessity (their loaders need require()/module.exports). Disable the
  rule for mobile/*.{js,cjs}.
- prettier wanting 2-space indent in webpack.config.cjs: .editorconfig
  enforces tabs for *.js/*.ts/*.vue but omitted *.cjs, so add it — the
  repo's lone .cjs file now matches every other JS-family file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- AppIcon: single-size 1024×1024 opaque app icon in
  Assets.xcassets/AppIcon.appiconset (iOS rounds corners; Xcode derives
  the smaller sizes)
- Launch screen: LaunchScreen.storyboard + AppIconBackground/Center image
  sets — white background with the centered blue-circle envelope, to
  match the Android 12+ splash
- build.xcconfig: set ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon.
  Without it NativeScript's generated Xcode project never designates the
  app icon, so actool ships a blank icon and no CFBundleIcons

Verified on simulator: home-screen icon and launch-screen logo both
render; actool/ibtool compile the catalog and storyboard with no
warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@krantheman krantheman merged commit 8ecb5bf into frappe:mobile-app May 29, 2026
3 checks passed
@krantheman krantheman deleted the mobile/484-scaffolding branch June 1, 2026 19:37
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