Adjust display in dark mode and add manual control support for dark mode.

pull/505/head
zanllp 2024-01-24 01:45:54 +08:00
parent a16cf5d98f
commit c85cbcd397
10 changed files with 81 additions and 66 deletions

2
vue/components.d.ts vendored
View File

@ -28,6 +28,8 @@ declare module '@vue/runtime-core' {
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
AModal: typeof import('ant-design-vue/es')['Modal']
ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
ASelect: typeof import('ant-design-vue/es')['Select']
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
ASlider: typeof import('ant-design-vue/es')['Slider']

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { onMounted } from 'vue'
import { onMounted, watch } from 'vue'
import { getGlobalSetting } from './api'
import { useGlobalStore } from './store/useGlobalStore'
import { getQuickMovePaths } from '@/page/taskRecord/autoComplete'
@ -9,6 +9,8 @@ import { resolveQueryActions } from './queryActions'
import { refreshTauriConf, tauriConf } from './util/tauriAppConf'
import { openModal } from './taurilaunchModal'
import { isTauri } from './util/env'
import { usePreferredDark } from '@vueuse/core'
import { delay } from 'vue3-ts-util'
const globalStore = useGlobalStore()
const queue = createReactiveQueue()
@ -39,6 +41,30 @@ useGlobalEventListen('returnToIIB', async () => {
const r = await getQuickMovePaths(conf)
globalStore.quickMovePaths = r.filter((v) => v?.dir?.trim?.())
})
watch(
() => globalStore.computedTheme === 'dark',
async (enableDark) => {
await delay()
const head = document.getElementsByTagName('html')[0] // htmlhead
if (enableDark) {
document.body.classList.add('dark')
const darkStyle = document.createElement('style')
const { default: css } = await import('ant-design-vue/dist/antd.dark.css?inline')
darkStyle.innerHTML = css
darkStyle.setAttribute('antd-dark', '')
head.appendChild(darkStyle)
} else {
document.body.classList.remove('dark')
Array.from(head.querySelectorAll('style[antd-dark]')).forEach((e) => e.remove())
}
},
{ immediate: true }
)
onMounted(async () => {
if (isTauri) {
openModal()

View File

@ -65,15 +65,17 @@ $success-color: #28a745;
--zp-border: var(--zp-grey20);
--zp-icon-bg: #0004;
@media (prefers-color-scheme: dark) {
--zp-primary: var(--zp-grey20);
--zp-secondary: var(--zp-grey60);
--zp-tertiary: var(--zp-grey70);
--zp-primary-background: var(--zp-black);
--zp-secondary-background: var(--zp-grey96);
--zp-secondary-variant-background: var(--zp-grey90);
--zp-tertiary-background: var(--zp-grey4);
--zp-border: var(--zp-grey96);
--zp-icon-bg: #fff4;
.body:not(.dark) {
--zp-primary: var(--zp-grey20);
--zp-secondary: var(--zp-grey60);
--zp-tertiary: var(--zp-grey70);
--zp-primary-background: var(--zp-black);
--zp-secondary-background: var(--zp-grey96);
--zp-secondary-variant-background: var(--zp-grey90);
--zp-tertiary-background: var(--zp-grey4);
--zp-border: var(--zp-grey96);
--zp-icon-bg: #fff4;
}
}
body.dark {
--zp-primary: var(--zp-grey20);

View File

@ -1,4 +1,4 @@
import { createApp, watch } from 'vue'
import { createApp } from 'vue'
import type {} from 'antd-vue-volar'
// @ts-ignore
import App from './App.vue'
@ -8,10 +8,8 @@ import 'ant-design-vue/es/modal/style'
import './index.scss'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import { usePreferredDark } from '@vueuse/core'
import { i18n } from './i18n'
import { delay } from 'vue3-ts-util'
import VueDiff from 'vue-diff';
import VueDiff from 'vue-diff'
import 'vue-diff/dist/index.css';
@ -25,35 +23,3 @@ createApp(App)
})
.mount('#zanllp_dev_gradio_fe')
const dark = usePreferredDark()
const getParDark = () => {
try {
return parent.location.search.includes('theme=dark') // sd-webui的
} catch (error) {
//
}
return false
}
watch(
[dark, getParDark],
async ([selfdark, pardark]) => {
await delay()
const head = document.getElementsByTagName('html')[0] // html而不是head保证优先级
if (selfdark || pardark) {
document.body.classList.add('dark')
const darkStyle = document.createElement('style')
const { default: css } = await import('ant-design-vue/dist/antd.dark.css?inline')
darkStyle.innerHTML = css
darkStyle.setAttribute('antd-dark', '')
head.appendChild(darkStyle)
} else {
document.body.classList.remove('dark')
Array.from(head.querySelectorAll('style[antd-dark]')).forEach((e) => e.remove())
}
},
{ immediate: true }
)

View File

@ -68,7 +68,7 @@ const maxEdge = asyncComputed(async () => {
.hint-inline {
display: inline-block;
color: var(--main-text-color);
color: var(--zp-primary);
margin: 0 auto;
padding: 4px 8px;
border-radius: 4px;
@ -79,14 +79,10 @@ const maxEdge = asyncComputed(async () => {
.img-sli .default-theme {
.splitpanes__splitter {
background-color: #ccc;
background-color: var(--zp-tertiary);
position: relative;
width: 4px;
}
.splitpanes {
background-color: #f8f8f8;
}
}
</style>

View File

@ -15,7 +15,7 @@ const splitpane = ref<{ requestFullScreen (): void }>()
<div class="actions">
<AButton @click="sli.drawerVisible = false">{{ $t('close') }}</AButton>
<AButton @click="splitpane?.requestFullScreen()">{{ $t('fullscreenview') }}</AButton>
<a-alert banner style="height: 32px;" :message="'👇 '+$t('scrollDownToComparePrompt')" type="info" show-icon />
<a-alert banner style="height: 32px;" :message="'👇 ' + $t('scrollDownToComparePrompt')" type="info" show-icon />
</div>
</template>
</ADrawer>
@ -30,7 +30,6 @@ const splitpane = ref<{ requestFullScreen (): void }>()
}
</style>
<style lang="scss">
.img-sli {
.ant-drawer-header,
@ -39,16 +38,17 @@ const splitpane = ref<{ requestFullScreen (): void }>()
}
.default-theme {
.splitpanes__splitter {
background-color: #ccc;
background-color: var(--zp-tertiary);
position: relative;
width: 4px;
}
.splitpanes {
background-color: #f8f8f8;
.splitpanes__pane {
background: var(--zp-primary-background);
}
}
}</style>
}
</style>

View File

@ -6,6 +6,7 @@ import { getImageGenerationInfo } from '@/api'
import { watch, ref } from 'vue'
import { createReactiveQueue } from '@/util'
import { parse } from 'stable-diffusion-image-metadata'
import { useGlobalStore } from '@/store/useGlobalStore'
const props = defineProps<{
lImg: FileNodeInfo,
@ -13,6 +14,7 @@ const props = defineProps<{
}>()
const q = createReactiveQueue()
const g = useGlobalStore()
const lImgInfo = ref("")
const rImgInfo = ref("")
let seenKeys = []
@ -60,7 +62,7 @@ watch(
</script>
<template>
<VueDiff class="diff" mode="split" theme="light" language="plaintext" :prev="lImgInfo" :current="rImgInfo">
<VueDiff class="diff" mode="split" :theme="g.computedTheme" language="plaintext" :prev="lImgInfo" :current="rImgInfo">
</VueDiff>
</template>
@ -68,9 +70,6 @@ watch(
.diff {
transform: scale(1);
opacity: 1;
background-color: rgba(255, 255, 255, 0.5) !important;
color: #f8f8f8;
backdrop-filter: blur(5px);
transition: top 0.2s ease-in-out;
}

View File

@ -103,6 +103,7 @@ const restoreRecord = () => {
<LockOutlined title="Access Control mode" style="vertical-align: text-bottom;" />
</div>
<div flex-placeholder />
<a href="https://github.com/zanllp/sd-webui-infinite-image-browsing" target="_blank" class="last-record">Github</a>
<a href="https://github.com/zanllp/sd-webui-infinite-image-browsing/blob/main/.env.example" target="_blank"
class="last-record">{{ $t('privacyAndSecurity') }}</a>
@ -110,6 +111,11 @@ const restoreRecord = () => {
class="last-record">{{ $t('changlog') }}</a>
<a href="https://github.com/zanllp/sd-webui-infinite-image-browsing/issues/90" target="_blank"
class="last-record">{{ $t('faq') }}</a>
<a-radio-group v-model:value="global.darkModeControl" button-style="solid">
<a-radio-button value="light">light</a-radio-button>
<a-radio-button value="auto">auto</a-radio-button>
<a-radio-button value="dark">dark</a-radio-button>
</a-radio-group>
</div>
<a-alert show-icon v-if="global.conf?.enable_access_control && !global.dontShowAgain">
<template #message>
@ -244,7 +250,7 @@ const restoreRecord = () => {
}
.last-record {
margin-left: 16px;
margin-right: 16px;
font-size: 14px;
color: var(--zp-secondary);
flex-shrink: 0;

View File

@ -324,8 +324,8 @@ const copyPositivePrompt = () => {
line-height: 1.78em;
:deep(span) {
background: rgba(0, 0, 0, 0.06);
color: black;
background: var(--zp-secondary-variant-background);
color: var(--zp-primary);
padding: 2px 4px;
border-radius: 4px;
margin-right: 4px;

View File

@ -6,6 +6,7 @@ import { getPreferredLang } from '@/i18n'
import { SortMethod } from '@/page/fileTransfer/fileSort'
import type { getQuickMovePaths } from '@/page/taskRecord/autoComplete'
import { type Dict, type ReturnTypeAsync } from '@/util'
import { usePreferredDark } from '@vueuse/core'
import { cloneDeep, uniqueId } from 'lodash-es'
import { defineStore } from 'pinia'
import { VNode, computed, onMounted, reactive, toRaw, watch } from 'vue'
@ -98,6 +99,7 @@ export const useGlobalStore = defineStore(
const gridThumbnailResolution = ref(512)
const defaultSortingMethod = ref(SortMethod.CREATED_TIME_DESC)
const defaultGridCellWidth = ref(256)
const darkModeControl = ref<'light' | 'dark' | 'auto'>('auto')
const createEmptyPane = (): TabPane => ({
type: 'empty',
@ -176,7 +178,22 @@ export const useGlobalStore = defineStore(
const ignoredConfirmActions = reactive<Record<ActionConfirmRequired, boolean>>({ deleteOneOnly: false })
const dark = usePreferredDark()
const computedTheme = computed(() => {
const getParDark = () => {
try {
return parent.location.search.includes('theme=dark') // sd-webui的
} catch (error) {
return false
}
}
const isDark = darkModeControl.value === 'auto' ? (dark.value || getParDark()) : (darkModeControl.value === 'dark')
return isDark ? 'dark' : 'light'
})
return {
computedTheme,
darkModeControl,
defaultSortingMethod,
defaultGridCellWidth,
pathAliasMap,
@ -205,6 +222,7 @@ export const useGlobalStore = defineStore(
persist: {
// debug: true,
paths: [
'darkModeControl',
'dontShowAgainNewImgOpts',
'defaultSortingMethod',
'defaultGridCellWidth',