inicontent 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/.github/pull_request.yml +18 -0
  2. package/CONTRIBUTING.md +67 -0
  3. package/LICENSE +21 -0
  4. package/README.md +142 -0
  5. package/app/app.vue +106 -0
  6. package/app/assets/main.css +974 -0
  7. package/app/components/Api/EndpointCard.vue +169 -0
  8. package/app/components/Api/SchemaDocsTable.vue +208 -0
  9. package/app/components/Asset/Card.vue +1363 -0
  10. package/app/components/Asset/Grid.vue +295 -0
  11. package/app/components/Asset/Icon.vue +38 -0
  12. package/app/components/Asset/Preview.vue +486 -0
  13. package/app/components/Asset/Scanner.vue +700 -0
  14. package/app/components/Asset/Thumb.vue +708 -0
  15. package/app/components/Auth/Reset.vue +99 -0
  16. package/app/components/Auth/index.vue +346 -0
  17. package/app/components/ChatInterface.vue +2326 -0
  18. package/app/components/ChatPagePreview.vue +34 -0
  19. package/app/components/Column/Array.vue +29 -0
  20. package/app/components/Column/Asset.vue +21 -0
  21. package/app/components/Column/Boolean.vue +12 -0
  22. package/app/components/Column/Color.vue +9 -0
  23. package/app/components/Column/Date.vue +57 -0
  24. package/app/components/Column/Edit.vue +215 -0
  25. package/app/components/Column/Email.vue +9 -0
  26. package/app/components/Column/Html.vue +27 -0
  27. package/app/components/Column/Id.vue +20 -0
  28. package/app/components/Column/Locale.vue +32 -0
  29. package/app/components/Column/Object.vue +18 -0
  30. package/app/components/Column/Password.vue +7 -0
  31. package/app/components/Column/Role.vue +15 -0
  32. package/app/components/Column/S.vue +14 -0
  33. package/app/components/Column/Table/Single.vue +49 -0
  34. package/app/components/Column/Table/index.vue +42 -0
  35. package/app/components/Column/Tags.vue +31 -0
  36. package/app/components/Column/Text.vue +9 -0
  37. package/app/components/Column/Url.vue +9 -0
  38. package/app/components/Column/index.vue +41 -0
  39. package/app/components/Dashboard/Editor.vue +221 -0
  40. package/app/components/Dashboard/Grid.vue +270 -0
  41. package/app/components/Dashboard/View.vue +131 -0
  42. package/app/components/Dashboard/Widget/BarChart.vue +73 -0
  43. package/app/components/Dashboard/Widget/Counter.vue +51 -0
  44. package/app/components/Dashboard/Widget/LineChart.vue +76 -0
  45. package/app/components/Dashboard/Widget/PieChart.vue +75 -0
  46. package/app/components/Dashboard/Widget/Table.vue +94 -0
  47. package/app/components/Dashboard/WidgetEditor.vue +274 -0
  48. package/app/components/Data/Array.vue +102 -0
  49. package/app/components/Data/Html.vue +9 -0
  50. package/app/components/Data/Icon.vue +9 -0
  51. package/app/components/Data/Object.vue +10 -0
  52. package/app/components/Data/S.vue +16 -0
  53. package/app/components/Data/Table.vue +53 -0
  54. package/app/components/Data/Value.vue +34 -0
  55. package/app/components/Data/index.vue +14 -0
  56. package/app/components/Field/Array.vue +324 -0
  57. package/app/components/Field/Asset/Actions.vue +97 -0
  58. package/app/components/Field/Asset/index.vue +639 -0
  59. package/app/components/Field/Boolean.vue +26 -0
  60. package/app/components/Field/Checkbox.vue +48 -0
  61. package/app/components/Field/Color.vue +27 -0
  62. package/app/components/Field/Date.vue +30 -0
  63. package/app/components/Field/Email.vue +51 -0
  64. package/app/components/Field/EmailTemplate.vue +420 -0
  65. package/app/components/Field/Html/ColorPicker.vue +127 -0
  66. package/app/components/Field/Html/Editor.vue +544 -0
  67. package/app/components/Field/Html/index.vue +25 -0
  68. package/app/components/Field/Icon.vue +114 -0
  69. package/app/components/Field/JSON.vue +113 -0
  70. package/app/components/Field/Mention.vue +36 -0
  71. package/app/components/Field/Number.vue +27 -0
  72. package/app/components/Field/Object.vue +92 -0
  73. package/app/components/Field/Password.vue +55 -0
  74. package/app/components/Field/Radio.vue +47 -0
  75. package/app/components/Field/S.vue +44 -0
  76. package/app/components/Field/Select.vue +49 -0
  77. package/app/components/Field/Table.vue +348 -0
  78. package/app/components/Field/Tags.vue +113 -0
  79. package/app/components/Field/Text.vue +31 -0
  80. package/app/components/Field/Textarea.vue +33 -0
  81. package/app/components/Field/Url.vue +40 -0
  82. package/app/components/Field/Wrapper.vue +128 -0
  83. package/app/components/Field/index.vue +68 -0
  84. package/app/components/FloatingChatbot.vue +73 -0
  85. package/app/components/Form/Card.vue +151 -0
  86. package/app/components/Form/Drawer.vue +195 -0
  87. package/app/components/Form/index.vue +621 -0
  88. package/app/components/Header.vue +328 -0
  89. package/app/components/Offline/ConflictModal.vue +200 -0
  90. package/app/components/Offline/SyncStatus.vue +249 -0
  91. package/app/components/PlatformFeatureLanding.vue +65 -0
  92. package/app/components/Table/Backups.vue +638 -0
  93. package/app/components/Table/Flows.vue +814 -0
  94. package/app/components/Table/Grid.vue +296 -0
  95. package/app/components/Table/Icon.vue +36 -0
  96. package/app/components/Table/Logs.vue +181 -0
  97. package/app/components/Table/Schedules.vue +722 -0
  98. package/app/components/Table/Search/Button.vue +256 -0
  99. package/app/components/Table/Search/Items.vue +286 -0
  100. package/app/components/Table/Search/index.vue +87 -0
  101. package/app/components/Table/Settings/Schema.vue +801 -0
  102. package/app/components/Table/Settings/index.vue +631 -0
  103. package/app/components/Table/TranslateDrawer.vue +526 -0
  104. package/app/components/Table/Views/Kanban.vue +289 -0
  105. package/app/components/Table/Views/Table.vue +1273 -0
  106. package/app/components/Table/index.vue +890 -0
  107. package/app/composables/Translation/define.ts +41 -0
  108. package/app/composables/Translation/fetch.ts +107 -0
  109. package/app/composables/Translation/languages.ts +1 -0
  110. package/app/composables/Translation/loadCoreTranslations.ts +38 -0
  111. package/app/composables/Translation/translate.ts +250 -0
  112. package/app/composables/databaseCookies.ts +79 -0
  113. package/app/composables/fieldValidator.ts +72 -0
  114. package/app/composables/fieldsList.ts +301 -0
  115. package/app/composables/formatDatabase.ts +101 -0
  116. package/app/composables/index.ts +444 -0
  117. package/app/composables/openDrawer.ts +118 -0
  118. package/app/composables/optimizeFile.ts +287 -0
  119. package/app/composables/renderLabel.ts +88 -0
  120. package/app/composables/schemaClipboard.ts +95 -0
  121. package/app/composables/search.ts +353 -0
  122. package/app/composables/setThemeConfig.ts +48 -0
  123. package/app/composables/translationValue.ts +169 -0
  124. package/app/composables/useAssetPreview.ts +84 -0
  125. package/app/composables/useAssetUploader.ts +56 -0
  126. package/app/composables/useDashboardData.ts +310 -0
  127. package/app/composables/useDocumentThumbnail.ts +351 -0
  128. package/app/composables/useEcharts.ts +33 -0
  129. package/app/composables/useLocalDatabaseConfig.ts +51 -0
  130. package/app/composables/useOcr.ts +300 -0
  131. package/app/composables/useOfflineFetch.ts +194 -0
  132. package/app/composables/useOfflineItem.ts +107 -0
  133. package/app/composables/useOfflineQueue.ts +302 -0
  134. package/app/composables/useOfflineSync.ts +235 -0
  135. package/app/composables/usePasskeyAuth.ts +156 -0
  136. package/app/composables/usePdfCompressor.ts +180 -0
  137. package/app/composables/usePlatformRedirect.ts +72 -0
  138. package/app/composables/useRealtimeSync.ts +233 -0
  139. package/app/composables/useReferencedItems.ts +180 -0
  140. package/app/composables/useScanner.ts +664 -0
  141. package/app/composables/useSubscription.ts +650 -0
  142. package/app/composables/useThumbnailCache.ts +136 -0
  143. package/app/composables/useVideoCompressor.ts +194 -0
  144. package/app/error.vue +112 -0
  145. package/app/layouts/api.vue +188 -0
  146. package/app/layouts/dashboard.vue +91 -0
  147. package/app/layouts/default.vue +228 -0
  148. package/app/layouts/table.vue +471 -0
  149. package/app/locales/ar.ts +996 -0
  150. package/app/locales/en.ts +655 -0
  151. package/app/locales/es.ts +996 -0
  152. package/app/locales/fr.ts +997 -0
  153. package/app/middleware/dashboard.ts +33 -0
  154. package/app/middleware/database.ts +83 -0
  155. package/app/middleware/global.ts +1 -0
  156. package/app/middleware/sid-ingest.global.ts +29 -0
  157. package/app/middleware/table.ts +54 -0
  158. package/app/middleware/user.ts +26 -0
  159. package/app/pages/[[database]]/admin/api/auth/index.vue +306 -0
  160. package/app/pages/[[database]]/admin/api/index.vue +18 -0
  161. package/app/pages/[[database]]/admin/api/tables/[table]/index.vue +497 -0
  162. package/app/pages/[[database]]/admin/api/tables/index.vue +87 -0
  163. package/app/pages/[[database]]/admin/billing/index.vue +16 -0
  164. package/app/pages/[[database]]/admin/dashboards/[id]/edit.vue +66 -0
  165. package/app/pages/[[database]]/admin/dashboards/[id]/index.vue +117 -0
  166. package/app/pages/[[database]]/admin/dashboards/index.vue +20 -0
  167. package/app/pages/[[database]]/admin/index.vue +28 -0
  168. package/app/pages/[[database]]/admin/settings.vue +526 -0
  169. package/app/pages/[[database]]/admin/tables/[table]/[id]/edit.vue +143 -0
  170. package/app/pages/[[database]]/admin/tables/[table]/[id]/index.vue +146 -0
  171. package/app/pages/[[database]]/admin/tables/[table]/flows.vue +10 -0
  172. package/app/pages/[[database]]/admin/tables/[table]/index.vue +10 -0
  173. package/app/pages/[[database]]/admin/tables/[table]/new.vue +12 -0
  174. package/app/pages/[[database]]/admin/tables/[table]/schedules.vue +10 -0
  175. package/app/pages/[[database]]/admin/tables/[table]/settings.vue +30 -0
  176. package/app/pages/[[database]]/admin/tables/assets/[...path].vue +24 -0
  177. package/app/pages/[[database]]/admin/tables/assets/flows.vue +10 -0
  178. package/app/pages/[[database]]/admin/tables/backups/index.vue +10 -0
  179. package/app/pages/[[database]]/admin/tables/blocks/index.vue +16 -0
  180. package/app/pages/[[database]]/admin/tables/index.vue +20 -0
  181. package/app/pages/[[database]]/admin/tables/pages/index.vue +16 -0
  182. package/app/pages/[[database]]/admin/tables/templates/index.vue +16 -0
  183. package/app/pages/[[database]]/api/index.vue +120 -0
  184. package/app/pages/[[database]]/auth/index.vue +12 -0
  185. package/app/pages/[[database]]/auth/reset.vue +10 -0
  186. package/app/pages/[[database]]/index.vue +10 -0
  187. package/app/plugins/offline-warmup.client.ts +53 -0
  188. package/app/plugins/template-globals.ts +9 -0
  189. package/app/spa-loading-template.html +93 -0
  190. package/biome.json +53 -0
  191. package/index.d.ts +380 -0
  192. package/modules/naiveui.ts +41 -0
  193. package/nuxt.config.ts +269 -0
  194. package/package.json +56 -0
  195. package/pnpm-workspace.yaml +5 -0
  196. package/public/apple-touch-icon.png +0 -0
  197. package/public/favicon-16x16.png +0 -0
  198. package/public/favicon-32x32.png +0 -0
  199. package/public/favicon.ico +0 -0
  200. package/public/pwa-192x192.png +0 -0
  201. package/public/pwa-512x512.png +0 -0
  202. package/public/pwa-maskable-192x192.png +0 -0
  203. package/public/pwa-maskable-512x512.png +0 -0
  204. package/public/vendor/opencv.js +48 -0
  205. package/tsconfig.json +9 -0
