Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bd7ef3b80 | ||
|
|
4f36ff9ceb |
@@ -249,6 +249,35 @@ class Base extends Abstract {
|
|||||||
return this.postRequest({ url });
|
return this.postRequest({ url });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== 用户外观偏好(外观偏好服务端化 2026-10-08;后端契约见 AppearanceController)=====
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读当前用户外观偏好聚合:{myTheme, schTheme, avatarMy, avatarSch, logoUrl}(紧凑编码/绝对 URL,查不到为 null)。
|
||||||
|
* 各子应用 yh-theme-init 异步补齐段的同源数据源;选择端预留(本轮设置页双写用不到)。
|
||||||
|
*/
|
||||||
|
getAppearance() {
|
||||||
|
const url = path + "/appearance";
|
||||||
|
return this.getRequest<{
|
||||||
|
myTheme: string | null;
|
||||||
|
schTheme: string | null;
|
||||||
|
avatarMy: string | null;
|
||||||
|
avatarSch: string | null;
|
||||||
|
logoUrl: string | null;
|
||||||
|
}>({ url });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存用户自选主题档(紧凑编码 theme|sideDeep01|gradOn01|sideFollow01);null=跟随学校默认。设置页 fire-and-forget 双写:成功不提示、失败不回滚本地 */
|
||||||
|
saveMyTheme(themeState: string | null) {
|
||||||
|
const url = path + "/saveMyTheme";
|
||||||
|
return this.postRequest({ url, data: { themeState } as any });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存用户自选头像样式("text"|"silhouette");null=跟随学校默认。双写语义同 saveMyTheme */
|
||||||
|
saveMyAvatarStyle(avatarStyle: string | null) {
|
||||||
|
const url = path + "/saveMyAvatarStyle";
|
||||||
|
return this.postRequest({ url, data: { avatarStyle } as any });
|
||||||
|
}
|
||||||
|
|
||||||
savUserRole(info: any) {
|
savUserRole(info: any) {
|
||||||
const url = path + "/user/savUserRole";
|
const url = path + "/user/savUserRole";
|
||||||
return this.postRequest({ url, data: info as any });
|
return this.postRequest({ url, data: info as any });
|
||||||
|
|||||||
@@ -181,6 +181,14 @@
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
/* 应用类型:右侧灰字(来源 BoaAppType.name,与 /apps 分组标题同源) */
|
||||||
|
.app-cmdk-type {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 11.5px;
|
||||||
|
color: #98a2b0;
|
||||||
|
font-weight: 400;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
.app-cmdk-empty {
|
.app-cmdk-empty {
|
||||||
display: none;
|
display: none;
|
||||||
padding: 28px 18px 32px;
|
padding: 28px 18px 32px;
|
||||||
|
|||||||
@@ -208,6 +208,7 @@
|
|||||||
/>
|
/>
|
||||||
<img v-else :src="$utils.appIconPath(item.icon)" class="app-cmdk-img" alt="" />
|
<img v-else :src="$utils.appIconPath(item.icon)" class="app-cmdk-img" alt="" />
|
||||||
<span class="app-cmdk-name">{{ item.name }}</span>
|
<span class="app-cmdk-name">{{ item.name }}</span>
|
||||||
|
<span class="app-cmdk-type" v-if="item.appTypeName">{{ item.appTypeName }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-cmdk-empty" :class="{ 'is-show': !cmdkResult.length }">
|
<div class="app-cmdk-empty" :class="{ 'is-show': !cmdkResult.length }">
|
||||||
@@ -409,9 +410,10 @@ onUnmounted(() => {
|
|||||||
window.removeEventListener("keydown", onCmdkKeydown);
|
window.removeEventListener("keydown", onCmdkKeydown);
|
||||||
closeMsgWs();
|
closeMsgWs();
|
||||||
});
|
});
|
||||||
watch(searchAppText, val => {
|
// 面板已是模态框,输入只驱动面板自身过滤;
|
||||||
|
// 不再 emit("searchChange") —— 背景应用网格保持原样(2026-10-08 用户修订 1)
|
||||||
|
watch(searchAppText, () => {
|
||||||
cmdkStagger.value = false; // 输入过滤时不重播逐条入场
|
cmdkStagger.value = false; // 输入过滤时不重播逐条入场
|
||||||
mittBus.emit("searchChange", val);
|
|
||||||
});
|
});
|
||||||
// ===== 搜索命令面板(2026-10-08 定稿 B 方案)=====
|
// ===== 搜索命令面板(2026-10-08 定稿 B 方案)=====
|
||||||
const refCmdkList = ref<any>();
|
const refCmdkList = ref<any>();
|
||||||
@@ -425,12 +427,21 @@ function vectorIconOf(item: any): string {
|
|||||||
return appiconKeyOf(item?.name || "");
|
return appiconKeyOf(item?.name || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 结果取自 store(由 AppList.reloadAppData 写入),与背景应用网格同源同口径 */
|
/** 结果取自 store.curUserAppList(写入方 = AppList.reloadAppData)。
|
||||||
|
* 它是 BoaAppType 分组结构 [{ id, name, apps }],name 就是应用类型名;
|
||||||
|
* 展开时把类型名挂到每条上供右侧灰字展示。
|
||||||
|
* 注意别用 store.getFlattenAppList —— 它是纯 flatten,会把类型名丢掉 */
|
||||||
const cmdkResult = computed(() => {
|
const cmdkResult = computed(() => {
|
||||||
const all = store.getFlattenAppList;
|
|
||||||
const q = (searchAppText.value || "").trim();
|
const q = (searchAppText.value || "").trim();
|
||||||
if (!q) return all;
|
const out: any[] = [];
|
||||||
return all.filter((x: any) => x.name.indexOf(q) !== -1);
|
(store.curUserAppList || []).forEach((group: any) => {
|
||||||
|
(group.apps || []).forEach((app: any) => {
|
||||||
|
if (!q || (app.name || "").indexOf(q) !== -1) {
|
||||||
|
out.push({ ...app, appTypeName: group.name });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return out;
|
||||||
});
|
});
|
||||||
|
|
||||||
function openSearch() {
|
function openSearch() {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
取值链/取字契约见《设置页修复与默认头像落地方案》§10.1/§10.2;样式全在本文件 <style scoped>(唯一 CSS 源,
|
取值链/取字契约见《设置页修复与默认头像落地方案》§10.1/§10.2;样式全在本文件 <style scoped>(唯一 CSS 源,
|
||||||
不进通道 icons.src.css——通道 CSS 对 UserHome 不可达,内联分发才能消双份漂移,见同方案 §10.4)。
|
不进通道 icons.src.css——通道 CSS 对 UserHome 不可达,内联分发才能消双份漂移,见同方案 §10.4)。
|
||||||
根元素即 .yh-avatar 圆:尺寸内联必须挂圆本身(挂外层 span 会被 flex 拉成椭圆,§12 踩坑)。 */
|
根元素即 .yh-avatar 圆:尺寸内联必须挂圆本身(挂外层 span 会被 flex 拉成椭圆,§12 踩坑)。 */
|
||||||
import { computed } from "vue";
|
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import { pickAvatarText, resolveAvatarStyle } from "@/utils/avatar";
|
import { pickAvatarText, resolveAvatarStyle } from "@/utils/avatar";
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
@@ -22,7 +22,16 @@ const props = withDefaults(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const text = computed(() => (props.src ? "" : pickAvatarText(props.name)));
|
const text = computed(() => (props.src ? "" : pickAvatarText(props.name)));
|
||||||
const style = computed(() => resolveAvatarStyle());
|
/* 外观偏好异步补齐(yh-theme-init 在挂载后拉服务端真源收敛 localStorage 键)会在
|
||||||
|
document 上派发 yh-appearance-updated;tick 自增让 style 依赖失效重读键,三态即时切换(无需刷新)。 */
|
||||||
|
const appearanceTick = ref(0);
|
||||||
|
const onAppearanceUpdated = () => { appearanceTick.value += 1; };
|
||||||
|
onMounted(() => document.addEventListener("yh-appearance-updated", onAppearanceUpdated));
|
||||||
|
onBeforeUnmount(() => document.removeEventListener("yh-appearance-updated", onAppearanceUpdated));
|
||||||
|
const style = computed(() => {
|
||||||
|
appearanceTick.value;
|
||||||
|
return resolveAvatarStyle();
|
||||||
|
});
|
||||||
/** 首字态 = style==="text" 且能取到字(契约 §10.2:二者缺一即剪影,取到字但档位是剪影时绝不能出字) */
|
/** 首字态 = style==="text" 且能取到字(契约 §10.2:二者缺一即剪影,取到字但档位是剪影时绝不能出字) */
|
||||||
const showText = computed(() => style.value === "text" && !!text.value);
|
const showText = computed(() => style.value === "text" && !!text.value);
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -78,12 +78,18 @@ function applyMockState() {
|
|||||||
],
|
],
|
||||||
curUserAppList: [
|
curUserAppList: [
|
||||||
{
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "常用应用",
|
||||||
apps: [
|
apps: [
|
||||||
{ appKey: "100019", appCode: "flow", name: "流程中心" },
|
{ appKey: "100019", appCode: "flow", name: "流程中心" },
|
||||||
{ appKey: "100617", appCode: "notice", name: "通知公告" },
|
{ appKey: "100617", appCode: "notice", name: "通知公告" },
|
||||||
{ appKey: "100611", appCode: "leave", name: "请假" },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "教学应用",
|
||||||
|
apps: [{ appKey: "100611", appCode: "leave", name: "请假" }],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
unreadCount: 5,
|
unreadCount: 5,
|
||||||
curUserSettingInfo: {
|
curUserSettingInfo: {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ type MittType<T = any> = {
|
|||||||
openBschIframePage: IframePageParmas; //打开iframe页面
|
openBschIframePage: IframePageParmas; //打开iframe页面
|
||||||
showLightAppModal: LightAppModal; //打开lightapp模态框
|
showLightAppModal: LightAppModal; //打开lightapp模态框
|
||||||
searchReset: void; //重置搜索框
|
searchReset: void; //重置搜索框
|
||||||
searchChange: string | null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 类型
|
// 类型
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* 本文件由 YschTheme scripts/gen-theme.mjs 从 assets-src/pc/theme-core.js 生成(版本 20261006-2013-75c1d10),勿手改。
|
* 本文件由 YschTheme scripts/gen-theme.mjs 从 assets-src/pc/theme-core.js 生成(版本 20261008-1831-d9db725),勿手改。
|
||||||
* 分发方式:YschTheme `npm run sync` 拷进各端 src/utils/theme.ts(与 ThemeSwitcher.vue 配套,MD5 对齐报告)。
|
* 分发方式:YschTheme `npm run sync` 拷进各端 src/utils/theme.ts(与 ThemeSwitcher.vue 配套,MD5 对齐报告)。
|
||||||
* 运行时档位类名由 /static/js/yh-theme-init.js 在 <head> 内先行挂好,本模块只负责读写与切换。
|
* 运行时档位类名由 /static/js/yh-theme-init.js 在 <head> 内先行挂好,本模块只负责读写与切换。
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-58
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-list-wrapper base-mask">
|
<div class="app-list-wrapper base-mask">
|
||||||
<vuescroll :ops="scrollOps">
|
<vuescroll :ops="scrollOps">
|
||||||
<template v-if="!isSearch" v-for="(item, index) in appList">
|
<template v-for="(item, index) in appList">
|
||||||
<h3 class="app-type-box">{{ item.name }}</h3>
|
<h3 class="app-type-box">{{ item.name }}</h3>
|
||||||
<div
|
<div
|
||||||
:class="{
|
:class="{
|
||||||
@@ -39,42 +39,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!!isSearch">
|
|
||||||
<div class="app-list-box" v-if="searchAppList.length > 0">
|
|
||||||
<template v-for="item in searchAppList">
|
|
||||||
<ContextMenu
|
|
||||||
class="app-container app-container__mask"
|
|
||||||
:title="item.name"
|
|
||||||
@on-change="onMenuChange"
|
|
||||||
@select="onMenuSel"
|
|
||||||
:menu="[
|
|
||||||
{
|
|
||||||
label: '添加到桌面',
|
|
||||||
appId: item.id,
|
|
||||||
id: '1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '新窗口打开',
|
|
||||||
appId: item.id,
|
|
||||||
url: item.webAddr,
|
|
||||||
id: '2',
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<a @click="linkPage(item)">
|
|
||||||
<AppIcon v-if="vectorIconOf(item)" :name="vectorIconOf(item)" scene="tile"
|
|
||||||
:tint="item.iconColor" />
|
|
||||||
<img v-else :src="requireImg('defappicon.png')"
|
|
||||||
v-real-img="$utils.appIconPath(item.icon)" />
|
|
||||||
<div class="app-name">{{ item.name }}</div>
|
|
||||||
</a>
|
|
||||||
</ContextMenu>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="no-search-box" v-else>
|
|
||||||
<img :src="requireImg('no-search-bg.png')" alt="" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</vuescroll>
|
</vuescroll>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -86,11 +50,9 @@ import vuescroll from "vuescroll";
|
|||||||
import { ref, onMounted, onUnmounted, computed, watch } from "vue";
|
import { ref, onMounted, onUnmounted, computed, watch } from "vue";
|
||||||
import BaseApi from "@/api/BaseApi";
|
import BaseApi from "@/api/BaseApi";
|
||||||
import { useDefaultStore } from "@/store";
|
import { useDefaultStore } from "@/store";
|
||||||
import { requireImg } from "@/utils/hook/useImg";
|
|
||||||
import mittBus from "@/utils/mitt";
|
import mittBus from "@/utils/mitt";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { BschLoadTypeEnum, DesktopAppTypeEnum, LinkOpenTypeEnum } from "@/types";
|
import { BschLoadTypeEnum, DesktopAppTypeEnum, LinkOpenTypeEnum } from "@/types";
|
||||||
import { flatten } from "lodash";
|
|
||||||
import UserSettingApi from "@/api/UserSettingApi";
|
import UserSettingApi from "@/api/UserSettingApi";
|
||||||
import { Message } from "view-ui-plus";
|
import { Message } from "view-ui-plus";
|
||||||
import { bschLinkPage, openAppPage } from "@/utils/bschLinkPage";
|
import { bschLinkPage, openAppPage } from "@/utils/bschLinkPage";
|
||||||
@@ -120,15 +82,8 @@ const router = useRouter();
|
|||||||
const store = useDefaultStore();
|
const store = useDefaultStore();
|
||||||
const { $conf, $utils } = useCurrentInstance();
|
const { $conf, $utils } = useCurrentInstance();
|
||||||
|
|
||||||
const searchAppText = ref<string | null>(null),
|
const appList = ref<any[]>([]);
|
||||||
appList = ref<any[]>([]);
|
|
||||||
|
|
||||||
const searchAppList = computed(() => {
|
|
||||||
const allAppList = flatten(appList.value.map(x => x.apps));
|
|
||||||
return allAppList.filter(x => x.name.indexOf(searchAppText.value) !== -1);
|
|
||||||
});
|
|
||||||
|
|
||||||
const isSearch = computed(() => !!searchAppText.value);
|
|
||||||
const compMenuId = computed(() => {
|
const compMenuId = computed(() => {
|
||||||
let menuList = store.curUserMenuList.find(x => x.url == route.path);
|
let menuList = store.curUserMenuList.find(x => x.url == route.path);
|
||||||
return menuList ? menuList.id : -1;
|
return menuList ? menuList.id : -1;
|
||||||
@@ -137,13 +92,9 @@ const compMenuId = computed(() => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
reloadAppData();
|
reloadAppData();
|
||||||
mittBus.emit("searchReset");
|
mittBus.emit("searchReset");
|
||||||
mittBus.on("searchChange", val => {
|
|
||||||
searchAppText.value = val;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
mittBus.emit("searchReset");
|
mittBus.emit("searchReset");
|
||||||
mittBus.off("searchChange");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => store.curRoleUid, reloadAppData);
|
watch(() => store.curRoleUid, reloadAppData);
|
||||||
@@ -237,11 +188,4 @@ function linkPage(item: any) {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.no-search-box {
|
|
||||||
text-align: center;
|
|
||||||
position: relative;
|
|
||||||
top: -50%;
|
|
||||||
-webkit-transform: translateY(40%);
|
|
||||||
transform: translateY(40%);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+24
-5
@@ -1033,6 +1033,18 @@ function keyExists(key: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ThemeState → 服务端紧凑编码 theme|sideDeep01|gradOn01|sideFollow01(与 SchSettings 存储形态同款) */
|
||||||
|
function themeToCompact(s: ThemeState): string {
|
||||||
|
return `${s.theme}|${s.sideDeep ? 1 : 0}|${s.gradOn ? 1 : 0}|${s.sideFollow ? 1 : 0}`;
|
||||||
|
}
|
||||||
|
/** 外观偏好服务端双写(2026-10-08):本地体验不变,fire-and-forget 补写真源——成功不提示、失败 console.warn 不回滚本地 */
|
||||||
|
function syncMyThemeRemote(s: ThemeState | null) {
|
||||||
|
BaseApi.saveMyTheme(s ? themeToCompact(s) : null).catch((e: any) => console.warn("[appearance] saveMyTheme 失败(本地已生效,不回滚):", e));
|
||||||
|
}
|
||||||
|
function syncMyAvatarRemote(style: string | null) {
|
||||||
|
BaseApi.saveMyAvatarStyle(style).catch((e: any) => console.warn("[appearance] saveMyAvatarStyle 失败(本地已生效,不回滚):", e));
|
||||||
|
}
|
||||||
|
|
||||||
// ---- 我的主题(所有人)----
|
// ---- 我的主题(所有人)----
|
||||||
const myCandidate = ref<string>(resolveEffectiveThemeState().theme);
|
const myCandidate = ref<string>(resolveEffectiveThemeState().theme);
|
||||||
const myOrigin = computed<"mine" | "school" | "system">(() => {
|
const myOrigin = computed<"mine" | "school" | "system">(() => {
|
||||||
@@ -1052,17 +1064,20 @@ const myEffective = computed(() => {
|
|||||||
|
|
||||||
function pickMyTheme(key: string) {
|
function pickMyTheme(key: string) {
|
||||||
const cur = resolveEffectiveThemeState();
|
const cur = resolveEffectiveThemeState();
|
||||||
saveThemeState({ ...cur, theme: key } as ThemeState);
|
const state = { ...cur, theme: key } as ThemeState;
|
||||||
|
saveThemeState(state);
|
||||||
|
syncMyThemeRemote(state);
|
||||||
myCandidate.value = key;
|
myCandidate.value = key;
|
||||||
myTick.value += 1;
|
myTick.value += 1;
|
||||||
}
|
}
|
||||||
/** 跟随学校默认 = 删用户自选键(之后回落学校档/系统默认,§3.3) */
|
/** 跟随学校默认 = 删用户自选键(之后回落学校档/系统默认,§3.3);服务端同步置 NULL */
|
||||||
function followSchoolTheme() {
|
function followSchoolTheme() {
|
||||||
try {
|
try {
|
||||||
localStorage.removeItem(THEME_STORAGE_KEY);
|
localStorage.removeItem(THEME_STORAGE_KEY);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
/* 隐私模式静默 */
|
/* 隐私模式静默 */
|
||||||
}
|
}
|
||||||
|
syncMyThemeRemote(null);
|
||||||
myTick.value += 1;
|
myTick.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1170,16 +1185,18 @@ const myAvatarOriginLabel = computed(
|
|||||||
() => ({ mine: "我的选择", school: "学校默认", system: "系统默认" })[myAvatarOrigin.value]
|
() => ({ mine: "我的选择", school: "学校默认", system: "系统默认" })[myAvatarOrigin.value]
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 选样式即写键即生效(saveAvatarStyle 直写 localStorage 无响应式,靠 tick 刷示例与来源标签) */
|
/** 选样式即写键即生效(saveAvatarStyle 直写 localStorage 无响应式,靠 tick 刷示例与来源标签);服务端双写真源 */
|
||||||
function pickMyAvatarStyle(key: AvatarStyle) {
|
function pickMyAvatarStyle(key: AvatarStyle) {
|
||||||
saveAvatarStyle(key);
|
saveAvatarStyle(key);
|
||||||
|
syncMyAvatarRemote(key);
|
||||||
myAvatarCandidate.value = key;
|
myAvatarCandidate.value = key;
|
||||||
myAvatarTick.value += 1;
|
myAvatarTick.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 跟随学校默认 = 删用户自选键(之后回落学校默认/系统默认,与 followSchoolTheme 同构) */
|
/** 跟随学校默认 = 删用户自选键(之后回落学校默认/系统默认,与 followSchoolTheme 同构);服务端同步置 NULL */
|
||||||
function followSchoolAvatar() {
|
function followSchoolAvatar() {
|
||||||
clearAvatarStyle();
|
clearAvatarStyle();
|
||||||
|
syncMyAvatarRemote(null);
|
||||||
myAvatarTick.value += 1;
|
myAvatarTick.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1255,7 +1272,9 @@ const sideDeep = ref(resolveEffectiveThemeState().sideDeep);
|
|||||||
const gradOn = ref(resolveEffectiveThemeState().gradOn);
|
const gradOn = ref(resolveEffectiveThemeState().gradOn);
|
||||||
|
|
||||||
function pickSide(patch: Partial<ThemeState>) {
|
function pickSide(patch: Partial<ThemeState>) {
|
||||||
saveThemeState({ ...resolveEffectiveThemeState(), ...patch } as ThemeState);
|
const state = { ...resolveEffectiveThemeState(), ...patch } as ThemeState;
|
||||||
|
saveThemeState(state);
|
||||||
|
syncMyThemeRemote(state);
|
||||||
myTick.value += 1;
|
myTick.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user