diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2022-12-27 14:36:33 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2022-12-27 14:36:33 +0900 |
| commit | 9384f5399da39e53855beb8e7f8ded1aa56bf72e (patch) | |
| tree | ce5959571a981b9c4047da3c7b3fd080aa44222c /packages/client/src/pages/theme-editor.vue | |
| parent | wip: retention for dashboard (diff) | |
| download | misskey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.tar.gz misskey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.tar.bz2 misskey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.zip | |
rename: client -> frontend
Diffstat (limited to 'packages/client/src/pages/theme-editor.vue')
| -rw-r--r-- | packages/client/src/pages/theme-editor.vue | 283 |
1 files changed, 0 insertions, 283 deletions
diff --git a/packages/client/src/pages/theme-editor.vue b/packages/client/src/pages/theme-editor.vue deleted file mode 100644 index d8ff170ca2..0000000000 --- a/packages/client/src/pages/theme-editor.vue +++ /dev/null @@ -1,283 +0,0 @@ -<template> -<MkStickyContainer> - <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800" :margin-min="16" :margin-max="32"> - <div class="cwepdizn _formRoot"> - <FormFolder :default-open="true" class="_formBlock"> - <template #label>{{ i18n.ts.backgroundColor }}</template> - <div class="cwepdizn-colors"> - <div class="row"> - <button v-for="color in bgColors.filter(x => x.kind === 'light')" :key="color.color" class="color _button" :class="{ active: theme.props.bg === color.color }" @click="setBgColor(color)"> - <div class="preview" :style="{ background: color.forPreview }"></div> - </button> - </div> - <div class="row"> - <button v-for="color in bgColors.filter(x => x.kind === 'dark')" :key="color.color" class="color _button" :class="{ active: theme.props.bg === color.color }" @click="setBgColor(color)"> - <div class="preview" :style="{ background: color.forPreview }"></div> - </button> - </div> - </div> - </FormFolder> - - <FormFolder :default-open="true" class="_formBlock"> - <template #label>{{ i18n.ts.accentColor }}</template> - <div class="cwepdizn-colors"> - <div class="row"> - <button v-for="color in accentColors" :key="color" class="color rounded _button" :class="{ active: theme.props.accent === color }" @click="setAccentColor(color)"> - <div class="preview" :style="{ background: color }"></div> - </button> - </div> - </div> - </FormFolder> - - <FormFolder :default-open="true" class="_formBlock"> - <template #label>{{ i18n.ts.textColor }}</template> - <div class="cwepdizn-colors"> - <div class="row"> - <button v-for="color in fgColors" :key="color" class="color char _button" :class="{ active: (theme.props.fg === color.forLight) || (theme.props.fg === color.forDark) }" @click="setFgColor(color)"> - <div class="preview" :style="{ color: color.forPreview ? color.forPreview : theme.base === 'light' ? '#5f5f5f' : '#dadada' }">A</div> - </button> - </div> - </div> - </FormFolder> - - <FormFolder :default-open="false" class="_formBlock"> - <template #icon><i class="ti ti-code"></i></template> - <template #label>{{ i18n.ts.editCode }}</template> - - <div class="_formRoot"> - <FormTextarea v-model="themeCode" tall class="_formBlock"> - <template #label>{{ i18n.ts._theme.code }}</template> - </FormTextarea> - <FormButton primary class="_formBlock" @click="applyThemeCode">{{ i18n.ts.apply }}</FormButton> - </div> - </FormFolder> - - <FormFolder :default-open="false" class="_formBlock"> - <template #label>{{ i18n.ts.addDescription }}</template> - - <div class="_formRoot"> - <FormTextarea v-model="description"> - <template #label>{{ i18n.ts._theme.description }}</template> - </FormTextarea> - </div> - </FormFolder> - </div> - </MkSpacer> -</MkStickyContainer> -</template> - -<script lang="ts" setup> -import { watch } from 'vue'; -import { toUnicode } from 'punycode/'; -import tinycolor from 'tinycolor2'; -import { v4 as uuid } from 'uuid'; -import JSON5 from 'json5'; - -import FormButton from '@/components/MkButton.vue'; -import FormTextarea from '@/components/form/textarea.vue'; -import FormFolder from '@/components/form/folder.vue'; - -import { $i } from '@/account'; -import { Theme, applyTheme } from '@/scripts/theme'; -import lightTheme from '@/themes/_light.json5'; -import darkTheme from '@/themes/_dark.json5'; -import { host } from '@/config'; -import * as os from '@/os'; -import { ColdDeviceStorage, defaultStore } from '@/store'; -import { addTheme } from '@/theme-store'; -import { i18n } from '@/i18n'; -import { useLeaveGuard } from '@/scripts/use-leave-guard'; -import { definePageMetadata } from '@/scripts/page-metadata'; - -const bgColors = [ - { color: '#f5f5f5', kind: 'light', forPreview: '#f5f5f5' }, - { color: '#f0eee9', kind: 'light', forPreview: '#f3e2b9' }, - { color: '#e9eff0', kind: 'light', forPreview: '#bfe3e8' }, - { color: '#f0e9ee', kind: 'light', forPreview: '#f1d1e8' }, - { color: '#dce2e0', kind: 'light', forPreview: '#a4dccc' }, - { color: '#e2e0dc', kind: 'light', forPreview: '#d8c7a5' }, - { color: '#d5dbe0', kind: 'light', forPreview: '#b0cae0' }, - { color: '#dad5d5', kind: 'light', forPreview: '#d6afaf' }, - { color: '#2b2b2b', kind: 'dark', forPreview: '#444444' }, - { color: '#362e29', kind: 'dark', forPreview: '#735c4d' }, - { color: '#303629', kind: 'dark', forPreview: '#506d2f' }, - { color: '#293436', kind: 'dark', forPreview: '#258192' }, - { color: '#2e2936', kind: 'dark', forPreview: '#504069' }, - { color: '#252722', kind: 'dark', forPreview: '#3c462f' }, - { color: '#212525', kind: 'dark', forPreview: '#303e3e' }, - { color: '#191919', kind: 'dark', forPreview: '#272727' }, -] as const; -const accentColors = ['#e36749', '#f29924', '#98c934', '#34c9a9', '#34a1c9', '#606df7', '#8d34c9', '#e84d83']; -const fgColors = [ - { color: 'none', forLight: '#5f5f5f', forDark: '#dadada', forPreview: null }, - { color: 'red', forLight: '#7f6666', forDark: '#e4d1d1', forPreview: '#ca4343' }, - { color: 'yellow', forLight: '#736955', forDark: '#e0d5c0', forPreview: '#d49923' }, - { color: 'green', forLight: '#586d5b', forDark: '#d1e4d4', forPreview: '#4cbd5c' }, - { color: 'cyan', forLight: '#5d7475', forDark: '#d1e3e4', forPreview: '#2abdc3' }, - { color: 'blue', forLight: '#676880', forDark: '#d1d2e4', forPreview: '#7275d8' }, - { color: 'pink', forLight: '#84667d', forDark: '#e4d1e0', forPreview: '#b12390' }, -]; - -let theme = $ref<Partial<Theme>>({ - base: 'light', - props: lightTheme.props, -}); -let description = $ref<string | null>(null); -let themeCode = $ref<string | null>(null); -let changed = $ref(false); - -useLeaveGuard($$(changed)); - -function showPreview() { - os.pageWindow('/preview'); -} - -function setBgColor(color: typeof bgColors[number]) { - if (theme.base !== color.kind) { - const base = color.kind === 'dark' ? darkTheme : lightTheme; - for (const prop of Object.keys(base.props)) { - if (prop === 'accent') continue; - if (prop === 'fg') continue; - theme.props[prop] = base.props[prop]; - } - } - theme.base = color.kind; - theme.props.bg = color.color; - - if (theme.props.fg) { - const matchedFgColor = fgColors.find(x => [tinycolor(x.forLight).toRgbString(), tinycolor(x.forDark).toRgbString()].includes(tinycolor(theme.props.fg).toRgbString())); - if (matchedFgColor) setFgColor(matchedFgColor); - } -} - -function setAccentColor(color) { - theme.props.accent = color; -} - -function setFgColor(color) { - theme.props.fg = theme.base === 'light' ? color.forLight : color.forDark; -} - -function apply() { - themeCode = JSON5.stringify(theme, null, '\t'); - applyTheme(theme, false); - changed = true; -} - -function applyThemeCode() { - let parsed; - - try { - parsed = JSON5.parse(themeCode); - } catch (err) { - os.alert({ - type: 'error', - text: i18n.ts._theme.invalid, - }); - return; - } - - theme = parsed; -} - -async function saveAs() { - const { canceled, result: name } = await os.inputText({ - title: i18n.ts.name, - allowEmpty: false, - }); - if (canceled) return; - - theme.id = uuid(); - theme.name = name; - theme.author = `@${$i.username}@${toUnicode(host)}`; - if (description) theme.desc = description; - await addTheme(theme); - applyTheme(theme); - if (defaultStore.state.darkMode) { - ColdDeviceStorage.set('darkTheme', theme); - } else { - ColdDeviceStorage.set('lightTheme', theme); - } - changed = false; - os.alert({ - type: 'success', - text: i18n.t('_theme.installed', { name: theme.name }), - }); -} - -watch($$(theme), apply, { deep: true }); - -const headerActions = $computed(() => [{ - asFullButton: true, - icon: 'ti ti-eye', - text: i18n.ts.preview, - handler: showPreview, -}, { - asFullButton: true, - icon: 'ti ti-check', - text: i18n.ts.saveAs, - handler: saveAs, -}]); - -const headerTabs = $computed(() => []); - -definePageMetadata({ - title: i18n.ts.themeEditor, - icon: 'ti ti-palette', -}); -</script> - -<style lang="scss" scoped> -.cwepdizn { - ::v-deep(.cwepdizn-colors) { - text-align: center; - - > .row { - > .color { - display: inline-block; - position: relative; - width: 64px; - height: 64px; - border-radius: 8px; - - > .preview { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - width: 42px; - height: 42px; - border-radius: 4px; - box-shadow: 0 2px 4px rgb(0 0 0 / 30%); - transition: transform 0.15s ease; - } - - &:hover { - > .preview { - transform: scale(1.1); - } - } - - &.active { - box-shadow: 0 0 0 2px var(--divider) inset; - } - - &.rounded { - border-radius: 999px; - - > .preview { - border-radius: 999px; - } - } - - &.char { - line-height: 42px; - } - } - } - } -} -</style> |