@@ -0,0 +1,18 @@
1
+ name: Code quality
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ quality:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Checkout
12
+ uses: actions/checkout@v4
13
+ - name: Setup Biome
14
+ uses: biomejs/setup-biome@v2
15
+ with:
16
+ version: latest
17
+ - name: Run Biome
18
+ run: biome ci .
@@ -0,0 +1,67 @@
1
+ # Contributing to Inicontent CMS
2
+
3
+ Thanks for taking the time to contribute.
4
+
5
+ ## Getting Started
6
+
7
+ 1. Fork [inicontent/inicontent](https://github.com/inicontent/inicontent), then clone your fork:
8
+ ```bash
9
+ cd inicontent
10
+ ```
11
+ 2. Install dependencies (this project uses [pnpm](https://pnpm.io/)):
12
+ ```bash
13
+ pnpm install
14
+ ```
15
+ 3. Start the dev server:
16
+ ```bash
17
+ pnpm run dev
18
+ ```
19
+ The app runs at [http://localhost:3434](http://localhost:3434).
20
+
21
+ ## Project Structure
22
+
23
+ - `app/` - Nuxt application: pages, components, composables, layouts, middleware, plugins, locales.
24
+ - `modules/` - custom Nuxt modules (e.g. `naiveui.ts`).
25
+ - `public/` - static assets.
26
+ - `index.d.ts` - shared type declarations.
27
+
28
+ ## Branching and Commits
29
+
30
+ - Branch off `main` using a short descriptive name, e.g. `fix/pdf-export-crash` or `feat/table-filters`.
31
+ - Keep commits focused; one logical change per commit.
32
+ - Write commit messages in imperative mood ("fix", "add", "refactor"), not past tense.
33
+
34
+ ## Code Style
35
+
36
+ Linting and formatting are enforced with [Biome](https://biomejs.dev/):
37
+
38
+ ```bash
39
+ pnpm lint # check for issues
40
+ pnpm format # check and auto-fix
41
+ ```
42
+
43
+ Run `pnpm lint` before opening a PR; CI runs `biome ci .` on every push and pull request and will fail on violations.
44
+
45
+ Style conventions already encoded in `biome.json`:
46
+ - Tabs for indentation.
47
+ - Double quotes in JavaScript/TypeScript.
48
+ - Imports auto-organized on save/format.
49
+
50
+ ## Pull Requests
51
+
52
+ 1. Ensure `pnpm lint` passes locally.
53
+ 2. Open the PR against `inicontent/inicontent`'s `main` branch.
54
+ 3. Describe **what** changed and **why** in the PR description; link any related issue.
55
+ 4. Keep PRs scoped to a single feature or fix, when possible, to make review easier.
56
+ 5. Be responsive to review feedback; a maintainer will merge once approved and CI is green.
57
+
58
+ ## Reporting Bugs
59
+
60
+ Open an issue against [inicontent/inicontent](https://github.com/inicontent/inicontent/issues) with:
61
+ - Steps to reproduce.
62
+ - Expected vs. actual behavior.
63
+ - Environment details (browser, Node version, OS).
64
+
65
+ ## Questions
66
+
67
+ If something is unclear, open an issue or start a discussion before investing significant time in an implementation, especially for larger changes.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Inicontent
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.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # Inicontent CMS
2
+
3
+ ## Introduction
4
+
5
+ Inicontent CMS is a content management system built using [Nuxt](https://github.com/nuxt/nuxt) as its framework. It leverages modern tools such as:
6
+ - [Naive UI](https://github.com/tusen-ai/naive-ui) for a sleek component library.
7
+ - [Tabler Icons](https://github.com/tabler/tabler-icons) for intuitive and attractive icons.
8
+ - [Tiptap](https://github.com/ueberdosis/tiptap) for a powerful Rich Text Editor.
9
+
10
+ ## Features
11
+
12
+ - **Multi-database admin** - manage one or many databases from a single `/admin` interface.
13
+ - **Rich text editing** via [Tiptap](https://github.com/ueberdosis/tiptap).
14
+ - **Sleek UI** built with [Naive UI](https://github.com/tusen-ai/naive-ui) and [Tabler Icons](https://github.com/tabler/tabler-icons).
15
+ - **PWA-ready** out of the box.
16
+ - **Drop-in as a Nuxt Layer**, or clone and customize directly.
17
+
18
+ ## Ecosystem
19
+
20
+ - **[`inicontent/starter`](https://github.com/inicontent/starter)** — the minimal layer app to
21
+ build on. It ships `CONTEXT.md`, the AI-agent build context: authentication, the REST API,
22
+ the query language, table schemas & flows, and custom-route registration.
23
+ - **`inicontent/api (private)`** — the server behind
24
+ `https://api.inicontent.com/`: REST CRUD per table, authentication, assets, and the built-in
25
+ AI-assistant endpoints (`{db}/ai`, `{db}/ai/tables`, …).
26
+
27
+ ## REST API & authentication (short version)
28
+
29
+ Every database gets a public REST API at `https://api.inicontent.com/{databaseSlug}`:
30
+
31
+ - `PUT {db}/auth/signin` with `{ "username": ..., "password": ... }` → returns a `sessionID`;
32
+ pass it on every request as the `{db}_sid` query param.
33
+ - Table data: `GET/POST/PUT/DELETE {db}/{table}` — list pagination/projection live in the
34
+ Inison-stringified `options` query param and filters in `where`.
35
+ - Structure: `GET/POST/PUT/DELETE inicontent/databases/{db}[/{table}]` for metadata, schemas,
36
+ flows (`onRequest`/`onResponse`), and table CRUD.
37
+ - AI assistant: `POST {db}/ai` (router), then `POST/PUT {db}/ai/tables`, `{db}/ai/data`,
38
+ `{db}/ai/pages` … to design schemas, roles and demo data.
39
+
40
+ See the `CONTEXT.md` shipped with `inicontent/starter` for the full reference (query language,
41
+ schema field types, flows, routing).
42
+
43
+ ## Usage
44
+
45
+ There are two ways to use this project:
46
+
47
+ ### 1. Recommended Method: Add as a Nuxt Layer
48
+
49
+ The easiest way to integrate Inicontent CMS is to use it as a Nuxt Layer.
50
+
51
+ **Steps:**
52
+ 1. Add the repository as a layer in your `nuxt.config` file.
53
+ 2. Remove your existing `app.vue` file to avoid conflicts.
54
+ 3. To override specific admin routes, create corresponding files in the `pages` directory. These will automatically override the default routes provided by the CMS.
55
+
56
+ **Database Configuration:**
57
+ - By default, the CMS is a multi-database manager.
58
+ - When no `database` is set in `.env`, the admin interface (`/admin`) will display all available databases. Users can then navigate to a specific database's admin panel at `/admin/<dbName>`.
59
+ - If a `database` is specified in `.env`, the `/admin` route will directly display the tables for the specified database, removing the need to include the database name in the path.
60
+
61
+ **Example Configuration:**
62
+
63
+ ```javascript
64
+ // nuxt.config.ts
65
+ export default defineNuxtConfig({
66
+ extends: [["github:inicontent/inicontent", { install: true }]]
67
+ });
68
+ ```
69
+
70
+ ```sh
71
+ # .env
72
+ database=DATABASE_SLUG
73
+ ```
74
+
75
+ **Database configuration:**
76
+ - The CMS is a multi-database manager by default.
77
+ - When no `database` is set in `.env`, `/admin` lists all available databases; users navigate to a specific database's admin panel at `/admin/<dbName>`.
78
+ - When `database` is set, `/admin` shows that database's tables directly, without the name in the path.
79
+
80
+ This method keeps your project clean and makes updates to the CMS easy.
81
+
82
+ ### 2. Advanced Method: Clone and Edit the Repository
83
+
84
+ If you need extensive customization, clone the repository and modify it directly.
85
+ ```bash
86
+ git clone https://github.com/inicontent/inicontent.git
87
+ cd inicontent
88
+ pnpm install
89
+ ```
90
+
91
+ ## Environment Variables
92
+
93
+ | Variable | Required | Default | Description |
94
+ |------------|----------|--------------------------------|------------------------------------------------|
95
+ | `database` | No | `inicontent` | Database slug the admin panel targets directly. |
96
+ | `apiBase` | No | `https://api.inicontent.com/` | Base URL for the Inicontent API. |
97
+ | `idOne` | No | (built-in default) | Public identifier used by the API client. |
98
+
99
+ Copy these into a local `.env` file as needed; none are required to start the dev server.
100
+
101
+ ## Setup
102
+
103
+ Install the dependencies to get started (any package manager works — npm, pnpm, yarn, or bun):
104
+
105
+ ```bash
106
+ npm install
107
+ ```
108
+
109
+ ## Development
110
+
111
+ Start the development server at [http://localhost:3434](http://localhost:3434):
112
+
113
+ ```bash
114
+ npm run dev
115
+ ```
116
+
117
+ ## Production
118
+
119
+ Build the application for production:
120
+
121
+ ```bash
122
+ npm run build
123
+ ```
124
+
125
+ Preview the production build locally:
126
+
127
+ ```bash
128
+ npm run preview
129
+ ```
130
+
131
+ ## Linting
132
+
133
+ This project uses [Biome](https://biomejs.dev/) for linting and formatting:
134
+
135
+ ```bash
136
+ pnpm lint # check
137
+ pnpm format # check and write
138
+ ```
139
+
140
+ ## Contributing
141
+
142
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, branch/commit conventions, and the PR process.
package/app/app.vue ADDED
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <NuxtPwaManifest />
3
+ <NuxtLayout>
4
+ <NuxtPage />
5
+ </NuxtLayout>
6
+ </template>
7
+
8
+ <script lang="ts" setup>
9
+ import { useOsTheme } from "naive-ui";
10
+ import { debounce, loadCoreTranslations } from "./composables";
11
+ import { saveDatabaseConfigLocally } from "./composables/useLocalDatabaseConfig";
12
+
13
+ const database = useState<Database>("database");
14
+ const Language = useScopedCookie<LanguagesType>(
15
+ "language",
16
+ database.value?.slug,
17
+ );
18
+
19
+ // Load core translations with the initial language
20
+ loadCoreTranslations(Language.value);
21
+
22
+ // Watch for language changes and load translations dynamically
23
+ watch(Language, async (newLang, oldLang) => {
24
+ if (newLang) await loadCoreTranslations(newLang, oldLang);
25
+ });
26
+
27
+ const Theme = useCookie<"light" | "dark">("theme", { sameSite: true });
28
+ const sessionID = useScopedCookie<string>("sid", database.value?.slug);
29
+ const osThemeRef = useOsTheme();
30
+ const isManual = ref(false);
31
+ if (!Theme.value) {
32
+ Theme.value = osThemeRef.value ?? "light";
33
+ } else {
34
+ isManual.value = true;
35
+ }
36
+
37
+ watch(Theme, () => {
38
+ setThemeConfig();
39
+ if (Theme.value !== osThemeRef.value) {
40
+ isManual.value = true;
41
+ }
42
+ });
43
+
44
+ watch(osThemeRef, (newOsTheme) => {
45
+ if (!isManual.value && newOsTheme) {
46
+ Theme.value = newOsTheme;
47
+ }
48
+ });
49
+
50
+ watch(
51
+ () => database.value?.slug,
52
+ (slug) => {
53
+ syncCookiesFromDatabase(slug);
54
+ },
55
+ { immediate: true },
56
+ );
57
+
58
+ watch(
59
+ [Language, Theme, sessionID, () => database.value?.slug],
60
+ () => {
61
+ syncCookiesToDatabase(database.value?.slug);
62
+ },
63
+ { immediate: true },
64
+ );
65
+
66
+ // Persist the database config locally so the app stays reachable offline from
67
+ // local storage even when the service worker cache is missing. The middleware
68
+ // saves the initial fetch; this debounced deep watcher also catches config
69
+ // updates made later (e.g. schema changes from the Settings page).
70
+ const persistDatabaseConfigDebounced = debounce(() => {
71
+ const db = database.value;
72
+ if (db?.slug) saveDatabaseConfigLocally(db.slug, db);
73
+ }, 2000);
74
+ watch(
75
+ () => database.value,
76
+ () => {
77
+ persistDatabaseConfigDebounced();
78
+ },
79
+ { deep: true },
80
+ );
81
+
82
+ // Initialize the offline queue tracker on boot so pending counts start
83
+ // loading even before the Header (which hosts the SyncStatus badge) mounts.
84
+ // Deferred to an idle callback so opening IndexedDB can never compete with
85
+ // the first page's route-middleware fetch or initial render.
86
+ onMounted(() => {
87
+ const runInit = () => useOfflineSync().initSync();
88
+ if ("requestIdleCallback" in window) {
89
+ // @ts-expect-error requestIdleCallback types not present
90
+ window.requestIdleCallback(runInit, { timeout: 3000 });
91
+ } else {
92
+ setTimeout(runInit, 500);
93
+ }
94
+ });
95
+
96
+ useHead({
97
+ bodyAttrs: {
98
+ class: computed(() =>
99
+ [
100
+ Language.value === "ar" ? "rtl" : "ltr",
101
+ Theme.value === "dark" ? "dark" : "light",
102
+ ].join(" "),
103
+ ),
104
+ },
105
+ });
106
+ </script>