Skip to content

Commit c003cd6

Browse files
committed
feat: implement a working at a glance widget configurer
1 parent bb6a4ce commit c003cd6

File tree

12 files changed

+99
-10
lines changed

12 files changed

+99
-10
lines changed

src/components/general/layout/PagesSelector.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const { page } = defineProps<{
88
"page": RouteType;
99
}>();
1010
11+
// Do not import other page codes unless they are selected
1112
const Library = defineAsyncComponent(() => import("@/components/library/Library.vue"));
1213
const Settings = defineAsyncComponent(() => import("@/components/settings/Settings.vue"));
1314
const AddInstance = defineAsyncComponent(() => import("@/components/add-instance/AddInstance.vue"));

src/components/general/misc/ConfigSyncer.vue

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
<script setup lang="ts">
22
import { writeTextFile } from "@tauri-apps/plugin-fs";
33
import { useIntervalFn } from "@vueuse/core";
4-
import { ref } from "vue";
4+
import { inject, ref, watchEffect } from "vue";
55
6+
import { ApplicationNamespace, GlobalStatesContextKey } from "@/constants/application.ts";
67
import Configs from "@/lib/configs";
78
import Errors from "@/lib/errors";
89
import GlobalStateHelpers from "@/lib/global-state-helpers";
910
import { log } from "@/lib/logging/scopes/log.ts";
1011
import type { ConfigType } from "@/types/application/config.type.ts";
12+
import type { ContextGlobalStatesType } from "@/types/application/global-states.type.ts";
13+
14+
const globalStates = inject<ContextGlobalStatesType>(GlobalStatesContextKey);
1115
1216
const syncing = ref<boolean>(false);
1317
@@ -71,7 +75,21 @@ async function handleConfigSync(): Promise<void> {
7175
}
7276
7377
// Trigger config sync every 30 seconds
74-
useIntervalFn(handleConfigSync, 30_000);
78+
const { pause, resume } = useIntervalFn(handleConfigSync, 30_000);
79+
80+
// Make the config sync function accessible to everyone
81+
window[ApplicationNamespace].__internals.syncConfig = handleConfigSync;
82+
83+
// Use auto config sync only if user has enabled it
84+
watchEffect(() => {
85+
if (globalStates?.misc?.autoConfigSync) {
86+
pause();
87+
88+
return;
89+
}
90+
91+
resume();
92+
});
7593
</script>
7694

7795
<template>

