@esershnr/artalk-sidebar 1.0.3
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/README.md +16 -0
- package/auto-imports.d.ts +76 -0
- package/components.d.ts +31 -0
- package/env.d.ts +2 -0
- package/index.html +15 -0
- package/package.json +32 -0
- package/public/favicon.png +0 -0
- package/public/robots.txt +2 -0
- package/src/App.vue +89 -0
- package/src/artalk.ts +82 -0
- package/src/assets/favicon.png +0 -0
- package/src/assets/icon-darkmode-off.svg +1 -0
- package/src/assets/icon-darkmode-on.svg +1 -0
- package/src/assets/icon-eye-off.svg +1 -0
- package/src/assets/icon-eye-on.svg +1 -0
- package/src/assets/nav-icon-comments.svg +1 -0
- package/src/assets/nav-icon-pages.svg +1 -0
- package/src/assets/nav-icon-search.svg +1 -0
- package/src/assets/nav-icon-settings.svg +1 -0
- package/src/assets/nav-icon-sites.svg +1 -0
- package/src/assets/nav-icon-transfer.svg +1 -0
- package/src/assets/nav-icon-users.svg +1 -0
- package/src/components/AppHeader.vue +235 -0
- package/src/components/AppNavigation.vue +11 -0
- package/src/components/AppNavigationDesktop.vue +176 -0
- package/src/components/AppNavigationMenu.ts +152 -0
- package/src/components/AppNavigationMobile.vue +187 -0
- package/src/components/AppNavigationSearch.vue +137 -0
- package/src/components/FileUploader.vue +149 -0
- package/src/components/ItemTextEditor.vue +130 -0
- package/src/components/LoadingLayer.vue +37 -0
- package/src/components/LogTerminal.vue +89 -0
- package/src/components/PageEditor.vue +171 -0
- package/src/components/Pagination.vue +253 -0
- package/src/components/PreferenceArr.vue +105 -0
- package/src/components/PreferenceGrp.vue +153 -0
- package/src/components/PreferenceItem.vue +159 -0
- package/src/components/SiteCreate.vue +96 -0
- package/src/components/SiteEditor.vue +138 -0
- package/src/components/SiteSwitcher.vue +184 -0
- package/src/components/UserEditor.vue +229 -0
- package/src/global.ts +62 -0
- package/src/hooks/MobileWidth.ts +27 -0
- package/src/i18n/fr.ts +103 -0
- package/src/i18n/ja.ts +100 -0
- package/src/i18n/ko.ts +99 -0
- package/src/i18n/ru.ts +102 -0
- package/src/i18n/tr.ts +102 -0
- package/src/i18n/zh-CN.ts +97 -0
- package/src/i18n/zh-TW.ts +97 -0
- package/src/i18n-en.ts +99 -0
- package/src/i18n.ts +37 -0
- package/src/lib/promise-polyfill.ts +9 -0
- package/src/lib/settings-option.ts +186 -0
- package/src/lib/settings-sensitive.ts +44 -0
- package/src/lib/settings.ts +94 -0
- package/src/main.ts +65 -0
- package/src/pages/comments.vue +110 -0
- package/src/pages/index.vue +33 -0
- package/src/pages/login.vue +245 -0
- package/src/pages/pages.vue +309 -0
- package/src/pages/settings.vue +181 -0
- package/src/pages/sites.vue +353 -0
- package/src/pages/transfer.vue +204 -0
- package/src/pages/users.vue +271 -0
- package/src/stores/nav.ts +114 -0
- package/src/stores/user.ts +48 -0
- package/src/style/_extends.scss +100 -0
- package/src/style/_variables.scss +18 -0
- package/src/style.scss +245 -0
- package/src/vue-i18n.d.ts +7 -0
- package/tsconfig.json +40 -0
- package/tsconfig.node.json +11 -0
- package/typed-router.d.ts +30 -0
- package/vite.config.ts +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Vue 3 + TypeScript + Vite
|
|
2
|
+
|
|
3
|
+
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
|
4
|
+
|
|
5
|
+
## Recommended IDE Setup
|
|
6
|
+
|
|
7
|
+
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
|
8
|
+
|
|
9
|
+
## Type Support For `.vue` Imports in TS
|
|
10
|
+
|
|
11
|
+
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
|
|
12
|
+
|
|
13
|
+
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
|
|
14
|
+
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
|
|
15
|
+
|
|
16
|
+
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/* prettier-ignore */
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
// noinspection JSUnusedGlobalSymbols
|
|
5
|
+
// Generated by unplugin-auto-import
|
|
6
|
+
// biome-ignore lint: disable
|
|
7
|
+
export {}
|
|
8
|
+
declare global {
|
|
9
|
+
const EffectScope: typeof import('vue')['EffectScope']
|
|
10
|
+
const computed: typeof import('vue')['computed']
|
|
11
|
+
const createApp: typeof import('vue')['createApp']
|
|
12
|
+
const customRef: typeof import('vue')['customRef']
|
|
13
|
+
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
|
14
|
+
const defineComponent: typeof import('vue')['defineComponent']
|
|
15
|
+
const effectScope: typeof import('vue')['effectScope']
|
|
16
|
+
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
|
17
|
+
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
|
18
|
+
const h: typeof import('vue')['h']
|
|
19
|
+
const inject: typeof import('vue')['inject']
|
|
20
|
+
const isProxy: typeof import('vue')['isProxy']
|
|
21
|
+
const isReactive: typeof import('vue')['isReactive']
|
|
22
|
+
const isReadonly: typeof import('vue')['isReadonly']
|
|
23
|
+
const isRef: typeof import('vue')['isRef']
|
|
24
|
+
const markRaw: typeof import('vue')['markRaw']
|
|
25
|
+
const nextTick: typeof import('vue')['nextTick']
|
|
26
|
+
const onActivated: typeof import('vue')['onActivated']
|
|
27
|
+
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
|
28
|
+
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
|
29
|
+
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
|
30
|
+
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
|
31
|
+
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
|
32
|
+
const onDeactivated: typeof import('vue')['onDeactivated']
|
|
33
|
+
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
|
34
|
+
const onMounted: typeof import('vue')['onMounted']
|
|
35
|
+
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
|
36
|
+
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
|
37
|
+
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
|
38
|
+
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
|
39
|
+
const onUnmounted: typeof import('vue')['onUnmounted']
|
|
40
|
+
const onUpdated: typeof import('vue')['onUpdated']
|
|
41
|
+
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
|
42
|
+
const provide: typeof import('vue')['provide']
|
|
43
|
+
const reactive: typeof import('vue')['reactive']
|
|
44
|
+
const readonly: typeof import('vue')['readonly']
|
|
45
|
+
const ref: typeof import('vue')['ref']
|
|
46
|
+
const resolveComponent: typeof import('vue')['resolveComponent']
|
|
47
|
+
const shallowReactive: typeof import('vue')['shallowReactive']
|
|
48
|
+
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
|
49
|
+
const shallowRef: typeof import('vue')['shallowRef']
|
|
50
|
+
const toRaw: typeof import('vue')['toRaw']
|
|
51
|
+
const toRef: typeof import('vue')['toRef']
|
|
52
|
+
const toRefs: typeof import('vue')['toRefs']
|
|
53
|
+
const toValue: typeof import('vue')['toValue']
|
|
54
|
+
const triggerRef: typeof import('vue')['triggerRef']
|
|
55
|
+
const unref: typeof import('vue')['unref']
|
|
56
|
+
const useAttrs: typeof import('vue')['useAttrs']
|
|
57
|
+
const useCssModule: typeof import('vue')['useCssModule']
|
|
58
|
+
const useCssVars: typeof import('vue')['useCssVars']
|
|
59
|
+
const useI18n: typeof import('vue-i18n')['useI18n']
|
|
60
|
+
const useId: typeof import('vue')['useId']
|
|
61
|
+
const useModel: typeof import('vue')['useModel']
|
|
62
|
+
const useRoute: typeof import('vue-router')['useRoute']
|
|
63
|
+
const useRouter: typeof import('vue-router')['useRouter']
|
|
64
|
+
const useSlots: typeof import('vue')['useSlots']
|
|
65
|
+
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
|
66
|
+
const watch: typeof import('vue')['watch']
|
|
67
|
+
const watchEffect: typeof import('vue')['watchEffect']
|
|
68
|
+
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
|
69
|
+
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
|
70
|
+
}
|
|
71
|
+
// for type re-export
|
|
72
|
+
declare global {
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
|
75
|
+
import('vue')
|
|
76
|
+
}
|
package/components.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
// Generated by unplugin-vue-components
|
|
4
|
+
// Read more: https://github.com/vuejs/core/pull/3399
|
|
5
|
+
export {}
|
|
6
|
+
|
|
7
|
+
/* prettier-ignore */
|
|
8
|
+
declare module 'vue' {
|
|
9
|
+
export interface GlobalComponents {
|
|
10
|
+
AppHeader: typeof import('./src/components/AppHeader.vue')['default']
|
|
11
|
+
AppNavigation: typeof import('./src/components/AppNavigation.vue')['default']
|
|
12
|
+
AppNavigationDesktop: typeof import('./src/components/AppNavigationDesktop.vue')['default']
|
|
13
|
+
AppNavigationMobile: typeof import('./src/components/AppNavigationMobile.vue')['default']
|
|
14
|
+
AppNavigationSearch: typeof import('./src/components/AppNavigationSearch.vue')['default']
|
|
15
|
+
FileUploader: typeof import('./src/components/FileUploader.vue')['default']
|
|
16
|
+
ItemTextEditor: typeof import('./src/components/ItemTextEditor.vue')['default']
|
|
17
|
+
LoadingLayer: typeof import('./src/components/LoadingLayer.vue')['default']
|
|
18
|
+
LogTerminal: typeof import('./src/components/LogTerminal.vue')['default']
|
|
19
|
+
PageEditor: typeof import('./src/components/PageEditor.vue')['default']
|
|
20
|
+
Pagination: typeof import('./src/components/Pagination.vue')['default']
|
|
21
|
+
PreferenceArr: typeof import('./src/components/PreferenceArr.vue')['default']
|
|
22
|
+
PreferenceGrp: typeof import('./src/components/PreferenceGrp.vue')['default']
|
|
23
|
+
PreferenceItem: typeof import('./src/components/PreferenceItem.vue')['default']
|
|
24
|
+
RouterLink: typeof import('vue-router')['RouterLink']
|
|
25
|
+
RouterView: typeof import('vue-router')['RouterView']
|
|
26
|
+
SiteCreate: typeof import('./src/components/SiteCreate.vue')['default']
|
|
27
|
+
SiteEditor: typeof import('./src/components/SiteEditor.vue')['default']
|
|
28
|
+
SiteSwitcher: typeof import('./src/components/SiteSwitcher.vue')['default']
|
|
29
|
+
UserEditor: typeof import('./src/components/UserEditor.vue')['default']
|
|
30
|
+
}
|
|
31
|
+
}
|
package/env.d.ts
ADDED
package/index.html
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="referrer" content="strict-origin" />
|
|
7
|
+
<meta name="robots" content="noindex" />
|
|
8
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
|
|
9
|
+
<title>Artalk</title>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="app"></div>
|
|
13
|
+
<script type="module" src="/src/main.ts"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@esershnr/artalk-sidebar",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "The sidebar of artalk",
|
|
6
|
+
"private": false,
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "vite",
|
|
13
|
+
"build": "vue-tsc && vite build",
|
|
14
|
+
"preview": "vite preview"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/crypto-js": "^4.2.2",
|
|
18
|
+
"@vitejs/plugin-vue": "^5.1.4",
|
|
19
|
+
"@esershnr/artalk": "workspace:^",
|
|
20
|
+
"crypto-js": "^4.2.0",
|
|
21
|
+
"pinia": "^2.2.4",
|
|
22
|
+
"typescript": "^5.6.3",
|
|
23
|
+
"unplugin-auto-import": "^0.18.3",
|
|
24
|
+
"unplugin-vue-components": "^0.27.4",
|
|
25
|
+
"unplugin-vue-router": "^0.10.8",
|
|
26
|
+
"vue": "^3.5.12",
|
|
27
|
+
"vue-i18n": "^10.0.4",
|
|
28
|
+
"vue-router": "^4.4.5",
|
|
29
|
+
"vue-tsc": "^2.1.6",
|
|
30
|
+
"yaml": "^2.6.0"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
Binary file
|
package/src/App.vue
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { storeToRefs } from 'pinia'
|
|
3
|
+
import { useNavStore } from './stores/nav'
|
|
4
|
+
|
|
5
|
+
const nav = useNavStore()
|
|
6
|
+
const { scrollableArea, darkMode } = storeToRefs(nav)
|
|
7
|
+
|
|
8
|
+
const query = window.matchMedia('(prefers-color-scheme: dark)')
|
|
9
|
+
|
|
10
|
+
onMounted(() => query.addEventListener('change', onDarkModeChange))
|
|
11
|
+
onUnmounted(() => query.removeEventListener('change', onDarkModeChange))
|
|
12
|
+
const onDarkModeChange = (e: MediaQueryListEvent) => {
|
|
13
|
+
// auto switch when localStorage is empty
|
|
14
|
+
if (localStorage.getItem('ATK_SIDEBAR_DARK_MODE') === null) darkMode.value = e.matches
|
|
15
|
+
}
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div class="app-wrap artalk atk-sidebar" :class="{ 'atk-dark-mode': darkMode }">
|
|
20
|
+
<AppHeader />
|
|
21
|
+
<AppNavigation />
|
|
22
|
+
|
|
23
|
+
<div class="main">
|
|
24
|
+
<div ref="scrollableArea" class="atk-sidebar-inner">
|
|
25
|
+
<div class="atk-sidebar-container">
|
|
26
|
+
<router-view />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<LoadingLayer v-if="nav.isPageLoading" />
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<style scoped lang="scss">
|
|
35
|
+
$headerHeight: 61px;
|
|
36
|
+
$subHeaderHeight: 41px;
|
|
37
|
+
$maxWidth: 1100px;
|
|
38
|
+
$sidebarWidth: 280px;
|
|
39
|
+
|
|
40
|
+
.app-wrap {
|
|
41
|
+
background: var(--at-color-bg);
|
|
42
|
+
color: var(--at-color-font);
|
|
43
|
+
min-height: 100vh;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.main {
|
|
47
|
+
position: relative;
|
|
48
|
+
|
|
49
|
+
.atk-sidebar-inner {
|
|
50
|
+
overflow-y: auto;
|
|
51
|
+
height: calc(100vh - $headerHeight - $subHeaderHeight);
|
|
52
|
+
padding-bottom: 50px;
|
|
53
|
+
|
|
54
|
+
@media (min-width: 1024px) {
|
|
55
|
+
height: calc(100vh - $headerHeight - 51px);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// The placeholder area for the pagination bar
|
|
60
|
+
:deep(.atk-pagination-wrap) {
|
|
61
|
+
z-index: 200;
|
|
62
|
+
position: fixed;
|
|
63
|
+
width: 100%;
|
|
64
|
+
bottom: 0;
|
|
65
|
+
left: 0;
|
|
66
|
+
background: var(--at-color-bg);
|
|
67
|
+
border-top: 1px solid var(--at-color-border);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:deep(.atk-sidebar-container) {
|
|
72
|
+
position: relative;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@media (min-width: 1024px) {
|
|
76
|
+
:deep(.atk-sidebar-container) {
|
|
77
|
+
max-width: $maxWidth;
|
|
78
|
+
margin: 0 auto;
|
|
79
|
+
width: 100%;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@media (min-width: 1024px) and (max-width: calc($maxWidth + $sidebarWidth * 2)) {
|
|
84
|
+
:deep(.atk-sidebar-container) {
|
|
85
|
+
margin-left: $sidebarWidth;
|
|
86
|
+
max-width: calc(100% - $sidebarWidth);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
</style>
|
package/src/artalk.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import Artalk, { type Context } from '@esershnr/artalk'
|
|
2
|
+
import { Router } from 'vue-router'
|
|
3
|
+
import { bootParams } from './global'
|
|
4
|
+
import { useUserStore } from './stores/user'
|
|
5
|
+
|
|
6
|
+
export function setupArtalk() {
|
|
7
|
+
// Create virtual element for Artalk
|
|
8
|
+
const artalkEl = document.createElement('div')
|
|
9
|
+
artalkEl.style.display = 'none'
|
|
10
|
+
document.body.append(artalkEl)
|
|
11
|
+
|
|
12
|
+
// Init Artalk
|
|
13
|
+
return Artalk.init({
|
|
14
|
+
el: artalkEl,
|
|
15
|
+
server: '../',
|
|
16
|
+
pageKey: bootParams.pageKey,
|
|
17
|
+
site: bootParams.site,
|
|
18
|
+
darkMode: bootParams.darkMode,
|
|
19
|
+
pvAdd: false,
|
|
20
|
+
noComment: `<div class="atk-sidebar-no-content"></div>`,
|
|
21
|
+
flatMode: true,
|
|
22
|
+
pagination: {
|
|
23
|
+
pageSize: 20,
|
|
24
|
+
readMore: false,
|
|
25
|
+
autoLoad: false,
|
|
26
|
+
},
|
|
27
|
+
listUnreadHighlight: true,
|
|
28
|
+
fetchCommentsOnInit: false,
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function syncArtalkUser(artalk: Context, router: Router) {
|
|
33
|
+
const user = useUserStore()
|
|
34
|
+
const logout = () => {
|
|
35
|
+
user.logout()
|
|
36
|
+
nextTick(() => {
|
|
37
|
+
router.replace('/login')
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Access from open sidebar or directly by url
|
|
42
|
+
if (bootParams.user?.email) {
|
|
43
|
+
// sync user from sidebar to artalk
|
|
44
|
+
artalk.getUser().update(bootParams.user)
|
|
45
|
+
} else {
|
|
46
|
+
// Sync user from artalk to sidebar
|
|
47
|
+
try {
|
|
48
|
+
user.sync()
|
|
49
|
+
} catch {
|
|
50
|
+
logout()
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Async check user status (no await)
|
|
56
|
+
checkUser(artalk, logout)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function checkUser(artalk: Context, logout: () => void) {
|
|
60
|
+
// Get user info from artalk
|
|
61
|
+
const { name, email } = artalk.getUser().getData()
|
|
62
|
+
|
|
63
|
+
// Remove login failed dialog if sidebar
|
|
64
|
+
artalk.getApiHandlers().remove('need_login')
|
|
65
|
+
artalk.getApiHandlers().add('need_login', async () => {
|
|
66
|
+
logout()
|
|
67
|
+
throw new Error('Need login')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// Check user status
|
|
71
|
+
artalk
|
|
72
|
+
.getApi()
|
|
73
|
+
.user.getUserStatus({ email, name })
|
|
74
|
+
.then((res) => {
|
|
75
|
+
if (res.data.is_admin && !res.data.is_login) {
|
|
76
|
+
logout()
|
|
77
|
+
} else {
|
|
78
|
+
// Mark all notifications as read
|
|
79
|
+
artalk.getApi().notifies.markAllNotifyRead({ email, name })
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><path d="m7.5 5.25c0 2.8995 2.3505 5.25 5.25 5.25 1.4688 0 2.7967-.60323 3.7496-1.57538.0004.02513.0004.05025.0004.07538 0 4.1421-3.3579 7.5-7.5 7.5-4.14214 0-7.5-3.3579-7.5-7.5 0-4.14214 3.35786-7.5 7.5-7.5.02512 0 .05025 0 .07537.00037-.97215.95286-1.57537 2.28081-1.57537 3.74963zm-4.5 3.75c0 3.3137 2.68629 6 6 6 2.2937 0 4.2868-1.2871 5.2965-3.1784-.5006.1174-1.0189.1784-1.5465.1784-3.72795 0-6.75-3.02205-6.75-6.75 0-.52764.061-1.0459.17842-1.5465-1.89134 1.00967-3.17842 3.00277-3.17842 5.2965z" fill="#000"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h18v18h-18z"/></clipPath><g clip-path="url(#a)"><path d="m9 13.5c-2.48528 0-4.5-2.0147-4.5-4.5 0-2.48528 2.01472-4.5 4.5-4.5 2.4853 0 4.5 2.01472 4.5 4.5 0 2.4853-2.0147 4.5-4.5 4.5zm0-1.5c1.6568 0 3-1.3432 3-3 0-1.65686-1.3432-3-3-3-1.65686 0-3 1.34314-3 3 0 1.6568 1.34314 3 3 3zm-.75-11.25h1.5v2.25h-1.5zm0 14.25h1.5v2.25h-1.5zm-5.61396-11.3033 1.06066-1.06066 1.59099 1.59099-1.06066 1.06066zm10.07626 10.0763 1.0607-1.0607 1.591 1.591-1.0607 1.0607zm1.591-11.13696 1.0607 1.06066-1.591 1.59099-1.0607-1.06066zm-10.07627 10.07626 1.06066 1.0607-1.59099 1.591-1.06066-1.0607zm13.02297-4.4623v1.5h-2.25v-1.5zm-14.25 0v1.5h-2.25v-1.5z" fill="#fff"/></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="13" viewBox="0 0 13 13" width="13" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h13v13h-13z"/></clipPath><g clip-path="url(#a)"><path d="m9.68646 10.4524c-.92153.5843-2.0144.9227-3.1863.9227-2.92076 0-5.35066-2.10155-5.860105-4.87499.236535-1.28775.887075-2.43062 1.808535-3.28555l-1.693691-1.69368.766041-.766039 10.72446 10.724459-.766.7661zm-6.47134-6.47131c-.71981.65566-1.24464 1.52614-1.46945 2.51902.49695 2.19478 2.46016 3.79169 4.75449 3.79169.86635 0 1.68551-.2277 2.39634-.62933l-1.09867-1.09866c-.37575.23676-.82073.3738-1.29767.3738-1.34621 0-2.43752-1.09135-2.43752-2.4375 0-.47699.13699-.92197.37378-1.29771zm3.77991 3.77991-1.75578-1.75576c-.06021.1533-.09328.32018-.09328.49487 0 .74788.60631 1.35417 1.35419 1.35417.17464 0 .34158-.0331.49487-.09328zm4.27537 1.22661-.7751-.77502c.3553-.5064.6172-1.08501.7593-1.71248-.4969-2.19484-2.46015-3.79169-4.75444-3.79169-.45819 0-.90317.06369-1.32589.1831l-.85477-.85477c.67535-.26572 1.41095-.41166 2.18066-.41166 2.92072 0 5.35064 2.10154 5.86004 4.87502-.1691.92062-.5498 1.76724-1.0898 2.4875zm-4.9205-4.92047c.04968-.00302.09978-.00455.15026-.00455 1.34615 0 2.4375 1.0913 2.4375 2.43752 0 .05043-.00157.10053-.00455.1502z" fill="#636c76"/></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="13" viewBox="0 0 13 13" width="13" xmlns="http://www.w3.org/2000/svg"><path d="m6.50016 1.625c2.92072 0 5.35064 2.10154 5.86004 4.875-.5094 2.77344-2.93932 4.875-5.86004 4.875-2.92076 0-5.35066-2.10156-5.860105-4.875.509445-2.77346 2.939345-4.875 5.860105-4.875zm0 8.6667c2.29429 0 4.25754-1.59687 4.75444-3.7917-.4969-2.19482-2.46015-3.79167-4.75444-3.79167-2.29433 0-4.25754 1.59685-4.75449 3.79167.49695 2.19483 2.46016 3.7917 4.75449 3.7917zm0-1.3542c-1.34621 0-2.43752-1.0913-2.43752-2.4375 0-1.34619 1.09131-2.4375 2.43752-2.4375 1.34615 0 2.4375 1.09131 2.4375 2.4375 0 1.3462-1.09135 2.4375-2.4375 2.4375zm0-1.08333c.74788 0 1.35417-.60629 1.35417-1.35417s-.60629-1.35417-1.35417-1.35417-1.35419.60629-1.35419 1.35417.60631 1.35417 1.35419 1.35417z" fill="#636c76"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m5.37879 15.8333-3.71212 2.9167v-15.41667c0-.46023.3731-.83333.83333-.83333h15c.4603 0 .8333.3731.8333.83333v11.66667c0 .4602-.373.8333-.8333.8333zm-.57644-1.6666h11.86435v-10.00003h-13.33337v11.15423zm1.86432-5.83337h6.66663v1.66667h-6.66663z" fill="#636c76"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m15.8333 18.3333h-11.66663c-1.38071 0-2.5-1.1192-2.5-2.5v-13.3333c0-.46023.3731-.83333.83333-.83333h11.6667c.4602 0 .8333.3731.8333.83333v10h3.3333v3.3333c0 1.3808-1.1192 2.5-2.5 2.5zm-.8333-4.1666v1.6666c0 .4603.3731.8334.8333.8334.4603 0 .8334-.3731.8334-.8334v-1.6666zm-1.6667 2.5v-13.33337h-9.99997v12.49997c0 .4603.3731.8334.83334.8334zm-8.3333-10.83337h6.6667v1.66667h-6.6667zm0 3.33334h6.6667v1.66663h-6.6667zm0 3.33333h4.16667v1.6667h-4.16667z" fill="#636c76"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m9.16667 1.66667c4.14003 0 7.50003 3.36 7.50003 7.5 0 4.14003-3.36 7.50003-7.50003 7.50003-4.14 0-7.5-3.36-7.5-7.50003 0-4.14 3.36-7.5 7.5-7.5zm0 13.33333c3.22293 0 5.83333-2.6104 5.83333-5.83333 0-3.22292-2.6104-5.83334-5.83333-5.83334-3.22292 0-5.83334 2.61042-5.83334 5.83334 0 3.22293 2.61042 5.83333 5.83334 5.83333zm7.07113.0593 2.3569 2.357-1.1784 1.1784-2.357-2.3569z" fill="#636c76"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m10 .833333 7.9167 4.583337v9.16663l-7.9167 4.5834-7.91666-4.5834v-9.16663zm0 1.925837-6.25 3.61842v7.24481l6.25 3.6184 6.25-3.6184v-7.24481zm0 10.57413c-1.84095 0-3.33333-1.4924-3.33333-3.3333 0-1.84095 1.49238-3.33333 3.33333-3.33333 1.8409 0 3.3333 1.49238 3.3333 3.33333 0 1.8409-1.4924 3.3333-3.3333 3.3333zm0-1.6666c.9205 0 1.6667-.7462 1.6667-1.6667s-.7462-1.66667-1.6667-1.66667-1.66666.74617-1.66666 1.66667.74616 1.6667 1.66666 1.6667z" fill="#636c76"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m16.7362 12.6666 1.0017.6011c.1974.1184.2613.3743.1429.5716-.0352.0587-.0842.1078-.1429.1429l-7.3091 4.3855c-.2639.1584-.59363.1584-.85746 0l-7.30915-4.3855c-.19732-.1184-.26131-.3743-.14291-.5716.03519-.0587.08426-.1078.14291-.1429l1.00174-.6011 6.73617 4.0416zm0-3.91668 1.0017.60108c.1974.11842.2613.37433.1429.57167-.0352.05866-.0842.10773-.1429.14293l-7.7378 4.6427-7.73791-4.6427c-.19732-.11843-.26131-.37435-.14291-.57168.03519-.05867.08426-.10775.14291-.14292l1.00174-.60108 6.73617 4.04168zm-6.3074-7.65939 7.3091 4.38547c.1974.11839.2613.37433.1429.57166-.0352.05865-.0842.10773-.1429.14291l-7.7378 4.64263-7.73791-4.64263c-.19732-.11839-.26131-.37433-.14291-.57165.03519-.05865.08426-.10773.14291-.14292l7.30915-4.38547c.26383-.15833.59356-.15833.85746 0zm-.4287 1.68641-5.09397 3.05635 5.09397 3.05638 5.0939-3.05638z" fill="#636c76"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m5.00007 4.92853-1.91075 1.91075-1.17851-1.17851 3.92259-3.92259 3.9226 3.92259-1.1785 1.17851-1.91077-1.91075v4.23814h-1.66666zm9.16673 2.98816c1.1505 0 2.0833-.93274 2.0833-2.08333s-.9328-2.08333-2.0833-2.08333c-1.1506 0-2.0834.93274-2.0834 2.08333s.9328 2.08333 2.0834 2.08333zm0 1.66664c-2.0711 0-3.75-1.67891-3.75-3.74997 0-2.07107 1.6789-3.75 3.75-3.75 2.071 0 3.7499 1.67893 3.7499 3.75 0 2.07106-1.6789 3.74997-3.7499 3.74997zm3.9225 4.75587-1.1785-1.1785-1.9107 1.9108v-4.2382h-1.6667v4.2382l-1.9107-1.9108-1.1785 1.1785 3.9226 3.9226zm-13.92257 1.4941h3.33333l.00001-3.3333h-3.33334zm4.16669-5c.46025 0 .83333.3731.83333.8334v5c0 .4602-.37308.8333-.83333.8333h-5.00003c-.46023 0-.83333-.3731-.83332-.8333v-5c0-.4603.37309-.8334.83333-.8334z" fill="#636c76"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m2.5 4.16257c0-.91821.74385-1.66257 1.66257-1.66257h11.67483c.9183 0 1.6626.74385 1.6626 1.66257v11.67483c0 .9183-.7438 1.6626-1.6626 1.6626h-11.67483c-.91821 0-1.66257-.7438-1.66257-1.6626zm1.66667.0041v11.66663h11.66663v-11.66663zm2.4768 10.98403c-.51558-.2233-1.00415-.4971-1.45945-.8154 1.03909-1.6059 2.846-2.6686 4.90118-2.6686 1.9994 0 3.7639 1.0059 4.8149 2.5393-.4469.3303-.9281.6171-1.4372.8538-.7569-1.046-1.9879-1.7265-3.3777-1.7265-1.42978 0-2.69128.7201-3.44173 1.8174zm3.35653-4.3174c-1.61083 0-2.91667-1.3058-2.91667-2.91663 0-1.61084 1.30584-2.91667 2.91667-2.91667 1.6108 0 2.9167 1.30583 2.9167 2.91667 0 1.61083-1.3059 2.91663-2.9167 2.91663zm0-1.66663c.6903 0 1.25-.55967 1.25-1.25 0-.69036-.5597-1.25-1.25-1.25-.69033 0-1.25.55964-1.25 1.25 0 .69033.55967 1.25 1.25 1.25z" fill="#636c76"/></svg>
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { storeToRefs } from 'pinia'
|
|
3
|
+
import { useUserStore } from '../stores/user'
|
|
4
|
+
import { useNavStore } from '../stores/nav'
|
|
5
|
+
import { isOpenFromSidebar } from '../global'
|
|
6
|
+
|
|
7
|
+
const nav = useNavStore()
|
|
8
|
+
const router = useRouter()
|
|
9
|
+
const user = useUserStore()
|
|
10
|
+
const { t } = useI18n()
|
|
11
|
+
const { site: curtSite, is_admin: isAdmin, avatar } = storeToRefs(user)
|
|
12
|
+
const { darkMode } = storeToRefs(nav)
|
|
13
|
+
|
|
14
|
+
const avatarClickHandler = () => {
|
|
15
|
+
if (!isOpenFromSidebar()) logout()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const logout = () => {
|
|
19
|
+
if (!window.confirm(t('logoutConfirm'))) return
|
|
20
|
+
|
|
21
|
+
useUserStore().logout()
|
|
22
|
+
nextTick(() => {
|
|
23
|
+
router.replace('/login')
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<div class="header">
|
|
30
|
+
<template v-if="isAdmin">
|
|
31
|
+
<div
|
|
32
|
+
class="avatar clickable"
|
|
33
|
+
:class="{ active: nav.siteSwitcherShow }"
|
|
34
|
+
@click="nav.showSiteSwitcher()"
|
|
35
|
+
>
|
|
36
|
+
<div class="site">{{ curtSite.substring(0, 1) || '_' }}</div>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
<template v-else>
|
|
40
|
+
<div class="avatar" @click="avatarClickHandler">
|
|
41
|
+
<img :src="avatar" />
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<div class="title">
|
|
46
|
+
<div class="text show-mobile">{{ isAdmin ? t('ctrlCenter') : t('msgCenter') }}</div>
|
|
47
|
+
<div class="text show-desktop">
|
|
48
|
+
<template v-if="!isAdmin">{{ t('msgCenter') }}</template>
|
|
49
|
+
<template v-else-if="!!curtSite">{{ curtSite }}</template>
|
|
50
|
+
<template v-else>
|
|
51
|
+
<img src="../assets/favicon.png" class="artalk-logo" draggable="false" />
|
|
52
|
+
</template>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="close-btn"></div>
|
|
57
|
+
<div
|
|
58
|
+
class="dark-mode-toggle"
|
|
59
|
+
:data-darkmode="darkMode ? 'on' : 'off'"
|
|
60
|
+
@click="nav.toggleDarkMode()"
|
|
61
|
+
></div>
|
|
62
|
+
</div>
|
|
63
|
+
<SiteSwitcher v-if="isAdmin" />
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<style scoped lang="scss">
|
|
67
|
+
.header {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: row;
|
|
70
|
+
align-items: center;
|
|
71
|
+
border-bottom: 1px solid var(--at-color-border);
|
|
72
|
+
|
|
73
|
+
@media (min-width: 1024px) {
|
|
74
|
+
background: var(--at-sidebar-header-bg);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.avatar {
|
|
78
|
+
position: relative;
|
|
79
|
+
height: 60px;
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
justify-content: center;
|
|
83
|
+
border-right: 1px solid transparent;
|
|
84
|
+
padding: 0 10px 0 15px;
|
|
85
|
+
|
|
86
|
+
.site {
|
|
87
|
+
user-select: none;
|
|
88
|
+
color: #fff;
|
|
89
|
+
background: #697182;
|
|
90
|
+
height: 30px;
|
|
91
|
+
width: 30px;
|
|
92
|
+
border-radius: 2px;
|
|
93
|
+
text-align: center;
|
|
94
|
+
line-height: 30px;
|
|
95
|
+
font-size: 13px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
&.clickable {
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
|
|
101
|
+
&:hover,
|
|
102
|
+
&.active {
|
|
103
|
+
background: var(--at-color-bg-grey);
|
|
104
|
+
border-right: 1px solid var(--at-color-border);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&::after {
|
|
108
|
+
content: '';
|
|
109
|
+
margin-left: 10px;
|
|
110
|
+
vertical-align: middle;
|
|
111
|
+
border-top: 5px solid #747474;
|
|
112
|
+
border-left: 3px solid transparent;
|
|
113
|
+
border-right: 3px solid transparent;
|
|
114
|
+
margin-top: -1px;
|
|
115
|
+
display: inline-block;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
img {
|
|
120
|
+
height: 30px;
|
|
121
|
+
width: 30px;
|
|
122
|
+
border-radius: 2px;
|
|
123
|
+
background: #697182;
|
|
124
|
+
text-align: center;
|
|
125
|
+
line-height: 30px;
|
|
126
|
+
font-size: 13px;
|
|
127
|
+
color: #fff;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.title {
|
|
132
|
+
flex: auto;
|
|
133
|
+
text-align: center;
|
|
134
|
+
user-select: none;
|
|
135
|
+
|
|
136
|
+
.text {
|
|
137
|
+
display: inline-block;
|
|
138
|
+
position: relative;
|
|
139
|
+
color: var(--at-color-deep);
|
|
140
|
+
font-size: 20px;
|
|
141
|
+
|
|
142
|
+
&.show-mobile {
|
|
143
|
+
display: none;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
&.show-desktop {
|
|
147
|
+
display: inline-block;
|
|
148
|
+
|
|
149
|
+
&::after {
|
|
150
|
+
display: none;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@media (max-width: 1023px) {
|
|
155
|
+
&.show-mobile {
|
|
156
|
+
display: inline-block;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
&.show-desktop {
|
|
160
|
+
display: none;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
&::after {
|
|
165
|
+
content: '';
|
|
166
|
+
position: absolute;
|
|
167
|
+
bottom: 0;
|
|
168
|
+
left: 0;
|
|
169
|
+
width: 100%;
|
|
170
|
+
height: 6px;
|
|
171
|
+
background: #0083ff;
|
|
172
|
+
opacity: 0.4;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.artalk-logo {
|
|
177
|
+
border-radius: 2px;
|
|
178
|
+
height: 40px;
|
|
179
|
+
width: 40px;
|
|
180
|
+
background: #697182;
|
|
181
|
+
text-align: center;
|
|
182
|
+
line-height: 30px;
|
|
183
|
+
font-size: 13px;
|
|
184
|
+
color: #fff;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.close-btn {
|
|
189
|
+
width: 60px;
|
|
190
|
+
height: 60px;
|
|
191
|
+
margin-left: 10px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.dark-mode-toggle {
|
|
195
|
+
display: none;
|
|
196
|
+
width: 60px;
|
|
197
|
+
height: 60px;
|
|
198
|
+
margin-left: 10px;
|
|
199
|
+
justify-content: center;
|
|
200
|
+
align-items: center;
|
|
201
|
+
user-select: none;
|
|
202
|
+
cursor: pointer;
|
|
203
|
+
|
|
204
|
+
@media (min-width: 1024px) {
|
|
205
|
+
display: flex;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
&:hover {
|
|
209
|
+
&::after {
|
|
210
|
+
background-color: var(--at-color-bg-grey);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
&::after {
|
|
215
|
+
content: '';
|
|
216
|
+
display: block;
|
|
217
|
+
transition: background-color 0.2s;
|
|
218
|
+
width: 35px;
|
|
219
|
+
height: 35px;
|
|
220
|
+
background-repeat: no-repeat;
|
|
221
|
+
background-position: center;
|
|
222
|
+
background-size: 60%;
|
|
223
|
+
border-radius: 50%;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
&[data-darkmode='on']::after {
|
|
227
|
+
background-image: url('@/assets/icon-darkmode-on.svg');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
&[data-darkmode='off']::after {
|
|
231
|
+
background-image: url('@/assets/icon-darkmode-off.svg');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
</style>
|