@code-coaching/vuetiful 0.1.4 → 0.3.0
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/dist/style.css +2 -2
- package/dist/styles/all.css +323 -52
- package/dist/types/components/atoms/VButton.test.d.ts +1 -0
- package/dist/types/components/atoms/VButton.vue.d.ts +6 -72
- package/dist/types/components/index.d.ts +2 -1
- package/dist/types/components/index.test.d.ts +1 -0
- package/dist/types/components/molecules/VRail.vue.d.ts +51 -0
- package/dist/types/components/molecules/VRailTile.vue.d.ts +55 -0
- package/dist/types/components/molecules/VShell.vue.d.ts +78 -0
- package/dist/types/components/molecules/index.d.ts +4 -0
- package/dist/types/directives/clipboard.test.d.ts +1 -0
- package/dist/types/directives/index.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.test.d.ts +1 -0
- package/dist/types/services/index.d.ts +2 -0
- package/dist/types/services/rail.service.d.ts +4 -0
- package/dist/types/utils/code-block/code-block.vue.d.ts +2 -2
- package/dist/types/utils/code-block/highlight.service.test.d.ts +1 -0
- package/dist/types/utils/dark-mode/dark-mode.service.test.d.ts +1 -0
- package/dist/types/utils/dark-mode/dark-mode.vue.d.ts +3 -3
- package/dist/types/utils/index.d.ts +3 -3
- package/dist/types/utils/index.test.d.ts +1 -0
- package/dist/types/utils/platform/platform.service.test.d.ts +1 -0
- package/dist/types/utils/theme/callback.test.d.ts +1 -0
- package/dist/types/utils/theme/remove.test.d.ts +1 -0
- package/dist/types/utils/theme/theme-switcher.vue.d.ts +3 -3
- package/dist/types/utils/theme/{theme.d.ts → theme.service.d.ts} +2 -1
- package/dist/types/utils/theme/theme.service.test.d.ts +1 -0
- package/dist/vuetiful.es.mjs +658 -499
- package/dist/vuetiful.umd.js +13 -20
- package/package.json +8 -2
- package/src/components/atoms/VButton.test.ts +27 -0
- package/src/components/atoms/VButton.vue +19 -73
- package/src/components/index.test.ts +10 -0
- package/src/components/index.ts +2 -1
- package/src/components/molecules/VRail.vue +46 -0
- package/src/components/molecules/VRailTile.vue +75 -0
- package/src/components/molecules/VShell.vue +71 -0
- package/src/components/molecules/index.ts +5 -0
- package/src/directives/clipboard.test.ts +26 -0
- package/src/directives/index.ts +2 -4
- package/src/index.test.ts +26 -0
- package/src/index.ts +1 -1
- package/src/services/index.ts +3 -0
- package/src/services/rail.service.ts +11 -0
- package/src/styles/all.css +9 -6
- package/src/styles/transitions/fade.css +14 -0
- package/src/styles/transitions/slide.css +83 -0
- package/src/styles/transitions.css +2 -0
- package/src/utils/code-block/code-block.vue +1 -1
- package/src/utils/code-block/highlight.service.test.ts +24 -0
- package/src/utils/dark-mode/dark-mode.service.test.ts +234 -0
- package/src/utils/dark-mode/{dark-mode.ts → dark-mode.service.ts} +5 -4
- package/src/utils/dark-mode/dark-mode.vue +1 -1
- package/src/utils/index.test.ts +11 -0
- package/src/utils/index.ts +3 -4
- package/src/utils/platform/platform.service.test.ts +19 -0
- package/src/utils/theme/callback.test.ts +24 -0
- package/src/utils/theme/remove.test.ts +25 -0
- package/src/utils/theme/theme.service.test.ts +160 -0
- package/src/utils/theme/{theme.ts → theme.service.ts} +6 -7
- package/dist/types/constants/MyConstants.d.ts +0 -1
- package/dist/types/constants/index.d.ts +0 -2
- package/src/constants/MyConstants.ts +0 -1
- package/src/constants/index.ts +0 -5
- /package/dist/types/utils/code-block/{highlight.d.ts → highlight.service.d.ts} +0 -0
- /package/dist/types/utils/dark-mode/{dark-mode.d.ts → dark-mode.service.d.ts} +0 -0
- /package/dist/types/utils/platform/{platform.d.ts → platform.service.d.ts} +0 -0
- /package/src/utils/code-block/{highlight.ts → highlight.service.ts} +0 -0
- /package/src/utils/platform/{platform.ts → platform.service.ts} +0 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
const localStorageMock = {
|
|
4
|
+
getItem: vi.fn(),
|
|
5
|
+
setItem: vi.fn(),
|
|
6
|
+
};
|
|
7
|
+
const matchMediaMock = (matches: boolean) => vi.fn(() => ({ matches, onchange: vi.fn() }));
|
|
8
|
+
|
|
9
|
+
describe("useDarkMode", () => {
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.resetModules();
|
|
12
|
+
});
|
|
13
|
+
describe("getModeUserPrefers", () => {
|
|
14
|
+
describe("given not in browser", () => {
|
|
15
|
+
it("should return default modeUserPrefers", async () => {
|
|
16
|
+
const platform = await import("../platform/platform.service");
|
|
17
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: false });
|
|
18
|
+
|
|
19
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
20
|
+
const { getModeUserPrefers } = useDarkMode();
|
|
21
|
+
expect(getModeUserPrefers()).toBe(undefined);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("given in browser", () => {
|
|
26
|
+
describe("given no modeUserPrefers in localStorage", () => {
|
|
27
|
+
it("should return default modeUserPrefers", async () => {
|
|
28
|
+
const platform = await import("../platform/platform.service");
|
|
29
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
30
|
+
|
|
31
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
32
|
+
const { getModeUserPrefers } = useDarkMode();
|
|
33
|
+
|
|
34
|
+
window.localStorage = localStorageMock as any;
|
|
35
|
+
vi.spyOn(window.localStorage, "getItem").mockReturnValueOnce(null);
|
|
36
|
+
|
|
37
|
+
expect(getModeUserPrefers()).toBe(undefined);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("given modeUserPrefers in localStorage", () => {
|
|
41
|
+
it("should return the value", async () => {
|
|
42
|
+
const platform = await import("../platform/platform.service");
|
|
43
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
44
|
+
|
|
45
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
46
|
+
const { getModeUserPrefers } = useDarkMode();
|
|
47
|
+
|
|
48
|
+
window.localStorage = localStorageMock as any;
|
|
49
|
+
vi.spyOn(window.localStorage, "getItem").mockReturnValueOnce("true");
|
|
50
|
+
|
|
51
|
+
expect(getModeUserPrefers()).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("getModeOsPrefers", () => {
|
|
58
|
+
describe("given not in browser", () => {
|
|
59
|
+
it("should return default modeOsPrefers", async () => {
|
|
60
|
+
const platform = await import("../platform/platform.service");
|
|
61
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: false });
|
|
62
|
+
|
|
63
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
64
|
+
const { getModeOsPrefers } = useDarkMode();
|
|
65
|
+
expect(getModeOsPrefers()).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe("given in browser", () => {
|
|
70
|
+
describe("given prefers-color-scheme: light", () => {
|
|
71
|
+
it("should return true", async () => {
|
|
72
|
+
const platform = await import("../platform/platform.service");
|
|
73
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
74
|
+
const localStorageSpy = vi.spyOn(window.localStorage, "setItem");
|
|
75
|
+
|
|
76
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
77
|
+
const { getModeOsPrefers, MODE } = useDarkMode();
|
|
78
|
+
|
|
79
|
+
window.matchMedia = matchMediaMock(MODE.LIGHT) as any;
|
|
80
|
+
expect(getModeOsPrefers()).toBe(MODE.LIGHT);
|
|
81
|
+
expect(localStorageSpy).toHaveBeenCalledWith("modeOsPrefers", "true");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe("given prefers-color-scheme: dark", () => {
|
|
85
|
+
it("should return false", async () => {
|
|
86
|
+
const platform = await import("../platform/platform.service");
|
|
87
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
88
|
+
const localStorageSpy = vi.spyOn(window.localStorage, "setItem");
|
|
89
|
+
|
|
90
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
91
|
+
const { getModeOsPrefers, MODE } = useDarkMode();
|
|
92
|
+
|
|
93
|
+
window.matchMedia = matchMediaMock(MODE.DARK) as any;
|
|
94
|
+
expect(getModeOsPrefers()).toBe(MODE.DARK);
|
|
95
|
+
expect(localStorageSpy).toHaveBeenCalledWith("modeOsPrefers", "false");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("getModeAutoPrefers", () => {
|
|
102
|
+
describe("given not in browser", () => {
|
|
103
|
+
it("should return default modeAutoPrefers", async () => {
|
|
104
|
+
const platform = await import("../platform/platform.service");
|
|
105
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: false });
|
|
106
|
+
|
|
107
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
108
|
+
const { getModeAutoPrefers } = useDarkMode();
|
|
109
|
+
expect(getModeAutoPrefers()).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe("given in browser", () => {
|
|
114
|
+
describe("given no modeUserPrefers in localStorage", () => {
|
|
115
|
+
it("should return default modeAutoPrefers", async () => {
|
|
116
|
+
const platform = await import("../platform/platform.service");
|
|
117
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
118
|
+
|
|
119
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
120
|
+
const { getModeAutoPrefers } = useDarkMode();
|
|
121
|
+
|
|
122
|
+
window.localStorage = localStorageMock as any;
|
|
123
|
+
vi.spyOn(window.localStorage, "getItem").mockReturnValueOnce(null);
|
|
124
|
+
|
|
125
|
+
expect(getModeAutoPrefers()).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe("given modeUserPrefers in localStorage", () => {
|
|
129
|
+
it("should return the value", async () => {
|
|
130
|
+
const platform = await import("../platform/platform.service");
|
|
131
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
132
|
+
|
|
133
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
134
|
+
const { getModeAutoPrefers } = useDarkMode();
|
|
135
|
+
|
|
136
|
+
window.localStorage = localStorageMock as any;
|
|
137
|
+
vi.spyOn(window.localStorage, "getItem").mockReturnValueOnce("true");
|
|
138
|
+
|
|
139
|
+
expect(getModeAutoPrefers()).toBe(true);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("setModeUserPrefers", () => {
|
|
146
|
+
describe("given not in browser", () => {
|
|
147
|
+
it("should set modeUserPrefers", async () => {
|
|
148
|
+
const platform = await import("../platform/platform.service");
|
|
149
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: false });
|
|
150
|
+
vi.spyOn(window.localStorage, "setItem");
|
|
151
|
+
|
|
152
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
153
|
+
const { setModeUserPrefers, modeUserPrefers } = useDarkMode();
|
|
154
|
+
|
|
155
|
+
setModeUserPrefers(true);
|
|
156
|
+
expect(modeUserPrefers.value).toBe(true);
|
|
157
|
+
expect(window.localStorage.setItem).not.toHaveBeenCalled();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("given in browser", () => {
|
|
162
|
+
it("should set modeUserPrefers and localStorage", async () => {
|
|
163
|
+
const platform = await import("../platform/platform.service");
|
|
164
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
165
|
+
|
|
166
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
167
|
+
const { setModeUserPrefers, modeUserPrefers } = useDarkMode();
|
|
168
|
+
|
|
169
|
+
const localStorageSpy = vi.spyOn(window.localStorage, "setItem");
|
|
170
|
+
|
|
171
|
+
setModeUserPrefers(true);
|
|
172
|
+
expect(modeUserPrefers.value).toBe(true);
|
|
173
|
+
expect(localStorageSpy).toHaveBeenCalledWith("modeUserPrefers", "true");
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe("setModeCurrent", () => {
|
|
179
|
+
it("light mode set", async () => {
|
|
180
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
181
|
+
const { setModeCurrent, currentMode, MODE } = useDarkMode();
|
|
182
|
+
|
|
183
|
+
setModeCurrent(MODE.LIGHT);
|
|
184
|
+
expect(currentMode.value).toBe(MODE.LIGHT);
|
|
185
|
+
expect(document.documentElement.classList.contains("dark")).toBe(false);
|
|
186
|
+
});
|
|
187
|
+
it("dark mode set", async () => {
|
|
188
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
189
|
+
const { setModeCurrent, currentMode, MODE } = useDarkMode();
|
|
190
|
+
|
|
191
|
+
setModeCurrent(MODE.DARK);
|
|
192
|
+
expect(currentMode.value).toBe(MODE.DARK);
|
|
193
|
+
expect(document.documentElement.classList.contains("dark")).toBe(true);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe("initializeMode", () => {
|
|
198
|
+
it("should set currentMode", async () => {
|
|
199
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
200
|
+
const { initializeMode, currentMode, getModeAutoPrefers } = useDarkMode();
|
|
201
|
+
|
|
202
|
+
const mode = getModeAutoPrefers();
|
|
203
|
+
initializeMode();
|
|
204
|
+
expect(currentMode.value).toBe(mode);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe("autoModeWatcher", () => {
|
|
209
|
+
describe("given mode changes", () => {
|
|
210
|
+
it("should set modeCurrent", async () => {
|
|
211
|
+
const { useDarkMode } = await import("./dark-mode.service");
|
|
212
|
+
const darkMode = useDarkMode();
|
|
213
|
+
|
|
214
|
+
const mql = {
|
|
215
|
+
matches: true,
|
|
216
|
+
onchange: () => {
|
|
217
|
+
darkMode.setModeCurrent(mql.matches);
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
vi.spyOn(window, "matchMedia").mockReturnValueOnce(mql as any);
|
|
221
|
+
|
|
222
|
+
darkMode.autoModeWatcher();
|
|
223
|
+
|
|
224
|
+
mql.matches = false;
|
|
225
|
+
mql.onchange?.();
|
|
226
|
+
expect(darkMode.currentMode.value).toBe(false);
|
|
227
|
+
|
|
228
|
+
mql.matches = true;
|
|
229
|
+
mql.onchange?.();
|
|
230
|
+
expect(darkMode.currentMode.value).toBe(true);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readonly, Ref, ref } from "vue";
|
|
2
|
-
import { usePlatform } from "../platform/platform";
|
|
2
|
+
import { usePlatform } from "../platform/platform.service";
|
|
3
3
|
|
|
4
4
|
const { isBrowser } = usePlatform();
|
|
5
5
|
|
|
@@ -14,7 +14,8 @@ const modeUserPrefers: Ref<boolean | undefined> = ref(undefined);
|
|
|
14
14
|
|
|
15
15
|
const useDarkMode = () => {
|
|
16
16
|
const getModeOsPrefers = (): boolean => {
|
|
17
|
-
|
|
17
|
+
let prefersLightMode = false;
|
|
18
|
+
if (isBrowser) prefersLightMode = window.matchMedia("(prefers-color-scheme: light)").matches;
|
|
18
19
|
setModeOsPrefers(prefersLightMode);
|
|
19
20
|
return prefersLightMode;
|
|
20
21
|
};
|
|
@@ -30,8 +31,8 @@ const useDarkMode = () => {
|
|
|
30
31
|
const getModeAutoPrefers = (): boolean => {
|
|
31
32
|
const os = getModeOsPrefers();
|
|
32
33
|
const user = getModeUserPrefers();
|
|
33
|
-
|
|
34
|
-
return
|
|
34
|
+
if (user === undefined) return os;
|
|
35
|
+
return user;
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
const setModeOsPrefers = (value: boolean) => {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<script lang="ts">
|
|
27
27
|
import type { CssClasses } from "@/index";
|
|
28
28
|
import { computed, ComputedRef, defineComponent, onMounted } from "vue";
|
|
29
|
-
import { useDarkMode } from "./dark-mode";
|
|
29
|
+
import { useDarkMode } from "./dark-mode.service";
|
|
30
30
|
|
|
31
31
|
export default defineComponent({
|
|
32
32
|
props: {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// test that all exports are defined
|
|
2
|
+
import * as utils from "./index";
|
|
3
|
+
import { describe, it, expect } from "vitest";
|
|
4
|
+
|
|
5
|
+
describe("utils", () => {
|
|
6
|
+
Object.entries(utils).forEach(([key, value]) => {
|
|
7
|
+
it(`${key} is defined`, () => {
|
|
8
|
+
expect(value).toBeDefined();
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
})
|
package/src/utils/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import CodeBlock from "./code-block/code-block.vue";
|
|
2
|
+
import { useDarkMode } from "./dark-mode/dark-mode.service";
|
|
2
3
|
import DarkModeSwitch from "./dark-mode/dark-mode.vue";
|
|
3
|
-
import { useTheme } from "./theme/theme";
|
|
4
4
|
import ThemeSwitcher from "./theme/theme-switcher.vue";
|
|
5
|
-
|
|
6
|
-
import CodeBlock from "./code-block/code-block.vue";
|
|
5
|
+
import { useTheme } from "./theme/theme.service";
|
|
7
6
|
|
|
8
7
|
export { DarkModeSwitch, ThemeSwitcher, useDarkMode, useTheme, CodeBlock };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { usePlatform } from "./platform.service";
|
|
3
|
+
|
|
4
|
+
const matchMediaMock = (matches: boolean) => vi.fn(() => ({ matches, onchange: vi.fn() }));
|
|
5
|
+
|
|
6
|
+
describe("usePlatform", () => {
|
|
7
|
+
describe("isBrowser", () => {
|
|
8
|
+
it("should return true when window is defined", () => {
|
|
9
|
+
const { isBrowser } = usePlatform();
|
|
10
|
+
expect(isBrowser).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should return false when window is not defined", () => {
|
|
14
|
+
window = undefined as any;
|
|
15
|
+
const { isBrowser } = usePlatform();
|
|
16
|
+
expect(isBrowser).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* No clue why, but when this test is added to theme.service.test.ts, it fails.
|
|
5
|
+
* Running it in isolation works fine.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
describe("given there is a callback", () => {
|
|
9
|
+
it("should call the callback", async () => {
|
|
10
|
+
const { useTheme } = await import("./theme.service");
|
|
11
|
+
const { loadTheme } = useTheme();
|
|
12
|
+
|
|
13
|
+
const callbackSpy = vi.fn();
|
|
14
|
+
const callbackFunction = () => {
|
|
15
|
+
callbackSpy();
|
|
16
|
+
};
|
|
17
|
+
loadTheme("vuetiful", callbackFunction);
|
|
18
|
+
const link = document.querySelector("#theme") as HTMLLinkElement;
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
link.onload();
|
|
21
|
+
|
|
22
|
+
expect(callbackSpy).toHaveBeenCalled();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* No clue why, but when this test is added to theme.service.test.ts, it fails.
|
|
5
|
+
* Running it in isolation works fine.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
describe("given there is no existing theme style tag", () => {
|
|
9
|
+
it.only("should create a new theme style tag", async () => {
|
|
10
|
+
const { useTheme } = await import("./theme.service");
|
|
11
|
+
const { loadTheme } = useTheme();
|
|
12
|
+
|
|
13
|
+
const removeObject = { remove: () => {} };
|
|
14
|
+
const removeSpy = vi.spyOn(removeObject, "remove");
|
|
15
|
+
vi.spyOn(window.document, "getElementById").mockReturnValueOnce(removeObject as any);
|
|
16
|
+
|
|
17
|
+
loadTheme("vuetiful");
|
|
18
|
+
|
|
19
|
+
const link = document.querySelector("#theme") as HTMLLinkElement;
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
link.onload();
|
|
22
|
+
|
|
23
|
+
expect(removeSpy).toHaveBeenCalled();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { Theme } from "./theme.service";
|
|
3
|
+
|
|
4
|
+
const localStorageMock = {
|
|
5
|
+
getItem: vi.fn(),
|
|
6
|
+
setItem: vi.fn(),
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
describe("useTheme", () => {
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.resetModules();
|
|
12
|
+
});
|
|
13
|
+
describe("initializetheme", () => {
|
|
14
|
+
describe("given not in browser", () => {
|
|
15
|
+
it("should set the theme to the default theme if no theme is stored", async () => {
|
|
16
|
+
const platform = await import("../platform/platform.service");
|
|
17
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: false });
|
|
18
|
+
|
|
19
|
+
const localStorageSpy = vi.spyOn(window.localStorage, "getItem");
|
|
20
|
+
|
|
21
|
+
const { useTheme } = await import("./theme.service");
|
|
22
|
+
const { initializeTheme } = useTheme();
|
|
23
|
+
|
|
24
|
+
initializeTheme();
|
|
25
|
+
|
|
26
|
+
expect(localStorageSpy).not.toHaveBeenCalled();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("given in browser", () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
window.localStorage = localStorageMock as any;
|
|
33
|
+
});
|
|
34
|
+
describe("given no theme is stored", () => {
|
|
35
|
+
it("should set the theme to the default theme", async () => {
|
|
36
|
+
const platform = await import("../platform/platform.service");
|
|
37
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
38
|
+
|
|
39
|
+
const localStorageSpy = vi.spyOn(window.localStorage, "getItem");
|
|
40
|
+
|
|
41
|
+
const { useTheme } = await import("./theme.service");
|
|
42
|
+
const { initializeTheme, THEMES, chosenTheme } = useTheme();
|
|
43
|
+
|
|
44
|
+
initializeTheme();
|
|
45
|
+
|
|
46
|
+
expect(localStorageSpy).toHaveBeenCalledWith("vuetiful-theme");
|
|
47
|
+
expect(chosenTheme.value).toBe(THEMES.VUETIFUL);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe("given a theme is stored", () => {
|
|
51
|
+
it("should set the theme to the stored theme", async () => {
|
|
52
|
+
const platform = await import("../platform/platform.service");
|
|
53
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
54
|
+
|
|
55
|
+
const { useTheme } = await import("./theme.service");
|
|
56
|
+
const { initializeTheme, THEMES, chosenTheme } = useTheme();
|
|
57
|
+
|
|
58
|
+
const localStorageSpy = vi.spyOn(window.localStorage, "getItem");
|
|
59
|
+
localStorageSpy.mockReturnValueOnce(THEMES.ROCKET);
|
|
60
|
+
|
|
61
|
+
initializeTheme();
|
|
62
|
+
|
|
63
|
+
expect(localStorageSpy).toHaveBeenCalledWith("vuetiful-theme");
|
|
64
|
+
expect(chosenTheme.value).toBe(THEMES.ROCKET);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("given the theme is not valid", () => {
|
|
69
|
+
it("should set the theme to the default theme", async () => {
|
|
70
|
+
const platform = await import("../platform/platform.service");
|
|
71
|
+
vi.spyOn(platform, "usePlatform").mockReturnValueOnce({ isBrowser: true });
|
|
72
|
+
|
|
73
|
+
const { useTheme } = await import("./theme.service");
|
|
74
|
+
const { initializeTheme, THEMES, chosenTheme } = useTheme();
|
|
75
|
+
|
|
76
|
+
const localStorageSpy = vi.spyOn(window.localStorage, "getItem");
|
|
77
|
+
localStorageSpy.mockReturnValueOnce("invalid-theme");
|
|
78
|
+
|
|
79
|
+
initializeTheme();
|
|
80
|
+
|
|
81
|
+
expect(localStorageSpy).toHaveBeenCalledWith("vuetiful-theme");
|
|
82
|
+
expect(chosenTheme.value).toBe(THEMES.VUETIFUL);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("loadTheme", () => {
|
|
89
|
+
describe("given theme name exists in themes", () => {
|
|
90
|
+
it("should set the theme to the given theme", async () => {
|
|
91
|
+
const { useTheme } = await import("./theme.service");
|
|
92
|
+
const { loadTheme, THEMES, chosenTheme } = useTheme();
|
|
93
|
+
|
|
94
|
+
loadTheme(THEMES.ROCKET);
|
|
95
|
+
|
|
96
|
+
expect(chosenTheme.value).toBe(THEMES.ROCKET);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe("given theme name does not exist in themes", () => {
|
|
100
|
+
it("should set the theme to the default theme", async () => {
|
|
101
|
+
const { useTheme } = await import("./theme.service");
|
|
102
|
+
const { loadTheme, THEMES, chosenTheme } = useTheme();
|
|
103
|
+
|
|
104
|
+
loadTheme("invalid-theme");
|
|
105
|
+
|
|
106
|
+
expect(chosenTheme.value).toBe(THEMES.VUETIFUL);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe("given default theme is not in themes", () => {
|
|
110
|
+
it("should set the theme to the first theme in the themes object", async () => {
|
|
111
|
+
const { useTheme } = await import("./theme.service");
|
|
112
|
+
const { loadTheme, THEMES, chosenTheme, overwriteThemes, themes } = useTheme();
|
|
113
|
+
|
|
114
|
+
const theme: Theme = { name: "fake theme", url: "" };
|
|
115
|
+
overwriteThemes([themes.value[1], theme]);
|
|
116
|
+
|
|
117
|
+
loadTheme("invalid-theme");
|
|
118
|
+
|
|
119
|
+
expect(chosenTheme.value).toBe(themes.value[0].name);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe("registerAllBuiltInThemes", () => {
|
|
125
|
+
it("should register all built in themes", async () => {
|
|
126
|
+
const { useTheme } = await import("./theme.service");
|
|
127
|
+
const { registerAllBuiltInThemes, THEMES, themes } = useTheme();
|
|
128
|
+
|
|
129
|
+
registerAllBuiltInThemes();
|
|
130
|
+
|
|
131
|
+
expect(themes.value).toHaveLength(Object.keys(THEMES).length);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe("registerTheme", () => {
|
|
136
|
+
it("should register a theme", async () => {
|
|
137
|
+
const { useTheme } = await import("./theme.service");
|
|
138
|
+
const { registerTheme } = useTheme();
|
|
139
|
+
|
|
140
|
+
const theme: Theme = { name: "fake theme", url: "" };
|
|
141
|
+
expect(registerTheme(theme.name, "")).toEqual(theme);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("saveThemeToStorage", () => {
|
|
146
|
+
describe("given the theme does not exist", () => {
|
|
147
|
+
it("should not save the theme to storage", async () => {
|
|
148
|
+
const { useTheme } = await import("./theme.service");
|
|
149
|
+
const { saveThemeToStorage } = useTheme();
|
|
150
|
+
|
|
151
|
+
const localStorageSpy = vi.spyOn(window.localStorage, "setItem");
|
|
152
|
+
|
|
153
|
+
saveThemeToStorage("invalid-theme");
|
|
154
|
+
|
|
155
|
+
expect(localStorageSpy).not.toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { readonly, Ref, ref } from "vue";
|
|
2
|
-
import { usePlatform } from "../platform/platform";
|
|
2
|
+
import { usePlatform } from "../platform/platform.service";
|
|
3
3
|
|
|
4
4
|
const { isBrowser } = usePlatform();
|
|
5
5
|
|
|
6
|
-
interface Theme {
|
|
6
|
+
export interface Theme {
|
|
7
7
|
name: string;
|
|
8
8
|
url: string;
|
|
9
9
|
}
|
|
@@ -38,7 +38,7 @@ const defaultTheme = THEMES.VUETIFUL;
|
|
|
38
38
|
const chosenTheme = ref(defaultTheme);
|
|
39
39
|
|
|
40
40
|
const useTheme = () => {
|
|
41
|
-
const
|
|
41
|
+
const saveThemeToStorage = (name: string): void => {
|
|
42
42
|
const theme = themes.value.find((t) => t.name === name);
|
|
43
43
|
if (!theme) return;
|
|
44
44
|
|
|
@@ -74,10 +74,8 @@ const useTheme = () => {
|
|
|
74
74
|
link.rel = "stylesheet";
|
|
75
75
|
link.onload = () => {
|
|
76
76
|
if (existingStyle) existingStyle.remove();
|
|
77
|
-
|
|
78
|
-
if (callback)
|
|
79
|
-
callback();
|
|
80
|
-
}
|
|
77
|
+
saveThemeToStorage(theme.name);
|
|
78
|
+
if (callback) callback();
|
|
81
79
|
};
|
|
82
80
|
|
|
83
81
|
const head = document.querySelector("head");
|
|
@@ -102,6 +100,7 @@ const useTheme = () => {
|
|
|
102
100
|
|
|
103
101
|
initializeTheme,
|
|
104
102
|
loadTheme,
|
|
103
|
+
saveThemeToStorage,
|
|
105
104
|
|
|
106
105
|
THEMES,
|
|
107
106
|
overwriteThemes,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const MAGIC_NUM = 100;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const MAGIC_NUM = 100
|
package/src/constants/index.ts
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|