src/components/home/glance/AtAGlance.vue

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
<script setup lang="ts">
2-
import { computed, inject } from "vue";
2+
import { onClickOutside, useDebounceFn } from "@vueuse/core";
3+
import { computed, inject, nextTick, ref, useTemplateRef } from "vue";
34
45
import { ApplicationNamespace, GlobalStatesContextKey } from "@/constants/application.ts";
6+
import Configs from "@/lib/configs";
57
import General from "@/lib/general";
8+
import GlobalStateHelpers from "@/lib/global-state-helpers";
69
import { log } from "@/lib/logging/scopes/log.ts";
710
import type { ContextGlobalStatesType } from "@/types/application/global-states.type.ts";
811
import type { AtAGlanceType } from "@/types/ui/at-a-glance.type.ts";
912
1013
const globalStates = inject<ContextGlobalStatesType>(GlobalStatesContextKey);
1114
15+
const target = useTemplateRef<HTMLDivElement>("target");
16+
17+
const editing = ref<keyof AtAGlanceType | undefined>(undefined);
18+
1219
const currentGlance = computed((): AtAGlanceType => {
1320
const configGlance: {
1421
"title" : string | null | undefined;
@@ -39,24 +46,73 @@ const currentGlance = computed((): AtAGlanceType => {
3946
"subtitle": configGlance.subtitle,
4047
};
4148
});
49+
50+
const handleEdit = useDebounceFn(async (event: Event): Promise<void> => {
51+
const target = event?.target as HTMLInputElement;
52+
const value = target?.value;
53+
const key: keyof AtAGlanceType | undefined = editing.value;
54+
55+
if (!key || !value || !globalStates) {
56+
return;
57+
}
58+
59+
log.debug(`Setting the global 'At a Glance - ${key}' value to: ${value}`);
60+
GlobalStateHelpers.change("layout", {
61+
...globalStates.layout,
62+
"atAGlance": {
63+
...currentGlance.value,
64+
[key]: value,
65+
},
66+
});
67+
68+
// Global states didn't change yet - Vue batches them
69+
await nextTick();
70+
// Global states have changed, now we can sync the config file
71+
await Configs.sync();
72+
}, 300);
73+
74+
onClickOutside(target, () => {
75+
editing.value = undefined;
76+
});
4277
</script>
4378

4479
<template>
4580
<div
4681
id="__home-page__header-wrapper"
82+
ref="target"
4783
class="flex flex-col gap-1 pt-4"
4884
>
4985
<div
5086
id="__home-page__header-title"
51-
class="w-fit cursor-pointer border border-transparent rounded-md p-2 text-3xl leading-none transition-[background-color,border-color] hover:border-[theme(colors.white/.3)] hover:bg-[theme(colors.white/.1)]"
87+
@click="() => editing = 'title'"
88+
class="relative w-fit cursor-pointer break-all border border-transparent rounded-md p-2 text-3xl leading-none transition-[background-color,border-color] hover:border-[theme(colors.white/.3)] hover:bg-[theme(colors.white/.1)]"
5289
>
53-
{{ currentGlance.title }}
90+
<p id="__home-page__header-title-text">
91+
{{ currentGlance.title }}
92+
</p>
93+
<input
94+
v-if="editing === 'title'"
95+
id="__home-page__header-title-editor-wrapper"
96+
class="absolute left-0 top-14"
97+
:value="currentGlance.title"
98+
@input="handleEdit"
99+
/>
54100
</div>
55101
<div
56102
id="__home-page__header-subtitle"
57-
class="w-fit cursor-pointer border border-transparent rounded-md p-2 text-lg text-neutral-300 leading-none transition-[background-color,border-color] hover:border-[theme(colors.white/.3)] hover:bg-[theme(colors.white/.1)]"
103+
@click="() => editing = 'subtitle'"
104+
class="relative w-fit cursor-pointer break-all border border-transparent rounded-md p-2 text-lg text-neutral-300 leading-none transition-[background-color,border-color] hover:border-[theme(colors.white/.3)] hover:bg-[theme(colors.white/.1)]"
58105
>
59-
{{ currentGlance.subtitle }}
106+
<p id="__home-page__header-subtitle-text">
107+
{{ currentGlance.subtitle }}
108+
</p>
109+
<input
110+
v-if="editing === 'subtitle'"
111+
id="__home-page__header-title-editor-wrapper"
112+
class="absolute left-0 top-10"
113+
:value="currentGlance.subtitle"
114+
@input="handleEdit"
115+
/>
60116
</div>
61117
</div>
62118
</template>

src/declarations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ declare global {
8989
permissions: Array<PermissionType>,
9090
extension: string
9191
) => Promise<Array<boolean>>;
92+
// Syncs the config file using global states
93+
"syncConfig" : () => Promise<void>;
9294
// Platform-specific delimiter obtained by a single invoke of Tauri 'join'
9395
"joinDelimiter" : string;
9496
// Application's config state before launcher initialization

src/lib/configs/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ApplicationNamespace } from "@/constants/application.ts";
12
import { getConfigFile } from "@/lib/configs/scopes/get-config-file.ts";
23
import { getDefaultConfig } from "@/lib/configs/scopes/get-default-config.ts";
34
import { getSafeConfigFile } from "@/lib/configs/scopes/get-safe-config-file.ts";
@@ -8,4 +9,7 @@ export default {
89
"getDefault": getDefaultConfig,
910
"getSafe" : getSafeConfigFile,
1011
"initialize": initializeConfigFile,
12+
"sync" : async (): Promise<void> => {
13+
return window[ApplicationNamespace].__internals.syncConfig();
14+
},
1115
} as const;

src/lib/configs/scopes/get-config-file.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ const defaultConfig: ConfigType = {
3838
"icon" : "",
3939
},
4040
"misc": {
41-
"enableDiscordRPC" : false,
4241
"showAfterExtensionsInitialization": false,
42+
"enableDiscordRPC" : false,
43+
"autoConfigSync" : false,
4344
},
4445
};
4546

@@ -169,6 +170,7 @@ beforeEach(() => {
169170
"default": {
170171
"checkIsPortable" : async (): Promise<boolean> => false,
171172
"getBaseDirectory": async (): Promise<string> => "",
173+
"cachedJoin" : (): string => "",
172174
},
173175
};
174176
});

src/lib/configs/scopes/get-default-config.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ test(testName, async () => {
4343
"icon" : "",
4444
},
4545
"misc": {
46-
"enableDiscordRPC" : false,
4746
"showAfterExtensionsInitialization": false,
47+
"enableDiscordRPC" : false,
48+
"autoConfigSync" : false,
4849
},
4950
};
5051

src/lib/configs/scopes/get-default-config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ export async function getDefaultConfig(): Promise<ConfigType> {
5454
"icon" : "",
5555
},
5656
"misc": {
57-
"enableDiscordRPC" : false,
5857
"showAfterExtensionsInitialization": false,
58+
"enableDiscordRPC" : false,
59+
"autoConfigSync" : false,
5960
},
6061
};
6162
}

src/lib/global-state-helpers/scopes/get-default-global-states.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export function getDefaultGlobalStates(): GlobalStatesType {
7373
"misc": {
7474
"showAfterExtensionsInitialization": false,
7575
"enableDiscordRPC" : false,
76+
"autoConfigSync" : false,
7677
},
7778
"minecraft": {
7879
"windowHeight": 480,

src/lib/globals/scopes/declare-window.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export function declareWindow(): void {
4141
"getInstanceStates" : placeholderFunction as () => InstanceStatesType,
4242
"changeInstanceStates": placeholderFunction,
4343
"requestPermissions" : placeholderFunction as () => Promise<Array<boolean>>,
44+
"syncConfig" : placeholderFunction as () => Promise<void>,
4445
"joinDelimiter" : "",
4546
"initialConfig" : {} as ConfigType,
4647
"initialPortable" : false,

0 commit comments

Comments
 (0)