diff --git a/.gitignore b/.gitignore index 882155b..2582c5c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,7 @@ __pycache__/ .pytest_cache/ .coverage htmlcov/ + +.turbo +dist +.wrangler \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4afad3d --- /dev/null +++ b/README.md @@ -0,0 +1,172 @@ +# Xtablo Monorepo + +This is a Turborepo-based monorepo for the Xtablo project, containing multiple apps and shared packages. + +## Project Structure + +``` +xtablo-source/ +├── apps/ +│ ├── main/ # Main UI application +│ └── external/ # External booking widget microfrontend +├── packages/ +│ ├── ui-components/ # Shared UI components (buttons, inputs, etc.) +│ └── shared/ # Shared utilities, hooks, contexts, and types +├── api/ # TypeScript/Node.js API +├── backend/ # Python backend +├── go_backend/ # Go backend +└── xtablo-expo/ # React Native Expo app +``` + +## Getting Started + +### Prerequisites + +- Node.js 18+ and pnpm +- For other services: Python 3.11+, Go 1.21+ + +### Installation + +Install all dependencies: + +```bash +pnpm install +``` + +This will install dependencies for all apps and packages in the workspace. + +### Development + +Run all apps in development mode: + +```bash +turbo dev +``` + +Run specific app: + +```bash +# Main UI app (http://localhost:5173) +turbo dev --filter @xtablo/main + +# External microfrontend (http://localhost:5174) +turbo dev --filter @xtablo/external +``` + +### Building + +Build all apps: + +```bash +turbo build +``` + +Build specific app: + +```bash +turbo build --filter @xtablo/main +turbo build --filter @xtablo/external +``` + +### Linting and Formatting + +```bash +# Lint all packages +turbo lint + +# Format all packages +turbo format +``` + +## Packages + +### @xtablo/ui-components + +Shared UI components library used across the main and external apps. Contains all base UI components like buttons, inputs, dialogs, etc. + +**Usage:** + +```typescript +import { Button, Input, Dialog } from "@xtablo/ui-components"; +``` + +### @xtablo/shared + +Shared utilities, hooks, contexts, and types used across apps. + +**Usage:** + +```typescript +import { useSession } from "@xtablo/shared/contexts/SessionContext"; +import { api } from "@xtablo/shared/lib/api"; +import { Tables } from "@xtablo/shared/types/database.types"; +``` + +## Apps + +### Main (@xtablo/main) + +The main Xtablo application with full dashboard, planning, chat, and administrative features. + +**Local URL:** http://localhost:5173 + +### External (@xtablo/external) + +Embeddable booking widget that can be integrated into external websites. Supports both embedded and floating widget modes. + +**Local URL:** http://localhost:5174 + +**Usage:** + +- Embedded mode: `?mode=embed&eventTypeId=...` +- Floating widget: `?mode=widget&eventTypeId=...` + +## Turborepo Features + +This monorepo uses Turborepo for: + +- **Fast builds**: Parallel task execution and intelligent caching +- **Dependency management**: Automatic build ordering based on package dependencies +- **Code sharing**: Easy sharing of components and utilities between apps + +## Scripts + +- `turbo dev` - Start all apps in development mode +- `turbo build` - Build all apps +- `turbo lint` - Lint all packages +- `turbo format` - Format all packages +- `turbo typecheck` - Type check all packages +- `turbo test` - Run tests for all packages +- `turbo clean` - Clean all build artifacts and node_modules + +## Adding a New Package + +1. Create a new directory under `packages/` +2. Add a `package.json` with name `@xtablo/package-name` +3. Update `pnpm-workspace.yaml` if needed (already configured for `packages/*`) +4. Install in your app: `pnpm --filter @xtablo/your-app add @xtablo/package-name@workspace:*` + +## Migration Notes + +This project was migrated from a single UI app to a Turborepo monorepo with the following changes: + +- **Before**: Single `ui/` directory with all code +- **After**: + - `apps/main/` - Main application + - `apps/external/` - Separate microfrontend for booking widgets + - `packages/ui-components/` - Shared UI components + - `packages/shared/` - Shared utilities and logic + +All import paths have been updated to use workspace packages (`@xtablo/ui-components`, `@xtablo/shared`). + +## Contributing + +When adding new shared code: + +1. Add to the appropriate package (`ui-components` for UI, `shared` for logic/utils) +2. Export from the package's `index.ts` +3. Use the workspace import in your apps + +## License + +[Your License Here] diff --git a/apps/external/biome.json b/apps/external/biome.json new file mode 100644 index 0000000..3dc1855 --- /dev/null +++ b/apps/external/biome.json @@ -0,0 +1,342 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.2.5/schema.json", + "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, + "files": { + "includes": [ + "ui/src/**/*", + "ui/worker/**/*", + "ui/*.{ts,tsx,js,jsx,json}", + "api/src/**/*", + "api/*.{ts,tsx,js,jsx,json}", + "xtablo-expo/app/**/*", + "xtablo-expo/components/**/*", + "xtablo-expo/hooks/**/*", + "xtablo-expo/lib/**/*", + "xtablo-expo/providers/**/*", + "xtablo-expo/stores/**/*", + "xtablo-expo/types/**/*", + "xtablo-expo/*.{ts,tsx,js,jsx,json}" + ] + }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 100, + "attributePosition": "auto" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": false, + "complexity": { + "noAdjacentSpacesInRegex": "error", + "noBannedTypes": "error", + "noExtraBooleanCast": "error", + "noUselessCatch": "error", + "noUselessEscapeInRegex": "error", + "noUselessTypeConstraint": "error" + }, + "correctness": { + "noChildrenProp": "error", + "noConstAssign": "error", + "noConstantCondition": "error", + "noEmptyCharacterClassInRegex": "error", + "noEmptyPattern": "error", + "noGlobalObjectCalls": "error", + "noInvalidBuiltinInstantiation": "error", + "noInvalidConstructorSuper": "error", + "noNonoctalDecimalEscape": "error", + "noPrecisionLoss": "error", + "noSelfAssign": "error", + "noSetterReturn": "error", + "noSwitchDeclarations": "error", + "noUndeclaredVariables": "error", + "noUnreachable": "error", + "noUnreachableSuper": "error", + "noUnsafeFinally": "error", + "noUnsafeOptionalChaining": "error", + "noUnusedLabels": "error", + "noUnusedPrivateClassMembers": "error", + "noUnusedVariables": "error", + "noUnusedImports": "error", + "useIsNan": "error", + "useJsxKeyInIterable": "error", + "useValidForDirection": "error", + "useValidTypeof": "error", + "useYield": "error" + }, + "nursery": {}, + "security": { "noDangerouslySetInnerHtmlWithChildren": "error" }, + "style": { + "noCommonJs": "error", + "noNamespace": "error", + "useArrayLiterals": "error", + "useAsConstAssertion": "error", + "useConst": "error", + "useTemplate": "error" + }, + "suspicious": { + "noAsyncPromiseExecutor": "error", + "noCatchAssign": "error", + "noClassAssign": "error", + "noCommentText": "error", + "noCompareNegZero": "error", + "noConstantBinaryExpressions": "error", + "noControlCharactersInRegex": "error", + "noDebugger": "error", + "noDuplicateCase": "error", + "noDuplicateClassMembers": "error", + "noDuplicateElseIf": "error", + "noDuplicateJsxProps": "error", + "noDuplicateObjectKeys": "error", + "noDuplicateParameters": "error", + "noEmptyBlockStatements": "error", + "noExplicitAny": "error", + "noExtraNonNullAssertion": "error", + "noFallthroughSwitchClause": "error", + "noFunctionAssign": "error", + "noGlobalAssign": "error", + "noImportAssign": "error", + "noIrregularWhitespace": "error", + "noMisleadingCharacterClass": "error", + "noMisleadingInstantiator": "error", + "noPrototypeBuiltins": "error", + "noRedeclare": "error", + "noShadowRestrictedNames": "error", + "noSparseArray": "error", + "noUnsafeDeclarationMerging": "error", + "noUnsafeNegation": "error", + "noUselessRegexBackrefs": "error", + "noWith": "error", + "useGetterReturn": "error", + "useNamespaceKeyword": "error" + } + } + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "trailingCommas": "es5", + "semicolons": "always", + "arrowParentheses": "always", + "bracketSameLine": false, + "quoteStyle": "double", + "attributePosition": "auto", + "bracketSpacing": true + }, + "globals": [ + "onanimationend", + "ongamepadconnected", + "onlostpointercapture", + "onanimationiteration", + "onkeyup", + "onmousedown", + "onanimationstart", + "onslotchange", + "onprogress", + "ontransitionstart", + "onpause", + "onended", + "onpointerover", + "onscrollend", + "onformdata", + "ontransitionrun", + "onanimationcancel", + "ondrag", + "onchange", + "onbeforeinstallprompt", + "onbeforexrselect", + "onmessage", + "ontransitioncancel", + "onpointerdown", + "onabort", + "onpointerout", + "oncuechange", + "ongotpointercapture", + "onscrollsnapchanging", + "onsearch", + "onsubmit", + "onstalled", + "onsuspend", + "onreset", + "onerror", + "onresize", + "onmouseenter", + "ongamepaddisconnected", + "ondragover", + "onbeforetoggle", + "onmouseover", + "onpagehide", + "onmousemove", + "onratechange", + "onmessageerror", + "onwheel", + "ondevicemotion", + "onauxclick", + "ontransitionend", + "onpaste", + "onpageswap", + "ononline", + "ondeviceorientationabsolute", + "onkeydown", + "onclose", + "onselect", + "onpageshow", + "onpointercancel", + "onbeforematch", + "onpointerrawupdate", + "ondragleave", + "onscrollsnapchange", + "onseeked", + "onwaiting", + "onbeforeunload", + "onplaying", + "onvolumechange", + "ondragend", + "onstorage", + "onloadeddata", + "onfocus", + "onoffline", + "onplay", + "onafterprint", + "onclick", + "oncut", + "onmouseout", + "ondblclick", + "oncanplay", + "onloadstart", + "onappinstalled", + "onpointermove", + "ontoggle", + "oncontextmenu", + "onblur", + "oncancel", + "onbeforeprint", + "oncontextrestored", + "onloadedmetadata", + "onpointerup", + "onlanguagechange", + "oncopy", + "onselectstart", + "onscroll", + "onload", + "ondragstart", + "onbeforeinput", + "oncanplaythrough", + "oninput", + "oninvalid", + "ontimeupdate", + "ondurationchange", + "onselectionchange", + "onmouseup", + "location", + "onkeypress", + "onpointerleave", + "oncontextlost", + "ondrop", + "onsecuritypolicyviolation", + "oncontentvisibilityautostatechange", + "ondeviceorientation", + "onseeking", + "onrejectionhandled", + "onunload", + "onmouseleave", + "onhashchange", + "onpointerenter", + "onmousewheel", + "onunhandledrejection", + "ondragenter", + "onpopstate", + "onpagereveal", + "onemptied" + ] + }, + "json": { + "parser": { "allowComments": true, "allowTrailingCommas": false }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 100, + "trailingCommas": "none" + } + }, + "overrides": [ + { "linter": { "rules": { "suspicious": { "noExplicitAny": "off" } } } }, + { "linter": { "rules": { "style": { "useNodejsImportProtocol": "off" } } } }, + { + "linter": { + "rules": { + "style": { "useNodejsImportProtocol": "off" }, + "suspicious": { "noExplicitAny": "off" } + } + } + }, + { + "includes": [ + "ui/src/**/*.{ts,tsx}", + "ui/worker/**/*.{ts,tsx}", + "ui/*.{ts,tsx}", + "api/src/**/*.{ts,tsx}", + "api/*.{ts,tsx}", + "xtablo-expo/**/*.{ts,tsx}" + ], + "linter": { + "rules": { + "complexity": { "noArguments": "error" }, + "correctness": { + "noConstAssign": "off", + "noGlobalObjectCalls": "off", + "noInvalidBuiltinInstantiation": "off", + "noInvalidConstructorSuper": "off", + "noSetterReturn": "off", + "noUndeclaredVariables": "off", + "noUnreachable": "off", + "noUnreachableSuper": "off" + }, + "style": { "useConst": "error" }, + "suspicious": { + "noClassAssign": "off", + "noDuplicateClassMembers": "off", + "noDuplicateObjectKeys": "off", + "noDuplicateParameters": "off", + "noFunctionAssign": "off", + "noImportAssign": "off", + "noRedeclare": "off", + "noUnsafeNegation": "off", + "noVar": "error", + "useGetterReturn": "off" + } + } + } + }, + { + "includes": ["xtablo-expo/**/*.{js,jsx,ts,tsx}"], + "linter": { + "rules": { + "correctness": { + "noUndeclaredVariables": "off" + }, + "suspicious": { + "noExplicitAny": "warn" + } + } + } + }, + { + "includes": ["api/src/**/*.{js,ts}"], + "linter": { + "rules": { + "style": { + "noCommonJs": "off" + } + } + } + } + ] +} diff --git a/ui/external/index.html b/apps/external/index.html similarity index 70% rename from ui/external/index.html rename to apps/external/index.html index cffb5be..f49f514 100644 --- a/ui/external/index.html +++ b/apps/external/index.html @@ -3,9 +3,10 @@
+