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.
- package/.github/pull_request.yml +18 -0
- package/CONTRIBUTING.md +67 -0
- package/LICENSE +21 -0
- package/README.md +142 -0
- package/app/app.vue +106 -0
- package/app/assets/main.css +974 -0
- package/app/components/Api/EndpointCard.vue +169 -0
- package/app/components/Api/SchemaDocsTable.vue +208 -0
- package/app/components/Asset/Card.vue +1363 -0
- package/app/components/Asset/Grid.vue +295 -0
- package/app/components/Asset/Icon.vue +38 -0
- package/app/components/Asset/Preview.vue +486 -0
- package/app/components/Asset/Scanner.vue +700 -0
- package/app/components/Asset/Thumb.vue +708 -0
- package/app/components/Auth/Reset.vue +99 -0
- package/app/components/Auth/index.vue +346 -0
- package/app/components/ChatInterface.vue +2326 -0
- package/app/components/ChatPagePreview.vue +34 -0
- package/app/components/Column/Array.vue +29 -0
- package/app/components/Column/Asset.vue +21 -0
- package/app/components/Column/Boolean.vue +12 -0
- package/app/components/Column/Color.vue +9 -0
- package/app/components/Column/Date.vue +57 -0
- package/app/components/Column/Edit.vue +215 -0
- package/app/components/Column/Email.vue +9 -0
- package/app/components/Column/Html.vue +27 -0
- package/app/components/Column/Id.vue +20 -0
- package/app/components/Column/Locale.vue +32 -0
- package/app/components/Column/Object.vue +18 -0
- package/app/components/Column/Password.vue +7 -0
- package/app/components/Column/Role.vue +15 -0
- package/app/components/Column/S.vue +14 -0
- package/app/components/Column/Table/Single.vue +49 -0
- package/app/components/Column/Table/index.vue +42 -0
- package/app/components/Column/Tags.vue +31 -0
- package/app/components/Column/Text.vue +9 -0
- package/app/components/Column/Url.vue +9 -0
- package/app/components/Column/index.vue +41 -0
- package/app/components/Dashboard/Editor.vue +221 -0
- package/app/components/Dashboard/Grid.vue +270 -0
- package/app/components/Dashboard/View.vue +131 -0
- package/app/components/Dashboard/Widget/BarChart.vue +73 -0
- package/app/components/Dashboard/Widget/Counter.vue +51 -0
- package/app/components/Dashboard/Widget/LineChart.vue +76 -0
- package/app/components/Dashboard/Widget/PieChart.vue +75 -0
- package/app/components/Dashboard/Widget/Table.vue +94 -0
- package/app/components/Dashboard/WidgetEditor.vue +274 -0
- package/app/components/Data/Array.vue +102 -0
- package/app/components/Data/Html.vue +9 -0
- package/app/components/Data/Icon.vue +9 -0
- package/app/components/Data/Object.vue +10 -0
- package/app/components/Data/S.vue +16 -0
- package/app/components/Data/Table.vue +53 -0
- package/app/components/Data/Value.vue +34 -0
- package/app/components/Data/index.vue +14 -0
- package/app/components/Field/Array.vue +324 -0
- package/app/components/Field/Asset/Actions.vue +97 -0
- package/app/components/Field/Asset/index.vue +639 -0
- package/app/components/Field/Boolean.vue +26 -0
- package/app/components/Field/Checkbox.vue +48 -0
- package/app/components/Field/Color.vue +27 -0
- package/app/components/Field/Date.vue +30 -0
- package/app/components/Field/Email.vue +51 -0
- package/app/components/Field/EmailTemplate.vue +420 -0
- package/app/components/Field/Html/ColorPicker.vue +127 -0
- package/app/components/Field/Html/Editor.vue +544 -0
- package/app/components/Field/Html/index.vue +25 -0
- package/app/components/Field/Icon.vue +114 -0
- package/app/components/Field/JSON.vue +113 -0
- package/app/components/Field/Mention.vue +36 -0
- package/app/components/Field/Number.vue +27 -0
- package/app/components/Field/Object.vue +92 -0
- package/app/components/Field/Password.vue +55 -0
- package/app/components/Field/Radio.vue +47 -0
- package/app/components/Field/S.vue +44 -0
- package/app/components/Field/Select.vue +49 -0
- package/app/components/Field/Table.vue +348 -0
- package/app/components/Field/Tags.vue +113 -0
- package/app/components/Field/Text.vue +31 -0
- package/app/components/Field/Textarea.vue +33 -0
- package/app/components/Field/Url.vue +40 -0
- package/app/components/Field/Wrapper.vue +128 -0
- package/app/components/Field/index.vue +68 -0
- package/app/components/FloatingChatbot.vue +73 -0
- package/app/components/Form/Card.vue +151 -0
- package/app/components/Form/Drawer.vue +195 -0
- package/app/components/Form/index.vue +621 -0
- package/app/components/Header.vue +328 -0
- package/app/components/Offline/ConflictModal.vue +200 -0
- package/app/components/Offline/SyncStatus.vue +249 -0
- package/app/components/PlatformFeatureLanding.vue +65 -0
- package/app/components/Table/Backups.vue +638 -0
- package/app/components/Table/Flows.vue +814 -0
- package/app/components/Table/Grid.vue +296 -0
- package/app/components/Table/Icon.vue +36 -0
- package/app/components/Table/Logs.vue +181 -0
- package/app/components/Table/Schedules.vue +722 -0
- package/app/components/Table/Search/Button.vue +256 -0
- package/app/components/Table/Search/Items.vue +286 -0
- package/app/components/Table/Search/index.vue +87 -0
- package/app/components/Table/Settings/Schema.vue +801 -0
- package/app/components/Table/Settings/index.vue +631 -0
- package/app/components/Table/TranslateDrawer.vue +526 -0
- package/app/components/Table/Views/Kanban.vue +289 -0
- package/app/components/Table/Views/Table.vue +1273 -0
- package/app/components/Table/index.vue +890 -0
- package/app/composables/Translation/define.ts +41 -0
- package/app/composables/Translation/fetch.ts +107 -0
- package/app/composables/Translation/languages.ts +1 -0
- package/app/composables/Translation/loadCoreTranslations.ts +38 -0
- package/app/composables/Translation/translate.ts +250 -0
- package/app/composables/databaseCookies.ts +79 -0
- package/app/composables/fieldValidator.ts +72 -0
- package/app/composables/fieldsList.ts +301 -0
- package/app/composables/formatDatabase.ts +101 -0
- package/app/composables/index.ts +444 -0
- package/app/composables/openDrawer.ts +118 -0
- package/app/composables/optimizeFile.ts +287 -0
- package/app/composables/renderLabel.ts +88 -0
- package/app/composables/schemaClipboard.ts +95 -0
- package/app/composables/search.ts +353 -0
- package/app/composables/setThemeConfig.ts +48 -0
- package/app/composables/translationValue.ts +169 -0
- package/app/composables/useAssetPreview.ts +84 -0
- package/app/composables/useAssetUploader.ts +56 -0
- package/app/composables/useDashboardData.ts +310 -0
- package/app/composables/useDocumentThumbnail.ts +351 -0
- package/app/composables/useEcharts.ts +33 -0
- package/app/composables/useLocalDatabaseConfig.ts +51 -0
- package/app/composables/useOcr.ts +300 -0
- package/app/composables/useOfflineFetch.ts +194 -0
- package/app/composables/useOfflineItem.ts +107 -0
- package/app/composables/useOfflineQueue.ts +302 -0
- package/app/composables/useOfflineSync.ts +235 -0
- package/app/composables/usePasskeyAuth.ts +156 -0
- package/app/composables/usePdfCompressor.ts +180 -0
- package/app/composables/usePlatformRedirect.ts +72 -0
- package/app/composables/useRealtimeSync.ts +233 -0
- package/app/composables/useReferencedItems.ts +180 -0
- package/app/composables/useScanner.ts +664 -0
- package/app/composables/useSubscription.ts +650 -0
- package/app/composables/useThumbnailCache.ts +136 -0
- package/app/composables/useVideoCompressor.ts +194 -0
- package/app/error.vue +112 -0
- package/app/layouts/api.vue +188 -0
- package/app/layouts/dashboard.vue +91 -0
- package/app/layouts/default.vue +228 -0
- package/app/layouts/table.vue +471 -0
- package/app/locales/ar.ts +996 -0
- package/app/locales/en.ts +655 -0
- package/app/locales/es.ts +996 -0
- package/app/locales/fr.ts +997 -0
- package/app/middleware/dashboard.ts +33 -0
- package/app/middleware/database.ts +83 -0
- package/app/middleware/global.ts +1 -0
- package/app/middleware/sid-ingest.global.ts +29 -0
- package/app/middleware/table.ts +54 -0
- package/app/middleware/user.ts +26 -0
- package/app/pages/[[database]]/admin/api/auth/index.vue +306 -0
- package/app/pages/[[database]]/admin/api/index.vue +18 -0
- package/app/pages/[[database]]/admin/api/tables/[table]/index.vue +497 -0
- package/app/pages/[[database]]/admin/api/tables/index.vue +87 -0
- package/app/pages/[[database]]/admin/billing/index.vue +16 -0
- package/app/pages/[[database]]/admin/dashboards/[id]/edit.vue +66 -0
- package/app/pages/[[database]]/admin/dashboards/[id]/index.vue +117 -0
- package/app/pages/[[database]]/admin/dashboards/index.vue +20 -0
- package/app/pages/[[database]]/admin/index.vue +28 -0
- package/app/pages/[[database]]/admin/settings.vue +526 -0
- package/app/pages/[[database]]/admin/tables/[table]/[id]/edit.vue +143 -0
- package/app/pages/[[database]]/admin/tables/[table]/[id]/index.vue +146 -0
- package/app/pages/[[database]]/admin/tables/[table]/flows.vue +10 -0
- package/app/pages/[[database]]/admin/tables/[table]/index.vue +10 -0
- package/app/pages/[[database]]/admin/tables/[table]/new.vue +12 -0
- package/app/pages/[[database]]/admin/tables/[table]/schedules.vue +10 -0
- package/app/pages/[[database]]/admin/tables/[table]/settings.vue +30 -0
- package/app/pages/[[database]]/admin/tables/assets/[...path].vue +24 -0
- package/app/pages/[[database]]/admin/tables/assets/flows.vue +10 -0
- package/app/pages/[[database]]/admin/tables/backups/index.vue +10 -0
- package/app/pages/[[database]]/admin/tables/blocks/index.vue +16 -0
- package/app/pages/[[database]]/admin/tables/index.vue +20 -0
- package/app/pages/[[database]]/admin/tables/pages/index.vue +16 -0
- package/app/pages/[[database]]/admin/tables/templates/index.vue +16 -0
- package/app/pages/[[database]]/api/index.vue +120 -0
- package/app/pages/[[database]]/auth/index.vue +12 -0
- package/app/pages/[[database]]/auth/reset.vue +10 -0
- package/app/pages/[[database]]/index.vue +10 -0
- package/app/plugins/offline-warmup.client.ts +53 -0
- package/app/plugins/template-globals.ts +9 -0
- package/app/spa-loading-template.html +93 -0
- package/biome.json +53 -0
- package/index.d.ts +380 -0
- package/modules/naiveui.ts +41 -0
- package/nuxt.config.ts +269 -0
- package/package.json +56 -0
- package/pnpm-workspace.yaml +5 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/pwa-192x192.png +0 -0
- package/public/pwa-512x512.png +0 -0
- package/public/pwa-maskable-192x192.png +0 -0
- package/public/pwa-maskable-512x512.png +0 -0
- package/public/vendor/opencv.js +48 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<NuxtLayout name="default">
|
|
3
|
+
<NLayout position="absolute">
|
|
4
|
+
<NScrollbar id="iniHeader" style="max-height: 65px" xScrollable trigger="none">
|
|
5
|
+
<NLayoutHeader style="height: 64px; padding: 15px 24px" bordered>
|
|
6
|
+
<LazyHeader />
|
|
7
|
+
</NLayoutHeader>
|
|
8
|
+
</NScrollbar>
|
|
9
|
+
<NLayoutContent id="container" position="absolute"
|
|
10
|
+
content-style="padding: 24px;height: fit-content"
|
|
11
|
+
:native-scrollbar="false">
|
|
12
|
+
<slot></slot>
|
|
13
|
+
</NLayoutContent>
|
|
14
|
+
</NLayout>
|
|
15
|
+
|
|
16
|
+
<NModal v-model:show="showAuthModal" :mask-closable="false" :close-on-esc="false">
|
|
17
|
+
<Auth v-if="showAuthModal" :onLoggedIn />
|
|
18
|
+
</NModal>
|
|
19
|
+
|
|
20
|
+
<!-- Global conflict resolution modal: auto-opens when an offline edit
|
|
21
|
+
collides with the server during sync; also reachable from the
|
|
22
|
+
SyncStatus popover in the header. -->
|
|
23
|
+
<OfflineConflictModal />
|
|
24
|
+
|
|
25
|
+
<LazyAssetPreview />
|
|
26
|
+
|
|
27
|
+
<LazyFloatingChatbot v-if="route.path.includes('/admin')" />
|
|
28
|
+
</NuxtLayout>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
// onBeforeUpdate(() => {
|
|
33
|
+
// clearNuxtState("translations");
|
|
34
|
+
// })
|
|
35
|
+
|
|
36
|
+
const config = useRuntimeConfig();
|
|
37
|
+
const route = useRoute();
|
|
38
|
+
const database = useState<Database>("database");
|
|
39
|
+
|
|
40
|
+
const sessionID = useScopedCookie<string>("sid", database.value?.slug);
|
|
41
|
+
|
|
42
|
+
const showAuthModal = ref(false);
|
|
43
|
+
const authCheckFailCount = ref(0);
|
|
44
|
+
const AUTH_CHECK_MAX_FAILS = 3;
|
|
45
|
+
|
|
46
|
+
async function checkAuth() {
|
|
47
|
+
if (showAuthModal.value || String(route.name).includes("auth")) return;
|
|
48
|
+
|
|
49
|
+
if (!sessionID.value) {
|
|
50
|
+
showAuthModal.value = true;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const data = await $fetch<{ result: boolean }>(
|
|
56
|
+
`${config.public.apiBase}${database.value.slug}/auth/current`,
|
|
57
|
+
{
|
|
58
|
+
credentials: "include",
|
|
59
|
+
query: {
|
|
60
|
+
isSignedIn: true,
|
|
61
|
+
[`${database.value.slug}_sid`]: sessionID.value,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
authCheckFailCount.value = 0;
|
|
66
|
+
if (!data.result) {
|
|
67
|
+
showAuthModal.value = true;
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
// Do not force logout on a single transient network/server error.
|
|
71
|
+
authCheckFailCount.value += 1;
|
|
72
|
+
if (authCheckFailCount.value >= AUTH_CHECK_MAX_FAILS) {
|
|
73
|
+
showAuthModal.value = true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function onLoggedIn() {
|
|
79
|
+
showAuthModal.value = false;
|
|
80
|
+
authCheckFailCount.value = 0;
|
|
81
|
+
// User and sessionID are already updated in Auth component
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onMounted(async () => {
|
|
85
|
+
checkAuth();
|
|
86
|
+
if (!String(route.name).endsWith("auth")) {
|
|
87
|
+
const interval = setInterval(checkAuth, 60000); // Check every 1 minute
|
|
88
|
+
onUnmounted(() => clearInterval(interval));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
</script>
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<NConfigProvider v-bind="configProviderProps">
|
|
3
|
+
<NuxtLoadingIndicator :color="ThemeConfig.primaryColor" :height=2 />
|
|
4
|
+
<slot></slot>
|
|
5
|
+
</NConfigProvider>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
import {
|
|
10
|
+
type ConfigProviderProps,
|
|
11
|
+
arDZ,
|
|
12
|
+
createDiscreteApi,
|
|
13
|
+
darkTheme,
|
|
14
|
+
dateArDZ,
|
|
15
|
+
dateEnUS,
|
|
16
|
+
enUS,
|
|
17
|
+
} from "naive-ui"
|
|
18
|
+
|
|
19
|
+
import "~/assets/main.css"
|
|
20
|
+
|
|
21
|
+
import { hexToRGB } from "~/composables"
|
|
22
|
+
|
|
23
|
+
const database = useState<Database>("database");
|
|
24
|
+
const Language = useScopedCookie<LanguagesType>("language", database.value?.slug)
|
|
25
|
+
const Theme = useCookie<"light" | "dark">("theme", { sameSite: true })
|
|
26
|
+
const ThemeConfig = useState<ThemeConfig>("ThemeConfig")
|
|
27
|
+
|
|
28
|
+
// The unstable*Rtl styles are only meaningful for Arabic/rtl layouts. They used
|
|
29
|
+
// to be eagerly imported on every boot, pulling ~24 naive-ui style modules into
|
|
30
|
+
// the shared entry chunk that English/global sites never use. They are now
|
|
31
|
+
// loaded on demand (a single chunk, only when the language is "ar").
|
|
32
|
+
const rtlStyles = ref<any[]>([])
|
|
33
|
+
|
|
34
|
+
async function ensureRtlStyles() {
|
|
35
|
+
if (rtlStyles.value.length) return rtlStyles.value
|
|
36
|
+
const {
|
|
37
|
+
unstableListRtl,
|
|
38
|
+
unstablePageHeaderRtl,
|
|
39
|
+
unstableButtonGroupRtl,
|
|
40
|
+
unstableButtonRtl,
|
|
41
|
+
unstableCardRtl,
|
|
42
|
+
unstableScrollbarRtl,
|
|
43
|
+
unstableMessageRtl,
|
|
44
|
+
unstableCollapseRtl,
|
|
45
|
+
unstableDrawerRtl,
|
|
46
|
+
unstableInputNumberRtl,
|
|
47
|
+
unstableCheckboxRtl,
|
|
48
|
+
unstableRadioRtl,
|
|
49
|
+
unstableTagRtl,
|
|
50
|
+
unstableTableRtl,
|
|
51
|
+
unstableInputRtl,
|
|
52
|
+
unstableAvatarGroupRtl,
|
|
53
|
+
unstableFlexRtl,
|
|
54
|
+
unstableSelectRtl,
|
|
55
|
+
unstableDataTableRtl,
|
|
56
|
+
unstableDialogRtl,
|
|
57
|
+
unstablePaginationRtl,
|
|
58
|
+
unstableNotificationRtl,
|
|
59
|
+
unstableStepsRtl,
|
|
60
|
+
unstableAlertRtl,
|
|
61
|
+
} = await import("naive-ui")
|
|
62
|
+
rtlStyles.value = [
|
|
63
|
+
unstableListRtl,
|
|
64
|
+
unstablePageHeaderRtl,
|
|
65
|
+
unstableButtonGroupRtl,
|
|
66
|
+
unstableButtonRtl,
|
|
67
|
+
unstableCardRtl,
|
|
68
|
+
unstableScrollbarRtl,
|
|
69
|
+
unstableMessageRtl,
|
|
70
|
+
unstableCollapseRtl,
|
|
71
|
+
unstableDrawerRtl,
|
|
72
|
+
unstableInputNumberRtl,
|
|
73
|
+
unstableCheckboxRtl,
|
|
74
|
+
unstableRadioRtl,
|
|
75
|
+
unstableTagRtl,
|
|
76
|
+
unstableTableRtl,
|
|
77
|
+
unstableInputRtl,
|
|
78
|
+
unstableAvatarGroupRtl,
|
|
79
|
+
unstableFlexRtl,
|
|
80
|
+
unstableSelectRtl,
|
|
81
|
+
unstableDataTableRtl,
|
|
82
|
+
unstableDialogRtl,
|
|
83
|
+
unstablePaginationRtl,
|
|
84
|
+
unstableNotificationRtl,
|
|
85
|
+
unstableStepsRtl,
|
|
86
|
+
unstableAlertRtl,
|
|
87
|
+
]
|
|
88
|
+
return rtlStyles.value
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
watch(
|
|
92
|
+
computed(() => Language.value === "ar"),
|
|
93
|
+
async (isArabic) => {
|
|
94
|
+
if (isArabic) void ensureRtlStyles()
|
|
95
|
+
},
|
|
96
|
+
{ immediate: true },
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const Locales = {
|
|
100
|
+
ar: arDZ,
|
|
101
|
+
en: enUS,
|
|
102
|
+
}
|
|
103
|
+
const dateLocales = {
|
|
104
|
+
ar: dateArDZ,
|
|
105
|
+
en: dateEnUS,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const configProviderProps = computed<ConfigProviderProps>(() => ({
|
|
109
|
+
dir: Language.value === "ar" ? "rtl" : "ltr",
|
|
110
|
+
rtl:
|
|
111
|
+
Language.value === "ar" && rtlStyles.value.length
|
|
112
|
+
? rtlStyles.value
|
|
113
|
+
: undefined,
|
|
114
|
+
theme: Theme.value === "dark" ? darkTheme : undefined,
|
|
115
|
+
themeOverrides: {
|
|
116
|
+
common: {
|
|
117
|
+
...ThemeConfig.value,
|
|
118
|
+
fontFamily: "Cairo",
|
|
119
|
+
fontFamilyMono: "Cairo",
|
|
120
|
+
borderRadius: "15px"
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
locale: Locales[Language.value as "ar" | "en"] ?? Locales.en,
|
|
124
|
+
dateLocale: dateLocales[Language.value as "ar" | "en"] ?? dateLocales.en,
|
|
125
|
+
}))
|
|
126
|
+
const { message, notification } = createDiscreteApi(
|
|
127
|
+
["message", "notification"],
|
|
128
|
+
{
|
|
129
|
+
messageProviderProps: {
|
|
130
|
+
keepAliveOnHover: true,
|
|
131
|
+
closable: true,
|
|
132
|
+
containerStyle: {
|
|
133
|
+
top: "70px",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
configProviderProps,
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
onMounted(() => {
|
|
141
|
+
window.$message = message
|
|
142
|
+
window.$notification = notification
|
|
143
|
+
|
|
144
|
+
// Add an event listener for the print action
|
|
145
|
+
window.onbeforeprint = () => {
|
|
146
|
+
// Select the element with the class "printable"
|
|
147
|
+
let element = document.querySelector(".printable")
|
|
148
|
+
|
|
149
|
+
// Check if the element and its parent exist
|
|
150
|
+
if (element?.parentElement) {
|
|
151
|
+
// Add the class "printable-direct-parent" to the direct parent
|
|
152
|
+
element.parentElement.classList.add("printable-direct-parent")
|
|
153
|
+
|
|
154
|
+
// Traverse up the DOM starting from the direct parent's parent
|
|
155
|
+
let parent = element.parentElement.parentElement
|
|
156
|
+
while (parent) {
|
|
157
|
+
// Add the class "printable-parent" to all other ancestors
|
|
158
|
+
parent.classList.add("printable-parent")
|
|
159
|
+
parent = parent.parentElement
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Optional: Remove the added classes after printing
|
|
165
|
+
window.onafterprint = () => {
|
|
166
|
+
// Remove the "printable-parent" class after printing
|
|
167
|
+
const elements = document.querySelectorAll(".printable-parent")
|
|
168
|
+
for (let i = 0; i < elements.length; i++)
|
|
169
|
+
elements[i]?.classList.remove("printable-parent")
|
|
170
|
+
|
|
171
|
+
document
|
|
172
|
+
.querySelector(".printable-direct-parent")
|
|
173
|
+
?.classList.remove("printable-parent")
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
fetchTranslation()
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
watch(Language, () => fetchTranslation())
|
|
180
|
+
|
|
181
|
+
// Naive UI default body colors for each mode.
|
|
182
|
+
const bodyBgColor = computed(() =>
|
|
183
|
+
Theme.value === "dark" ? "rgb(16, 16, 20)" : "#fff",
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
useHead({
|
|
187
|
+
meta: [
|
|
188
|
+
{
|
|
189
|
+
name: "theme-color",
|
|
190
|
+
content: bodyBgColor,
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
htmlAttrs: {
|
|
194
|
+
// Let the browser render its own chrome (scrollbars, form controls,
|
|
195
|
+
// native widgets) in the matching color scheme so it follows the
|
|
196
|
+
// database primary color on desktop, mobile, android, mac & windows.
|
|
197
|
+
style: computed(
|
|
198
|
+
() =>
|
|
199
|
+
`color-scheme: ${Theme.value === "dark" ? "dark" : "light"}; ` +
|
|
200
|
+
`background-color: ${bodyBgColor.value}`,
|
|
201
|
+
),
|
|
202
|
+
},
|
|
203
|
+
bodyAttrs: {
|
|
204
|
+
style: computed(
|
|
205
|
+
() =>
|
|
206
|
+
`--primaryColor: ${hexToRGB(ThemeConfig.value.primaryColor).join(", ")}`,
|
|
207
|
+
),
|
|
208
|
+
},
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
// Safari Mobile ignores dynamic attribute changes on <meta name="theme-color">.
|
|
212
|
+
// Force it to re-read by removing and re-adding the element whenever the mode
|
|
213
|
+
// changes. The matching background-color on <html> gives Safari a reliable
|
|
214
|
+
// signal for the status-bar / safe-area-inset color.
|
|
215
|
+
onMounted(() => {
|
|
216
|
+
watch(bodyBgColor, (color) => {
|
|
217
|
+
const existing = document.querySelector('meta[name="theme-color"]')
|
|
218
|
+
if (existing) existing.remove()
|
|
219
|
+
const meta = document.createElement("meta")
|
|
220
|
+
meta.name = "theme-color"
|
|
221
|
+
meta.content = color
|
|
222
|
+
document.head.appendChild(meta)
|
|
223
|
+
|
|
224
|
+
document.documentElement.style.backgroundColor = color
|
|
225
|
+
}, { immediate: true })
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
</script>
|