├── apps ├── mobile │ ├── .npmrc │ ├── nativewind-env.d.ts │ ├── .env.example │ ├── globals.css │ ├── assets │ │ ├── images │ │ │ ├── icon.png │ │ │ ├── favicon.png │ │ │ ├── react-logo.png │ │ │ ├── splash-icon.png │ │ │ ├── adaptive-icon.png │ │ │ ├── react-logo@2x.png │ │ │ ├── react-logo@3x.png │ │ │ └── partial-react-logo.png │ │ └── fonts │ │ │ └── SpaceMono-Regular.ttf │ ├── .vscode │ │ └── settings.json │ ├── app │ │ ├── api │ │ │ └── auth │ │ │ │ └── [...auth]+api.ts │ │ ├── _layout.tsx │ │ ├── sign-in.tsx │ │ ├── index.tsx │ │ └── sign-up.tsx │ ├── gluestack-ui.config.json │ ├── eslint.config.js │ ├── metro.config.js │ ├── babel.config.js │ ├── lib │ │ └── auth │ │ │ └── auth-client.ts │ ├── tsconfig.json │ ├── .gitignore │ ├── components │ │ └── ui │ │ │ ├── card │ │ │ ├── styles.tsx │ │ │ ├── index.web.tsx │ │ │ └── index.tsx │ │ │ ├── gluestack-ui-provider │ │ │ ├── script.ts │ │ │ ├── index.tsx │ │ │ ├── index.web.tsx │ │ │ └── config.ts │ │ │ ├── hstack │ │ │ ├── index.web.tsx │ │ │ ├── styles.tsx │ │ │ └── index.tsx │ │ │ ├── text │ │ │ ├── index.web.tsx │ │ │ ├── index.tsx │ │ │ └── styles.tsx │ │ │ ├── heading │ │ │ ├── styles.tsx │ │ │ ├── index.web.tsx │ │ │ └── index.tsx │ │ │ ├── image │ │ │ └── index.tsx │ │ │ ├── link │ │ │ └── index.tsx │ │ │ └── badge │ │ │ └── index.tsx │ ├── app.json │ ├── package.json │ ├── tailwind.config.js │ └── README.md └── web │ ├── .env.example │ ├── postcss.config.mjs │ ├── lib │ ├── auth.ts │ └── auth-client.ts │ ├── eslint.config.js │ ├── app │ ├── dashboard │ │ └── page.tsx │ ├── api │ │ └── auth │ │ │ └── [...all] │ │ │ └── route.ts │ ├── layout.tsx │ ├── page.tsx │ └── sign-up │ │ └── page.tsx │ ├── next.config.ts │ ├── public │ ├── vercel.svg │ ├── file-text.svg │ ├── window.svg │ ├── next.svg │ ├── globe.svg │ ├── turborepo-dark.svg │ └── turborepo-light.svg │ ├── tsconfig.json │ ├── .gitignore │ ├── package.json │ └── README.md ├── pnpm-workspace.yaml ├── tooling ├── eslint │ ├── README.md │ ├── package.json │ ├── base.js │ ├── react-internal.js │ └── next.js ├── tailwind │ ├── postcss.config.mjs │ └── package.json └── typescript │ ├── react-library.json │ ├── package.json │ ├── nextjs.json │ └── base.json ├── .vscode └── settings.json ├── packages ├── ui │ ├── eslint.config.mjs │ ├── src │ │ ├── lib │ │ │ ├── utils.ts │ │ │ └── globals.css │ │ └── components │ │ │ ├── label.tsx │ │ │ ├── input.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── badge.tsx │ │ │ ├── button.tsx │ │ │ └── card.tsx │ ├── tsconfig.json │ ├── components.json │ ├── package.json │ └── README.md ├── auth │ ├── better-auth-client.ts │ ├── better-auth.ts │ └── package.json └── db │ ├── package.json │ └── src │ └── migration.sql ├── package.json ├── .gitignore ├── turbo.json ├── .github └── dependabot.yml ├── LICENSE └── README.md /apps/mobile/.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | node-linker=hoisted 3 | -------------------------------------------------------------------------------- /apps/mobile/nativewind-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/mobile/.env.example: -------------------------------------------------------------------------------- 1 | BETTER_AUTH_SECRET= 2 | BETTER_AUTH_URL= 3 | DATABASE_URL= -------------------------------------------------------------------------------- /apps/web/.env.example: -------------------------------------------------------------------------------- 1 | BETTER_AUTH_SECRET= 2 | BETTER_AUTH_URL= 3 | DATABASE_URL= -------------------------------------------------------------------------------- /apps/web/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from "@acme/tailwind/postcss.config"; -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "packages/*" 4 | - "tooling/*" 5 | -------------------------------------------------------------------------------- /apps/mobile/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /tooling/eslint/README.md: -------------------------------------------------------------------------------- 1 | # `@turbo/eslint` 2 | 3 | Collection of internal eslint configurations. 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.workingDirectories": [ 3 | { 4 | "mode": "auto" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /tooling/tailwind/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | "@tailwindcss/postcss": {}, 4 | }, 5 | }; -------------------------------------------------------------------------------- /apps/mobile/assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/images/icon.png -------------------------------------------------------------------------------- /apps/mobile/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/images/favicon.png -------------------------------------------------------------------------------- /apps/mobile/assets/images/react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/images/react-logo.png -------------------------------------------------------------------------------- /apps/mobile/assets/images/splash-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/images/splash-icon.png -------------------------------------------------------------------------------- /apps/mobile/assets/images/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/images/adaptive-icon.png -------------------------------------------------------------------------------- /apps/mobile/assets/images/react-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/images/react-logo@2x.png -------------------------------------------------------------------------------- /apps/mobile/assets/images/react-logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/images/react-logo@3x.png -------------------------------------------------------------------------------- /apps/web/lib/auth.ts: -------------------------------------------------------------------------------- 1 | import { createAuth } from "@acme/auth/better-auth"; 2 | 3 | export const auth = createAuth(process.env.DATABASE_URL || ""); 4 | -------------------------------------------------------------------------------- /apps/mobile/assets/fonts/SpaceMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/fonts/SpaceMono-Regular.ttf -------------------------------------------------------------------------------- /apps/mobile/assets/images/partial-react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimurBas/expo-nextjs-monorepo/HEAD/apps/mobile/assets/images/partial-react-logo.png -------------------------------------------------------------------------------- /apps/web/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { nextJsConfig } from "@acme/eslint/next-js"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default nextJsConfig; 5 | -------------------------------------------------------------------------------- /packages/ui/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { config } from "@acme/eslint/react-internal"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config; 5 | -------------------------------------------------------------------------------- /apps/web/app/dashboard/page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Dashboard = () => { 4 | return
Dashboard
; 5 | }; 6 | 7 | export default Dashboard; 8 | -------------------------------------------------------------------------------- /apps/web/next.config.ts: -------------------------------------------------------------------------------- 1 | import { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | transpilePackages: ["@acme/ui"], 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /tooling/typescript/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "jsx": "react-jsx" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/auth/better-auth-client.ts: -------------------------------------------------------------------------------- 1 | import { createAuthClient } from "better-auth/react"; 2 | import { toNextJsHandler } from "better-auth/next-js"; 3 | 4 | export { createAuthClient, toNextJsHandler }; 5 | -------------------------------------------------------------------------------- /apps/mobile/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll": "explicit", 4 | "source.organizeImports": "explicit", 5 | "source.sortMembers": "explicit" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/web/app/api/auth/[...all]/route.ts: -------------------------------------------------------------------------------- 1 | import { auth } from "../../../../lib/auth"; 2 | import { toNextJsHandler } from "@acme/auth/better-auth-client"; 3 | 4 | export const { POST, GET } = toNextJsHandler(auth); 5 | -------------------------------------------------------------------------------- /apps/mobile/app/api/auth/[...auth]+api.ts: -------------------------------------------------------------------------------- 1 | import { createAuth } from "@acme/auth/better-auth"; 2 | 3 | const handler = createAuth(process.env.DATABASE_URL || "").handler; 4 | export { handler as GET, handler as POST }; 5 | -------------------------------------------------------------------------------- /packages/ui/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /tooling/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@acme/typescript", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/db/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@acme/db", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "type": "module", 7 | "devDependencies": { 8 | "@acme/eslint": "workspace:*" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/mobile/gluestack-ui.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "tailwind": { 3 | "config": "tailwind.config.js", 4 | "css": "globals.css" 5 | }, 6 | "app": { 7 | "entry": "app/_layout.tsx", 8 | "components": "components/ui" 9 | } 10 | } -------------------------------------------------------------------------------- /apps/web/lib/auth-client.ts: -------------------------------------------------------------------------------- 1 | import { createAuthClient } from "@acme/auth/better-auth-client"; 2 | 3 | export const authClient: ReturnType = createAuthClient( 4 | { 5 | baseURL: "http://localhost:3000", 6 | } 7 | ); 8 | -------------------------------------------------------------------------------- /apps/mobile/eslint.config.js: -------------------------------------------------------------------------------- 1 | // https://docs.expo.dev/guides/using-eslint/ 2 | const { defineConfig } = require('eslint/config'); 3 | const expoConfig = require('eslint-config-expo/flat'); 4 | 5 | module.exports = defineConfig([ 6 | expoConfig, 7 | { 8 | ignores: ['dist/*'], 9 | }, 10 | ]); 11 | -------------------------------------------------------------------------------- /apps/mobile/metro.config.js: -------------------------------------------------------------------------------- 1 | const { getDefaultConfig } = require("expo/metro-config"); 2 | const { withNativeWind } = require('nativewind/metro'); 3 | 4 | const config = getDefaultConfig(__dirname) 5 | 6 | config.resolver.unstable_enablePackageExports = true; 7 | 8 | module.exports = withNativeWind(config, { input: './globals.css' }) -------------------------------------------------------------------------------- /apps/mobile/app/_layout.tsx: -------------------------------------------------------------------------------- 1 | import "@/globals.css"; 2 | import { Stack } from "expo-router"; 3 | import { GluestackUIProvider } from "@/components/ui/gluestack-ui-provider"; 4 | 5 | export default function RootLayout() { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /tooling/typescript/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "plugins": [{ "name": "next" }], 6 | "module": "ESNext", 7 | "moduleResolution": "Bundler", 8 | "allowJs": true, 9 | "jsx": "preserve", 10 | "noEmit": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@acme/typescript/react-library.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@acme/*": [ 7 | "./src/*" 8 | ] 9 | }, 10 | "jsx": "react-jsx" 11 | }, 12 | "include": [ 13 | "." 14 | ], 15 | "exclude": [ 16 | "node_modules", 17 | "dist" 18 | ] 19 | } -------------------------------------------------------------------------------- /apps/web/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/mobile/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: [ 5 | ["babel-preset-expo", { jsxImportSource: "nativewind" }], 6 | "nativewind/babel", 7 | ], 8 | 9 | plugins: [["module-resolver", { 10 | root: ["./"], 11 | 12 | alias: { 13 | "@": "./", 14 | "tailwind.config": "./tailwind.config.js" 15 | } 16 | }]] 17 | }; 18 | }; -------------------------------------------------------------------------------- /apps/mobile/lib/auth/auth-client.ts: -------------------------------------------------------------------------------- 1 | import { createAuthClient } from "better-auth/react"; 2 | import { expoClient } from "@better-auth/expo/client"; 3 | import * as SecureStore from "expo-secure-store"; 4 | 5 | export const authClient = createAuthClient({ 6 | baseURL: "http://192.168.1.66:3000", 7 | plugins: [ 8 | expoClient({ 9 | scheme: "mobile", 10 | storagePrefix: "mobile", 11 | storage: SecureStore, 12 | }), 13 | ], 14 | }); 15 | -------------------------------------------------------------------------------- /apps/web/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import "@acme/ui/globals.css"; 3 | 4 | export const metadata: Metadata = { 5 | title: "Create Next App", 6 | description: "Generated by create next app", 7 | }; 8 | 9 | export default function RootLayout({ 10 | children, 11 | }: Readonly<{ 12 | children: React.ReactNode; 13 | }>) { 14 | return ( 15 | 16 | {children} 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /apps/mobile/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "strict": true, 5 | "paths": { 6 | "@/*": [ 7 | "./*" 8 | ], 9 | "tailwind.config": [ 10 | "./tailwind.config.js" 11 | ] 12 | } 13 | }, 14 | "include": [ 15 | "**/*.ts", 16 | "**/*.tsx", 17 | ".expo/types/**/*.ts", 18 | "expo-env.d.ts", 19 | "tailwind.config.js", 20 | "babel.config.js", 21 | "nativewind-env.d.ts" 22 | ] 23 | } -------------------------------------------------------------------------------- /packages/ui/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/lib/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@acme/components", 14 | "utils": "@acme/utils", 15 | "ui": "@acme/components", 16 | "lib": "@acme/utils" 17 | }, 18 | "iconLibrary": "lucide" 19 | } 20 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@acme/typescript/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": [ 7 | "./*" 8 | ] 9 | }, 10 | "plugins": [ 11 | { 12 | "name": "next" 13 | } 14 | ] 15 | }, 16 | "include": [ 17 | "**/*.ts", 18 | "**/*.tsx", 19 | "next-env.d.ts", 20 | "next.config.ts", 21 | ".next/types/**/*.ts" 22 | ], 23 | "exclude": [ 24 | "node_modules" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /packages/auth/better-auth.ts: -------------------------------------------------------------------------------- 1 | import { betterAuth } from "better-auth"; 2 | import { expo } from "@better-auth/expo"; 3 | import { Pool } from "pg"; 4 | 5 | export const createAuth = (databaseUrl: string) => { 6 | return betterAuth({ 7 | database: new Pool({ 8 | connectionString: databaseUrl, 9 | }), 10 | emailAndPassword: { 11 | enabled: true, 12 | }, 13 | plugins: [expo()], 14 | trustedOrigins: ["expo://", "mobile://", "exp://", "http://localhost:3000"], 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /tooling/tailwind/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@acme/tailwind", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "exports": { 7 | "./postcss.config": "./postcss.config.mjs", 8 | "./native": "./native.ts" 9 | }, 10 | "license": "MIT", 11 | "scripts": { 12 | "lint": "eslint", 13 | "typecheck": "tsc --noEmit" 14 | }, 15 | "dependencies": { 16 | "@tailwindcss/postcss": "^4.1.17", 17 | "postcss": "^8.5.6", 18 | "tailwindcss": "^4.1.17" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "acme", 3 | "private": true, 4 | "scripts": { 5 | "build": "turbo run build", 6 | "dev": "turbo run dev", 7 | "lint": "turbo run lint", 8 | "format": "prettier --write \"**/*.{ts,tsx,md}\"", 9 | "check-types": "turbo run check-types" 10 | }, 11 | "devDependencies": { 12 | "prettier": "^3.6.2", 13 | "turbo": "^2.6.1", 14 | "typescript": "5.9.3" 15 | }, 16 | "packageManager": "pnpm@9.0.0", 17 | "engines": { 18 | "node": ">=18" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | 30 | 31 | # Debug 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # Misc 37 | .DS_Store 38 | *.pem 39 | -------------------------------------------------------------------------------- /apps/mobile/.gitignore: -------------------------------------------------------------------------------- 1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # Expo 7 | .expo/ 8 | dist/ 9 | web-build/ 10 | expo-env.d.ts 11 | 12 | # Native 13 | .kotlin/ 14 | *.orig.* 15 | *.jks 16 | *.p8 17 | *.p12 18 | *.key 19 | 20 | # Metro 21 | .metro-health-check* 22 | 23 | # debug 24 | npm-debug.* 25 | yarn-debug.* 26 | yarn-error.* 27 | 28 | # macOS 29 | .DS_Store 30 | *.pem 31 | 32 | # local env files 33 | .env*.local 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | 38 | app-example 39 | -------------------------------------------------------------------------------- /tooling/typescript/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "incremental": false, 8 | "isolatedModules": true, 9 | "lib": ["es2022", "DOM", "DOM.Iterable"], 10 | "module": "NodeNext", 11 | "moduleDetection": "force", 12 | "moduleResolution": "NodeNext", 13 | "noUncheckedIndexedAccess": true, 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true, 16 | "strict": true, 17 | "target": "ES2022" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@acme/auth", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "type": "module", 7 | "dependencies": { 8 | "@better-auth/expo": "^1.3.34", 9 | "better-auth": "^1.3.34", 10 | "pg": "^8.16.3" 11 | }, 12 | "devDependencies": { 13 | "@acme/eslint": "workspace:*", 14 | "@acme/typescript": "workspace:*", 15 | "@types/node": "^22.19.1", 16 | "@types/pg": "^8.15.6" 17 | }, 18 | "exports": { 19 | "./better-auth": "./better-auth.ts", 20 | "./better-auth-client": "./better-auth-client.ts" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # env files (can opt-in for commiting if needed) 29 | .env* 30 | !.env.example 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | certificates -------------------------------------------------------------------------------- /apps/mobile/components/ui/card/styles.tsx: -------------------------------------------------------------------------------- 1 | import { tva } from '@gluestack-ui/nativewind-utils/tva'; 2 | import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb'; 3 | const baseStyle = isWeb ? 'flex flex-col relative z-0' : ''; 4 | 5 | export const cardStyle = tva({ 6 | base: baseStyle, 7 | variants: { 8 | size: { 9 | sm: 'p-3 rounded', 10 | md: 'p-4 rounded-md', 11 | lg: 'p-6 rounded-xl', 12 | }, 13 | variant: { 14 | elevated: 'bg-background-0', 15 | outline: 'border border-outline-200 ', 16 | ghost: 'rounded-none', 17 | filled: 'bg-background-50', 18 | }, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.com/schema.json", 3 | "ui": "tui", 4 | "globalEnv": [ 5 | "NODE_ENV", 6 | "DATABASE_URL", 7 | "BETTER_AUTH_SECRET", 8 | "BETTER_AUTH_URL" 9 | ], 10 | "tasks": { 11 | "build": { 12 | "dependsOn": ["^build"], 13 | "inputs": ["$TURBO_DEFAULT$", ".env*"], 14 | "outputs": [".next/**", "!.next/cache/**"] 15 | }, 16 | "lint": { 17 | "dependsOn": ["^lint"] 18 | }, 19 | "check-types": { 20 | "dependsOn": ["^check-types"] 21 | }, 22 | "dev": { 23 | "cache": false, 24 | "persistent": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /apps/web/public/file-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/gluestack-ui-provider/script.ts: -------------------------------------------------------------------------------- 1 | export const script = (mode: string) => { 2 | const documentElement = document.documentElement; 3 | 4 | function getSystemColorMode() { 5 | return window.matchMedia('(prefers-color-scheme: dark)').matches 6 | ? 'dark' 7 | : 'light'; 8 | } 9 | 10 | try { 11 | const isSystem = mode === 'system'; 12 | const theme = isSystem ? getSystemColorMode() : mode; 13 | documentElement.classList.remove(theme === 'light' ? 'dark' : 'light'); 14 | documentElement.classList.add(theme); 15 | documentElement.style.colorScheme = theme; 16 | } catch (e) { 17 | console.error(e); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/card/index.web.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cardStyle } from './styles'; 3 | import type { VariantProps } from '@gluestack-ui/nativewind-utils'; 4 | 5 | type ICardProps = React.ComponentPropsWithoutRef<'div'> & 6 | VariantProps; 7 | 8 | const Card = React.forwardRef(function Card( 9 | { className, size = 'md', variant = 'elevated', ...props }, 10 | ref 11 | ) { 12 | return ( 13 |
18 | ); 19 | }); 20 | 21 | Card.displayName = 'Card'; 22 | 23 | export { Card }; 24 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | open-pull-requests-limit: 1 13 | groups: 14 | all-dependencies: 15 | patterns: 16 | - "*" 17 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/hstack/index.web.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { VariantProps } from '@gluestack-ui/nativewind-utils'; 3 | import { hstackStyle } from './styles'; 4 | 5 | type IHStackProps = React.ComponentPropsWithoutRef<'div'> & 6 | VariantProps; 7 | 8 | const HStack = React.forwardRef, IHStackProps>( 9 | function HStack({ className, space, reversed, ...props }, ref) { 10 | return ( 11 |
16 | ); 17 | } 18 | ); 19 | 20 | HStack.displayName = 'HStack'; 21 | 22 | export { HStack }; 23 | -------------------------------------------------------------------------------- /tooling/eslint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@acme/eslint", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "exports": { 7 | "./base": "./base.js", 8 | "./next-js": "./next.js", 9 | "./react-internal": "./react-internal.js" 10 | }, 11 | "devDependencies": { 12 | "@eslint/js": "^9.39.1", 13 | "@next/eslint-plugin-next": "^15.5.6", 14 | "eslint": "^9.39.1", 15 | "eslint-config-prettier": "^10.1.8", 16 | "eslint-plugin-only-warn": "^1.1.0", 17 | "eslint-plugin-react": "^7.37.5", 18 | "eslint-plugin-react-hooks": "^5.2.0", 19 | "eslint-plugin-turbo": "^2.6.1", 20 | "globals": "^16.5.0", 21 | "typescript": "^5.9.3", 22 | "typescript-eslint": "^8.46.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/ui/src/components/label.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import * as LabelPrimitive from "@radix-ui/react-label"; 5 | 6 | import { cn } from "@acme/ui/lib/utils"; 7 | 8 | function Label({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | ); 22 | } 23 | 24 | export { Label }; 25 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/hstack/styles.tsx: -------------------------------------------------------------------------------- 1 | import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb'; 2 | import { tva } from '@gluestack-ui/nativewind-utils/tva'; 3 | 4 | const baseStyle = isWeb 5 | ? 'flex relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none' 6 | : ''; 7 | 8 | export const hstackStyle = tva({ 9 | base: `flex-row ${baseStyle}`, 10 | variants: { 11 | space: { 12 | 'xs': 'gap-1', 13 | 'sm': 'gap-2', 14 | 'md': 'gap-3', 15 | 'lg': 'gap-4', 16 | 'xl': 'gap-5', 17 | '2xl': 'gap-6', 18 | '3xl': 'gap-7', 19 | '4xl': 'gap-8', 20 | }, 21 | reversed: { 22 | true: 'flex-row-reverse', 23 | }, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /apps/web/public/window.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/hstack/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { VariantProps } from '@gluestack-ui/nativewind-utils'; 3 | import { View } from 'react-native'; 4 | import type { ViewProps } from 'react-native'; 5 | import { hstackStyle } from './styles'; 6 | 7 | type IHStackProps = ViewProps & VariantProps; 8 | 9 | const HStack = React.forwardRef, IHStackProps>( 10 | function HStack({ className, space, reversed, ...props }, ref) { 11 | return ( 12 | 17 | ); 18 | } 19 | ); 20 | 21 | HStack.displayName = 'HStack'; 22 | 23 | export { HStack }; 24 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/card/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { VariantProps } from '@gluestack-ui/nativewind-utils'; 3 | import { View, ViewProps } from 'react-native'; 4 | import { cardStyle } from './styles'; 5 | 6 | type ICardProps = ViewProps & 7 | VariantProps & { className?: string }; 8 | 9 | const Card = React.forwardRef, ICardProps>( 10 | function Card( 11 | { className, size = 'md', variant = 'elevated', ...props }, 12 | ref 13 | ) { 14 | return ( 15 | 20 | ); 21 | } 22 | ); 23 | 24 | Card.displayName = 'Card'; 25 | 26 | export { Card }; 27 | -------------------------------------------------------------------------------- /tooling/eslint/base.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import eslintConfigPrettier from "eslint-config-prettier"; 3 | import turboPlugin from "eslint-plugin-turbo"; 4 | import tseslint from "typescript-eslint"; 5 | import onlyWarn from "eslint-plugin-only-warn"; 6 | 7 | /** 8 | * A shared ESLint configuration for the repository. 9 | * 10 | * @type {import("eslint").Linter.Config[]} 11 | * */ 12 | export const config = [ 13 | js.configs.recommended, 14 | eslintConfigPrettier, 15 | ...tseslint.configs.recommended, 16 | { 17 | plugins: { 18 | turbo: turboPlugin, 19 | }, 20 | rules: { 21 | "turbo/no-undeclared-env-vars": "warn", 22 | }, 23 | }, 24 | { 25 | plugins: { 26 | onlyWarn, 27 | }, 28 | }, 29 | { 30 | ignores: ["dist/**"], 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "next dev --turbopack --port 3000", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint --max-warnings 0", 11 | "check-types": "tsc --noEmit", 12 | "db:generate": "npx @better-auth/cli generate --output ../../packages/db/src/migration.sql" 13 | }, 14 | "dependencies": { 15 | "@acme/auth": "workspace:*", 16 | "@acme/tailwind": "workspace:*", 17 | "@acme/ui": "workspace:*", 18 | "@types/pg": "^8.15.6", 19 | "lucide-react": "^0.525.0", 20 | "next": "^15.5.6", 21 | "pg": "^8.16.3", 22 | "react": "^19.2.0", 23 | "react-dom": "^19.2.0" 24 | }, 25 | "devDependencies": { 26 | "@acme/eslint": "workspace:*", 27 | "@acme/typescript": "workspace:*", 28 | "@types/node": "^22.19.1", 29 | "@types/react": "~19.0.14", 30 | "@types/react-dom": "~19.0.6", 31 | "eslint": "^9.39.1", 32 | "typescript": "5.9.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/db/src/migration.sql: -------------------------------------------------------------------------------- 1 | create table "user" ("id" text not null primary key, "name" text not null, "email" text not null unique, "emailVerified" boolean not null, "image" text, "createdAt" timestamp not null, "updatedAt" timestamp not null); 2 | 3 | create table "session" ("id" text not null primary key, "expiresAt" timestamp not null, "token" text not null unique, "createdAt" timestamp not null, "updatedAt" timestamp not null, "ipAddress" text, "userAgent" text, "userId" text not null references "user" ("id")); 4 | 5 | create table "account" ("id" text not null primary key, "accountId" text not null, "providerId" text not null, "userId" text not null references "user" ("id"), "accessToken" text, "refreshToken" text, "idToken" text, "accessTokenExpiresAt" timestamp, "refreshTokenExpiresAt" timestamp, "scope" text, "password" text, "createdAt" timestamp not null, "updatedAt" timestamp not null); 6 | 7 | create table "verification" ("id" text not null primary key, "identifier" text not null, "value" text not null, "expiresAt" timestamp not null, "createdAt" timestamp, "updatedAt" timestamp); -------------------------------------------------------------------------------- /packages/ui/src/components/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@acme/ui/lib/utils"; 4 | 5 | function Input({ className, type, ...props }: React.ComponentProps<"input">) { 6 | return ( 7 | 18 | ); 19 | } 20 | 21 | export { Input }; 22 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/text/index.web.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { VariantProps } from '@gluestack-ui/nativewind-utils'; 3 | import { textStyle } from './styles'; 4 | 5 | type ITextProps = React.ComponentProps<'span'> & VariantProps; 6 | 7 | const Text = React.forwardRef, ITextProps>( 8 | function Text( 9 | { 10 | className, 11 | isTruncated, 12 | bold, 13 | underline, 14 | strikeThrough, 15 | size = 'md', 16 | sub, 17 | italic, 18 | highlight, 19 | ...props 20 | }: { className?: string } & ITextProps, 21 | ref 22 | ) { 23 | return ( 24 | 39 | ); 40 | } 41 | ); 42 | 43 | Text.displayName = 'Text'; 44 | 45 | export { Text }; 46 | -------------------------------------------------------------------------------- /apps/mobile/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "mobile", 4 | "slug": "mobile", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/images/icon.png", 8 | "scheme": "mobile", 9 | "userInterfaceStyle": "automatic", 10 | "newArchEnabled": true, 11 | "ios": { 12 | "supportsTablet": true 13 | }, 14 | "android": { 15 | "adaptiveIcon": { 16 | "foregroundImage": "./assets/images/adaptive-icon.png", 17 | "backgroundColor": "#ffffff" 18 | }, 19 | "edgeToEdgeEnabled": true 20 | }, 21 | "web": { 22 | "bundler": "metro", 23 | "output": "server", 24 | "favicon": "./assets/images/favicon.png" 25 | }, 26 | "plugins": [ 27 | "expo-router", 28 | [ 29 | "expo-splash-screen", 30 | { 31 | "image": "./assets/images/splash-icon.png", 32 | "imageWidth": 200, 33 | "resizeMode": "contain", 34 | "backgroundColor": "#ffffff" 35 | } 36 | ] 37 | ], 38 | "experiments": { 39 | "typedRoutes": true 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Timur 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/gluestack-ui-provider/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import { config } from './config'; 3 | import { View, ViewProps } from 'react-native'; 4 | import { OverlayProvider } from '@gluestack-ui/overlay'; 5 | import { ToastProvider } from '@gluestack-ui/toast'; 6 | import { useColorScheme } from 'nativewind'; 7 | 8 | export type ModeType = 'light' | 'dark' | 'system'; 9 | 10 | export function GluestackUIProvider({ 11 | mode = 'light', 12 | ...props 13 | }: { 14 | mode?: ModeType; 15 | children?: React.ReactNode; 16 | style?: ViewProps['style']; 17 | }) { 18 | const { colorScheme, setColorScheme } = useColorScheme(); 19 | 20 | useEffect(() => { 21 | setColorScheme(mode); 22 | // eslint-disable-next-line react-hooks/exhaustive-deps 23 | }, [mode]); 24 | 25 | return ( 26 | 33 | 34 | {props.children} 35 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/text/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import type { VariantProps } from '@gluestack-ui/nativewind-utils'; 4 | import { Text as RNText } from 'react-native'; 5 | import { textStyle } from './styles'; 6 | 7 | type ITextProps = React.ComponentProps & 8 | VariantProps; 9 | 10 | const Text = React.forwardRef, ITextProps>( 11 | function Text( 12 | { 13 | className, 14 | isTruncated, 15 | bold, 16 | underline, 17 | strikeThrough, 18 | size = 'md', 19 | sub, 20 | italic, 21 | highlight, 22 | ...props 23 | }, 24 | ref 25 | ) { 26 | return ( 27 | 42 | ); 43 | } 44 | ); 45 | 46 | Text.displayName = 'Text'; 47 | 48 | export { Text }; 49 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/heading/styles.tsx: -------------------------------------------------------------------------------- 1 | import { tva } from '@gluestack-ui/nativewind-utils/tva'; 2 | import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb'; 3 | const baseStyle = isWeb 4 | ? 'font-sans tracking-sm bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word' 5 | : ''; 6 | 7 | export const headingStyle = tva({ 8 | base: `text-typography-900 font-bold font-heading tracking-sm my-0 ${baseStyle}`, 9 | variants: { 10 | isTruncated: { 11 | true: 'truncate', 12 | }, 13 | bold: { 14 | true: 'font-bold', 15 | }, 16 | underline: { 17 | true: 'underline', 18 | }, 19 | strikeThrough: { 20 | true: 'line-through', 21 | }, 22 | sub: { 23 | true: 'text-xs', 24 | }, 25 | italic: { 26 | true: 'italic', 27 | }, 28 | highlight: { 29 | true: 'bg-yellow-500', 30 | }, 31 | size: { 32 | '5xl': 'text-6xl', 33 | '4xl': 'text-5xl', 34 | '3xl': 'text-4xl', 35 | '2xl': 'text-3xl', 36 | 'xl': 'text-2xl', 37 | 'lg': 'text-xl', 38 | 'md': 'text-lg', 39 | 'sm': 'text-base', 40 | 'xs': 'text-sm', 41 | }, 42 | }, 43 | }); 44 | -------------------------------------------------------------------------------- /tooling/eslint/react-internal.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import eslintConfigPrettier from "eslint-config-prettier"; 3 | import tseslint from "typescript-eslint"; 4 | import pluginReactHooks from "eslint-plugin-react-hooks"; 5 | import pluginReact from "eslint-plugin-react"; 6 | import globals from "globals"; 7 | import { config as baseConfig } from "./base.js"; 8 | 9 | /** 10 | * A custom ESLint configuration for libraries that use React. 11 | * 12 | * @type {import("eslint").Linter.Config[]} */ 13 | export const config = [ 14 | ...baseConfig, 15 | js.configs.recommended, 16 | eslintConfigPrettier, 17 | ...tseslint.configs.recommended, 18 | pluginReact.configs.flat.recommended, 19 | { 20 | languageOptions: { 21 | ...pluginReact.configs.flat.recommended.languageOptions, 22 | globals: { 23 | ...globals.serviceworker, 24 | ...globals.browser, 25 | }, 26 | }, 27 | }, 28 | { 29 | plugins: { 30 | "react-hooks": pluginReactHooks, 31 | }, 32 | settings: { react: { version: "detect" } }, 33 | rules: { 34 | ...pluginReactHooks.configs.recommended.rules, 35 | // React scope no longer necessary with new JSX transform. 36 | "react/react-in-jsx-scope": "off", 37 | }, 38 | }, 39 | ]; 40 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/text/styles.tsx: -------------------------------------------------------------------------------- 1 | import { tva } from '@gluestack-ui/nativewind-utils/tva'; 2 | import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb'; 3 | 4 | const baseStyle = isWeb 5 | ? 'font-sans tracking-sm my-0 bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word' 6 | : ''; 7 | 8 | export const textStyle = tva({ 9 | base: `text-typography-700 font-body ${baseStyle}`, 10 | 11 | variants: { 12 | isTruncated: { 13 | true: 'web:truncate', 14 | }, 15 | bold: { 16 | true: 'font-bold', 17 | }, 18 | underline: { 19 | true: 'underline', 20 | }, 21 | strikeThrough: { 22 | true: 'line-through', 23 | }, 24 | size: { 25 | '2xs': 'text-2xs', 26 | 'xs': 'text-xs', 27 | 'sm': 'text-sm', 28 | 'md': 'text-base', 29 | 'lg': 'text-lg', 30 | 'xl': 'text-xl', 31 | '2xl': 'text-2xl', 32 | '3xl': 'text-3xl', 33 | '4xl': 'text-4xl', 34 | '5xl': 'text-5xl', 35 | '6xl': 'text-6xl', 36 | }, 37 | sub: { 38 | true: 'text-xs', 39 | }, 40 | italic: { 41 | true: 'italic', 42 | }, 43 | highlight: { 44 | true: 'bg-yellow-500', 45 | }, 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@acme/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "lint": "eslint . --max-warnings 0", 7 | "check-types": "tsc --noEmit", 8 | "ui:add": "pnpm dlx shadcn@latest add" 9 | }, 10 | "devDependencies": { 11 | "@acme/eslint": "workspace:*", 12 | "@acme/typescript": "workspace:*", 13 | "@types/node": "^22.19.1", 14 | "@types/react": "~19.0.14", 15 | "@types/react-dom": "~19.0.6", 16 | "eslint": "^9.39.1", 17 | "typescript": "5.9.3" 18 | }, 19 | "dependencies": { 20 | "@radix-ui/react-checkbox": "^1.3.3", 21 | "@radix-ui/react-label": "^2.1.8", 22 | "@radix-ui/react-slot": "^1.2.4", 23 | "class-variance-authority": "^0.7.1", 24 | "clsx": "^2.1.1", 25 | "lucide-react": "^0.525.0", 26 | "react": "^19.2.0", 27 | "react-dom": "^19.2.0", 28 | "tailwind-merge": "^3.4.0", 29 | "tailwindcss": "^4.1.17", 30 | "tw-animate-css": "^1.4.0" 31 | }, 32 | "sideEffects": [ 33 | "./src/lib/globals.css" 34 | ], 35 | "exports": { 36 | "./globals.css": "./src/lib/globals.css", 37 | "./lib/*": "./src/lib/*.ts", 38 | "./components/*": [ 39 | "./src/components/*.tsx", 40 | "./src/components/*.ts" 41 | ], 42 | "./hooks/*": "./src/hooks/*.ts" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /apps/web/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/ui/src/components/checkbox.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; 5 | import { CheckIcon } from "lucide-react"; 6 | 7 | import { cn } from "@acme/ui/lib/utils"; 8 | 9 | function Checkbox({ 10 | className, 11 | ...props 12 | }: React.ComponentProps) { 13 | return ( 14 | 22 | 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | export { Checkbox }; 33 | -------------------------------------------------------------------------------- /apps/mobile/components/ui/image/index.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import React from 'react'; 3 | import { createImage } from '@gluestack-ui/image'; 4 | import { Platform, Image as RNImage } from 'react-native'; 5 | import { tva } from '@gluestack-ui/nativewind-utils/tva'; 6 | import type { VariantProps } from '@gluestack-ui/nativewind-utils'; 7 | 8 | const imageStyle = tva({ 9 | base: 'max-w-full', 10 | variants: { 11 | size: { 12 | '2xs': 'h-6 w-6', 13 | 'xs': 'h-10 w-10', 14 | 'sm': 'h-16 w-16', 15 | 'md': 'h-20 w-20', 16 | 'lg': 'h-24 w-24', 17 | 'xl': 'h-32 w-32', 18 | '2xl': 'h-64 w-64', 19 | 'full': 'h-full w-full', 20 | 'none': '', 21 | }, 22 | }, 23 | }); 24 | 25 | const UIImage = createImage({ Root: RNImage }); 26 | 27 | type ImageProps = VariantProps & 28 | React.ComponentProps; 29 | const Image = React.forwardRef< 30 | React.ComponentRef, 31 | ImageProps & { className?: string } 32 | >(function Image({ size = 'md', className, ...props }, ref) { 33 | return ( 34 | 45 | ); 46 | }); 47 | 48 | Image.displayName = 'Image'; 49 | export { Image }; 50 | -------------------------------------------------------------------------------- /tooling/eslint/next.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import eslintConfigPrettier from "eslint-config-prettier"; 3 | import tseslint from "typescript-eslint"; 4 | import pluginReactHooks from "eslint-plugin-react-hooks"; 5 | import pluginReact from "eslint-plugin-react"; 6 | import globals from "globals"; 7 | import pluginNext from "@next/eslint-plugin-next"; 8 | import { config as baseConfig } from "./base.js"; 9 | 10 | /** 11 | * A custom ESLint configuration for libraries that use Next.js. 12 | * 13 | * @type {import("eslint").Linter.Config[]} 14 | * */ 15 | export const nextJsConfig = [ 16 | ...baseConfig, 17 | js.configs.recommended, 18 | eslintConfigPrettier, 19 | ...tseslint.configs.recommended, 20 | { 21 | ...pluginReact.configs.flat.recommended, 22 | languageOptions: { 23 | ...pluginReact.configs.flat.recommended.languageOptions, 24 | globals: { 25 | ...globals.serviceworker, 26 | }, 27 | }, 28 | }, 29 | { 30 | plugins: { 31 | "@next/next": pluginNext, 32 | }, 33 | rules: { 34 | ...pluginNext.configs.recommended.rules, 35 | ...pluginNext.configs["core-web-vitals"].rules, 36 | }, 37 | }, 38 | { 39 | plugins: { 40 | "react-hooks": pluginReactHooks, 41 | }, 42 | settings: { react: { version: "detect" } }, 43 | rules: { 44 | ...pluginReactHooks.configs.recommended.rules, 45 | // React scope no longer necessary with new JSX transform. 46 | "react/react-in-jsx-scope": "off", 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /apps/mobile/app/sign-in.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { View, TextInput, Button, Alert } from "react-native"; 3 | import { authClient } from "../lib/auth/auth-client"; 4 | 5 | export default function SignIn() { 6 | const [email, setEmail] = useState(""); 7 | const [password, setPassword] = useState(""); 8 | const [loading, setLoading] = useState(false); 9 | 10 | const handleLogin = async () => { 11 | try { 12 | setLoading(true); 13 | const { data, error } = await authClient.signIn.email({ 14 | email, 15 | password, 16 | }); 17 | 18 | if (error) { 19 | Alert.alert("Error", error.message); 20 | return; 21 | } 22 | 23 | // Navigation will be handled by your app's auth state 24 | console.log("Signed in successfully:", data); 25 | } catch (error) { 26 | Alert.alert("Error", "Failed to sign in"); 27 | console.error("Sign in error:", error); 28 | } finally { 29 | setLoading(false); 30 | } 31 | }; 32 | 33 | return ( 34 | 35 | 43 | 50 |