@code-coaching/vuetiful 0.23.1 → 0.24.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 +1 -1
- package/dist/types/components/VBootstrap.vue.d.ts +1 -1
- package/dist/types/components/atoms/VAvatar.vue.d.ts +1 -1
- package/dist/types/components/atoms/VLightSwitch.vue.d.ts +7 -3
- package/dist/types/components/atoms/index.d.ts +13 -13
- package/dist/types/components/index.d.ts +2 -2
- package/dist/types/components/molecules/VAlert.vue.d.ts +1 -1
- package/dist/types/components/molecules/VCodeBlock.vue.d.ts +2 -2
- package/dist/types/components/molecules/VDrawer.vue.d.ts +1 -1
- package/dist/types/components/molecules/VListbox/VListbox.vue.d.ts +1 -1
- package/dist/types/components/molecules/VRail/VRail.vue.d.ts +1 -1
- package/dist/types/components/molecules/VRail/VRailTile.vue.d.ts +1 -1
- package/dist/types/components/molecules/index.d.ts +21 -21
- package/dist/types/directives/clipboard.d.ts +1 -1
- package/dist/types/directives/index.d.ts +1 -1
- package/dist/types/index.d.ts +6 -6
- package/dist/types/props/props.d.ts +1 -1
- package/dist/types/services/dark-mode.service.d.ts +13 -13
- package/dist/types/services/drawer.service.d.ts +1 -1
- package/dist/types/services/index.d.ts +6 -6
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/utils/colors/colors.service.d.ts +69 -0
- package/dist/types/utils/index.d.ts +7 -3
- package/dist/types/utils/theme/theme-switcher.vue.d.ts +1 -1
- package/dist/types/utils/theme/theme.service.d.ts +9 -24
- package/dist/types/utils/theme/themes.d.ts +35 -0
- package/dist/vuetiful.es.mjs +456 -161
- package/dist/vuetiful.umd.js +71 -16
- package/package.json +1 -1
- package/src/assets/main.css +6 -6
- package/src/components/VBootstrap.vue +43 -43
- package/src/components/atoms/VAvatar.test.ts +71 -71
- package/src/components/atoms/VAvatar.vue +22 -23
- package/src/components/atoms/VBadge.test.ts +11 -11
- package/src/components/atoms/VBadge.vue +2 -2
- package/src/components/atoms/VButton.test.ts +82 -82
- package/src/components/atoms/VButton.vue +20 -21
- package/src/components/atoms/VChip.test.ts +11 -11
- package/src/components/atoms/VChip.vue +3 -3
- package/src/components/atoms/VLightSwitch.test.ts +63 -14
- package/src/components/atoms/VLightSwitch.vue +35 -46
- package/src/components/atoms/VRadio/VRadioDescription.test.ts +13 -13
- package/src/components/atoms/VRadio/VRadioDescription.vue +2 -2
- package/src/components/atoms/VRadio/VRadioGroup.test.ts +40 -40
- package/src/components/atoms/VRadio/VRadioGroup.vue +19 -22
- package/src/components/atoms/VRadio/VRadioItem.test.ts +67 -67
- package/src/components/atoms/VRadio/VRadioItem.vue +10 -13
- package/src/components/atoms/VRadio/VRadioLabel.test.ts +13 -13
- package/src/components/atoms/VRadio/VRadioLabel.vue +5 -3
- package/src/components/atoms/VSwitch/VSwitch.test.ts +33 -33
- package/src/components/atoms/VSwitch/VSwitch.vue +24 -27
- package/src/components/atoms/VSwitch/VSwitchDescription.test.ts +13 -13
- package/src/components/atoms/VSwitch/VSwitchDescription.vue +2 -2
- package/src/components/atoms/VSwitch/VSwitchGroup.test.ts +9 -9
- package/src/components/atoms/VSwitch/VSwitchGroup.vue +2 -2
- package/src/components/atoms/VSwitch/VSwitchLabel.test.ts +19 -19
- package/src/components/atoms/VSwitch/VSwitchLabel.vue +2 -2
- package/src/components/atoms/index.ts +13 -13
- package/src/components/index.ts +2 -2
- package/src/components/molecules/VAccordion/VAccordion.test.ts +11 -17
- package/src/components/molecules/VAccordion/VAccordion.vue +3 -3
- package/src/components/molecules/VAccordion/VAccordionItem.test.ts +55 -55
- package/src/components/molecules/VAccordion/VAccordionItem.vue +9 -22
- package/src/components/molecules/VAlert.test.ts +38 -38
- package/src/components/molecules/VAlert.vue +25 -47
- package/src/components/molecules/VCard/VCard.test.ts +25 -25
- package/src/components/molecules/VCard/VCard.vue +13 -15
- package/src/components/molecules/VCard/VCardBody.test.ts +14 -14
- package/src/components/molecules/VCard/VCardBody.vue +4 -8
- package/src/components/molecules/VCard/VCardFooter.test.ts +22 -22
- package/src/components/molecules/VCard/VCardFooter.vue +10 -8
- package/src/components/molecules/VCard/VCardHeader.test.ts +25 -25
- package/src/components/molecules/VCard/VCardHeader.vue +7 -8
- package/src/components/molecules/VCodeBlock.test.ts +63 -63
- package/src/components/molecules/VCodeBlock.vue +27 -34
- package/src/components/molecules/VDrawer.test.ts +5 -5
- package/src/components/molecules/VDrawer.vue +10 -10
- package/src/components/molecules/VListbox/VListbox.test.ts +53 -53
- package/src/components/molecules/VListbox/VListbox.vue +31 -32
- package/src/components/molecules/VListbox/VListboxButton.test.ts +13 -13
- package/src/components/molecules/VListbox/VListboxButton.vue +5 -5
- package/src/components/molecules/VListbox/VListboxItem.test.ts +25 -25
- package/src/components/molecules/VListbox/VListboxItem.vue +7 -8
- package/src/components/molecules/VListbox/VListboxItems.test.ts +14 -14
- package/src/components/molecules/VListbox/VListboxItems.vue +9 -11
- package/src/components/molecules/VListbox/VListboxLabel.test.ts +10 -10
- package/src/components/molecules/VListbox/VListboxLabel.vue +2 -2
- package/src/components/molecules/VPreview.test.ts +26 -26
- package/src/components/molecules/VPreview.vue +22 -27
- package/src/components/molecules/VRail/VRail.test.ts +5 -5
- package/src/components/molecules/VRail/VRail.vue +7 -7
- package/src/components/molecules/VRail/VRailTile.test.ts +26 -28
- package/src/components/molecules/VRail/VRailTile.vue +13 -11
- package/src/components/molecules/VShell.test.ts +5 -5
- package/src/components/molecules/VShell.vue +11 -20
- package/src/components/molecules/VTabs/VTab.test.ts +69 -52
- package/src/components/molecules/VTabs/VTab.vue +13 -17
- package/src/components/molecules/VTabs/VTabPanel.test.ts +8 -8
- package/src/components/molecules/VTabs/VTabPanel.vue +1 -1
- package/src/components/molecules/VTabs/VTabs.test.ts +36 -36
- package/src/components/molecules/VTabs/VTabs.vue +18 -22
- package/src/components/molecules/index.ts +21 -21
- package/src/directives/clipboard.test.ts +9 -9
- package/src/directives/clipboard.ts +2 -2
- package/src/directives/index.ts +1 -1
- package/src/env.d.ts +2 -2
- package/src/index.ts +7 -7
- package/src/props/index.ts +1 -1
- package/src/props/props.ts +44 -44
- package/src/services/dark-mode.service.test.ts +64 -194
- package/src/services/dark-mode.service.ts +35 -54
- package/src/services/drawer.service.test.ts +21 -21
- package/src/services/drawer.service.ts +10 -10
- package/src/services/highlight.service.test.ts +12 -12
- package/src/services/highlight.service.ts +1 -1
- package/src/services/index.ts +6 -6
- package/src/services/rail.service.test.ts +7 -7
- package/src/services/rail.service.ts +2 -2
- package/src/services/settings.service.test.ts +5 -5
- package/src/services/settings.service.ts +1 -1
- package/src/styles/all.css +7 -7
- package/src/styles/elements/buttons.css +1 -1
- package/src/styles/elements/forms.css +7 -7
- package/src/styles/elements.css +13 -13
- package/src/styles/transitions.css +2 -2
- package/src/styles/typography.css +5 -5
- package/src/themes/theme-rocket.css +10 -10
- package/src/themes/theme-sahara.css +13 -13
- package/src/themes/theme-seafoam.css +13 -13
- package/src/themes/theme-seasonal.css +4 -4
- package/src/themes/theme-skeleton.css +7 -7
- package/src/themes/theme-vintage.css +12 -12
- package/src/themes/theme-vuetiful-0.0.1.css +13 -13
- package/src/types/index.ts +46 -46
- package/src/types/tailwind.ts +2 -21
- package/src/utils/colors/colors.service.ts +293 -0
- package/src/utils/index.ts +7 -3
- package/src/utils/platform/platform.service.test.ts +6 -6
- package/src/utils/platform/platform.service.ts +1 -1
- package/src/utils/theme/callback.test.ts +11 -7
- package/src/utils/theme/remove.test.ts +11 -9
- package/src/utils/theme/theme-switcher.vue +43 -49
- package/src/utils/theme/theme.service.test.ts +194 -84
- package/src/utils/theme/theme.service.ts +141 -81
- package/src/utils/theme/themes.ts +122 -0
- package/dist/types/components/index.test.d.ts +0 -1
- package/dist/types/index.test.d.ts +0 -1
- package/dist/types/utils/index.test.d.ts +0 -1
- package/src/components/index.test.ts +0 -10
- package/src/index.test.ts +0 -26
- package/src/utils/index.test.ts +0 -11
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { describe, expect,
|
|
2
|
-
import { usePlatform } from
|
|
1
|
+
import { describe, expect, vi, test } from 'vitest';
|
|
2
|
+
import { usePlatform } from './platform.service';
|
|
3
3
|
|
|
4
4
|
const matchMediaMock = (matches: boolean) => vi.fn(() => ({ matches, onchange: vi.fn() }));
|
|
5
5
|
|
|
6
|
-
describe(
|
|
7
|
-
describe(
|
|
8
|
-
|
|
6
|
+
describe('usePlatform', () => {
|
|
7
|
+
describe('isBrowser', () => {
|
|
8
|
+
test('should return true when window is defined', () => {
|
|
9
9
|
const { isBrowser } = usePlatform();
|
|
10
10
|
expect(isBrowser).toBe(true);
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
test('should return false when window is not defined', () => {
|
|
14
14
|
window = undefined as any;
|
|
15
15
|
const { isBrowser } = usePlatform();
|
|
16
16
|
expect(isBrowser).toBe(false);
|
|
@@ -1,21 +1,25 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, vi, test } from 'vitest';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* No clue why, but when this test is added to theme.service.test.ts, it fails.
|
|
5
5
|
* Running it in isolation works fine.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
describe(
|
|
9
|
-
|
|
10
|
-
const { useTheme } = await import(
|
|
11
|
-
const {
|
|
8
|
+
describe('given there is a callback', () => {
|
|
9
|
+
test('should call the callback', async () => {
|
|
10
|
+
const { useTheme } = await import('./theme.service');
|
|
11
|
+
const { applyTheme, themes } = useTheme();
|
|
12
12
|
|
|
13
13
|
const callbackSpy = vi.fn();
|
|
14
14
|
const callbackFunction = () => {
|
|
15
15
|
callbackSpy();
|
|
16
16
|
};
|
|
17
|
-
|
|
18
|
-
const
|
|
17
|
+
|
|
18
|
+
const newTheme = JSON.parse(JSON.stringify(themes[0]));
|
|
19
|
+
newTheme.name = 'new-theme';
|
|
20
|
+
applyTheme(newTheme, callbackFunction);
|
|
21
|
+
|
|
22
|
+
const link = document.querySelector('#vuetiful-theme') as HTMLLinkElement;
|
|
19
23
|
// @ts-ignore
|
|
20
24
|
link.onload();
|
|
21
25
|
|
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, vi, test } from 'vitest';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* No clue why, but when this test is added to theme.service.test.ts, it fails.
|
|
5
5
|
* Running it in isolation works fine.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
describe(
|
|
9
|
-
|
|
10
|
-
const { useTheme } = await import(
|
|
11
|
-
const {
|
|
8
|
+
describe('given there is no existing theme style tag', () => {
|
|
9
|
+
test('should create a new theme style tag', async () => {
|
|
10
|
+
const { useTheme } = await import('./theme.service');
|
|
11
|
+
const { applyTheme, themes } = useTheme();
|
|
12
12
|
|
|
13
13
|
const removeObject = { remove: () => {} };
|
|
14
|
-
const removeSpy = vi.spyOn(removeObject,
|
|
15
|
-
vi.spyOn(window.document,
|
|
14
|
+
const removeSpy = vi.spyOn(removeObject, 'remove');
|
|
15
|
+
vi.spyOn(window.document, 'getElementById').mockReturnValueOnce(removeObject as any);
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const newTheme = JSON.parse(JSON.stringify(themes[0]));
|
|
18
|
+
newTheme.name = 'new-theme';
|
|
19
|
+
applyTheme(newTheme);
|
|
18
20
|
|
|
19
|
-
const link = document.querySelector(
|
|
21
|
+
const link = document.querySelector('#vuetiful-theme') as HTMLLinkElement;
|
|
20
22
|
// @ts-ignore
|
|
21
23
|
link.onload();
|
|
22
24
|
|
|
@@ -1,80 +1,74 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="vuetiful-theme-switcher">
|
|
3
|
-
<v-button
|
|
4
|
-
:class="`vuetiful-theme-switcher__button ${classButton}`"
|
|
5
|
-
@click="showPopup = !showPopup"
|
|
6
|
-
>
|
|
7
|
-
Theme
|
|
8
|
-
</v-button>
|
|
9
|
-
|
|
10
|
-
<div
|
|
11
|
-
v-if="showPopup"
|
|
12
|
-
class="vuetiful-theme-switcher__popup absolute z-10 mt-1 space-y-4 p-4 shadow-xl rounded-container-token"
|
|
13
|
-
:class="`${background} ${text} ${widthPopup} ${classList}`"
|
|
14
|
-
>
|
|
15
|
-
<section class="flex items-center justify-between">
|
|
16
|
-
<div class="text-lg">Mode</div>
|
|
17
|
-
<v-light-switch />
|
|
18
|
-
</section>
|
|
19
|
-
<nav
|
|
20
|
-
class="vuetiful-theme-switcher__popup-list -m-4 flex flex-col gap-4 overflow-y-auto p-4"
|
|
21
|
-
:class="`${heightList} ${classList}`"
|
|
22
|
-
>
|
|
23
|
-
<v-button
|
|
24
|
-
class="vuetiful-theme-switcher__popup-list-item h-full w-full p-2 text-center capitalize hover:cursor-pointer"
|
|
25
|
-
v-for="(theme, index) in themes"
|
|
26
|
-
:class="`${classListItem} ${chosenTheme === theme.name ? 'variant-filled-surface' : ''}`"
|
|
27
|
-
:key="index"
|
|
28
|
-
@click="loadTheme(theme.name)"
|
|
29
|
-
>
|
|
30
|
-
{{ theme.name }}
|
|
31
|
-
</v-button>
|
|
32
|
-
</nav>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
</template>
|
|
36
|
-
|
|
37
1
|
<script setup lang="ts">
|
|
38
|
-
import { CssClasses, useTheme, VButton, VLightSwitch } from
|
|
39
|
-
import { onMounted, ref } from
|
|
2
|
+
import { CssClasses, useTheme, VButton, VLightSwitch } from '@/index';
|
|
3
|
+
import { onMounted, ref } from 'vue';
|
|
40
4
|
|
|
41
5
|
defineProps({
|
|
42
6
|
background: {
|
|
43
7
|
type: String as () => CssClasses,
|
|
44
|
-
default:
|
|
8
|
+
default: 'bg-surface-50-900-token',
|
|
45
9
|
},
|
|
46
10
|
text: {
|
|
47
11
|
type: String as () => CssClasses,
|
|
48
|
-
default:
|
|
12
|
+
default: 'text-surface-900-50-token',
|
|
49
13
|
},
|
|
50
14
|
|
|
51
15
|
widthPopup: {
|
|
52
16
|
type: String as () => CssClasses,
|
|
53
|
-
default:
|
|
17
|
+
default: 'w-60',
|
|
54
18
|
},
|
|
55
19
|
heightList: {
|
|
56
20
|
type: String as () => CssClasses,
|
|
57
|
-
default:
|
|
21
|
+
default: 'max-h-64 lg:max-h-[500px]',
|
|
58
22
|
},
|
|
59
23
|
|
|
60
24
|
classButton: {
|
|
61
25
|
type: String as () => CssClasses,
|
|
62
|
-
default:
|
|
26
|
+
default: '',
|
|
63
27
|
},
|
|
64
28
|
classList: {
|
|
65
29
|
type: String as () => CssClasses,
|
|
66
|
-
default:
|
|
30
|
+
default: '',
|
|
67
31
|
},
|
|
68
32
|
classListItem: {
|
|
69
33
|
type: String as () => CssClasses,
|
|
70
|
-
default:
|
|
34
|
+
default: '',
|
|
71
35
|
},
|
|
72
36
|
});
|
|
73
37
|
|
|
74
|
-
const {
|
|
38
|
+
const { applyTheme, themes, chosenTheme } = useTheme();
|
|
75
39
|
|
|
76
40
|
const showPopup = ref(false);
|
|
77
|
-
onMounted(() => {
|
|
78
|
-
initializeTheme();
|
|
79
|
-
});
|
|
80
41
|
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<div class="vuetiful-theme-switcher">
|
|
45
|
+
<v-button :class="`vuetiful-theme-switcher__button ${classButton}`" @click="showPopup = !showPopup">
|
|
46
|
+
Theme
|
|
47
|
+
</v-button>
|
|
48
|
+
|
|
49
|
+
<div
|
|
50
|
+
v-if="showPopup"
|
|
51
|
+
class="vuetiful-theme-switcher__popup absolute z-10 mt-1 space-y-4 p-4 shadow-xl rounded-container-token"
|
|
52
|
+
:class="`${background} ${text} ${widthPopup} ${classList}`"
|
|
53
|
+
>
|
|
54
|
+
<section class="flex items-center justify-between">
|
|
55
|
+
<div class="text-lg">Mode</div>
|
|
56
|
+
<v-light-switch />
|
|
57
|
+
</section>
|
|
58
|
+
<nav
|
|
59
|
+
class="vuetiful-theme-switcher__popup-list -m-4 flex flex-col gap-4 overflow-y-auto p-4"
|
|
60
|
+
:class="`${heightList} ${classList}`"
|
|
61
|
+
>
|
|
62
|
+
<v-button
|
|
63
|
+
class="vuetiful-theme-switcher__popup-list-item h-full w-full p-2 text-center capitalize hover:cursor-pointer"
|
|
64
|
+
v-for="(theme, index) in themes"
|
|
65
|
+
:class="`${classListItem} ${chosenTheme.name === theme.name ? 'variant-filled-surface' : ''}`"
|
|
66
|
+
:key="index"
|
|
67
|
+
@click="applyTheme(theme)"
|
|
68
|
+
>
|
|
69
|
+
{{ theme.name }}
|
|
70
|
+
</v-button>
|
|
71
|
+
</nav>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</template>
|
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect,
|
|
2
|
-
import { Theme } from "./theme.service";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
3
2
|
|
|
4
3
|
const localStorageMock = {
|
|
5
4
|
getItem: vi.fn(),
|
|
6
5
|
setItem: vi.fn(),
|
|
7
6
|
};
|
|
8
7
|
|
|
9
|
-
describe(
|
|
8
|
+
describe('useTheme', () => {
|
|
10
9
|
afterEach(() => {
|
|
11
10
|
vi.resetModules();
|
|
12
11
|
});
|
|
13
|
-
describe(
|
|
14
|
-
describe(
|
|
15
|
-
|
|
16
|
-
const platform = await import(
|
|
17
|
-
vi.spyOn(platform,
|
|
12
|
+
describe('initializetheme', () => {
|
|
13
|
+
describe('given not in browser', () => {
|
|
14
|
+
test('should set the theme to the default theme if no theme is stored', async () => {
|
|
15
|
+
const platform = await import('../platform/platform.service');
|
|
16
|
+
vi.spyOn(platform, 'usePlatform').mockReturnValueOnce({
|
|
17
|
+
isBrowser: false,
|
|
18
|
+
});
|
|
18
19
|
|
|
19
|
-
const localStorageSpy = vi.spyOn(window.localStorage,
|
|
20
|
+
const localStorageSpy = vi.spyOn(window.localStorage, 'getItem');
|
|
20
21
|
|
|
21
|
-
const { useTheme } = await import(
|
|
22
|
+
const { useTheme } = await import('./theme.service');
|
|
22
23
|
const { initializeTheme } = useTheme();
|
|
23
24
|
|
|
24
25
|
initializeTheme();
|
|
@@ -27,133 +28,242 @@ describe("useTheme", () => {
|
|
|
27
28
|
});
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
describe(
|
|
31
|
+
describe('given in browser', () => {
|
|
31
32
|
beforeEach(() => {
|
|
32
33
|
window.localStorage = localStorageMock as any;
|
|
33
34
|
});
|
|
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
35
|
|
|
39
|
-
|
|
36
|
+
describe('given no theme is stored', () => {
|
|
37
|
+
test('should set the theme to the default theme', async () => {
|
|
38
|
+
const platform = await import('../platform/platform.service');
|
|
39
|
+
vi.spyOn(platform, 'usePlatform').mockReturnValueOnce({
|
|
40
|
+
isBrowser: true,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const localStorageSpy = vi.spyOn(window.localStorage, 'getItem');
|
|
44
|
+
|
|
45
|
+
const { useTheme } = await import('./theme.service');
|
|
46
|
+
const { initializeTheme, themes, chosenTheme } = useTheme();
|
|
47
|
+
|
|
48
|
+
initializeTheme();
|
|
49
|
+
|
|
50
|
+
expect(localStorageSpy).not.toHaveBeenCalled();
|
|
51
|
+
expect(chosenTheme.value.name).toBe(themes[0].name);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('given a theme is stored', () => {
|
|
56
|
+
test('should set the theme to the stored theme', async () => {
|
|
57
|
+
const platform = await import('../platform/platform.service');
|
|
58
|
+
vi.spyOn(platform, 'usePlatform').mockReturnValueOnce({
|
|
59
|
+
isBrowser: true,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const { useTheme } = await import('./theme.service');
|
|
63
|
+
const { initializeTheme, themes, chosenTheme } = useTheme();
|
|
40
64
|
|
|
41
|
-
const
|
|
42
|
-
|
|
65
|
+
const customTheme = JSON.parse(JSON.stringify(themes[1]));
|
|
66
|
+
customTheme.name = 'rocket';
|
|
43
67
|
|
|
68
|
+
const localStorageSpy = vi.spyOn(window.localStorage, 'getItem');
|
|
69
|
+
|
|
70
|
+
document.cookie = 'vuetiful-theme=rocket';
|
|
44
71
|
initializeTheme();
|
|
45
72
|
|
|
46
|
-
expect(localStorageSpy).
|
|
47
|
-
expect(chosenTheme.value).
|
|
73
|
+
expect(localStorageSpy).not.toHaveBeenCalled();
|
|
74
|
+
expect(chosenTheme.value).toEqual(customTheme);
|
|
48
75
|
});
|
|
49
76
|
});
|
|
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
77
|
|
|
55
|
-
|
|
56
|
-
|
|
78
|
+
describe('given the theme cookie is not a known theme', () => {
|
|
79
|
+
test('should set the theme to the default theme', async () => {
|
|
80
|
+
const platform = await import('../platform/platform.service');
|
|
81
|
+
vi.spyOn(platform, 'usePlatform').mockReturnValueOnce({
|
|
82
|
+
isBrowser: true,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const { useTheme } = await import('./theme.service');
|
|
86
|
+
const { initializeTheme, themes, chosenTheme } = useTheme();
|
|
57
87
|
|
|
58
|
-
const localStorageSpy = vi.spyOn(window.localStorage,
|
|
59
|
-
localStorageSpy.mockReturnValueOnce(THEMES.ROCKET);
|
|
88
|
+
const localStorageSpy = vi.spyOn(window.localStorage, 'getItem');
|
|
60
89
|
|
|
90
|
+
document.cookie = 'vuetiful-theme=not-a-theme';
|
|
61
91
|
initializeTheme();
|
|
62
92
|
|
|
63
|
-
expect(localStorageSpy).
|
|
64
|
-
expect(chosenTheme.value).
|
|
93
|
+
expect(localStorageSpy).not.toHaveBeenCalled();
|
|
94
|
+
expect(chosenTheme.value).toEqual(themes[0]);
|
|
65
95
|
});
|
|
66
96
|
});
|
|
67
97
|
|
|
68
|
-
describe(
|
|
69
|
-
|
|
70
|
-
const platform = await import(
|
|
71
|
-
vi.spyOn(platform,
|
|
98
|
+
describe('given the theme is set to custom', () => {
|
|
99
|
+
test('should set the custom theme from local storage', async () => {
|
|
100
|
+
const platform = await import('../platform/platform.service');
|
|
101
|
+
vi.spyOn(platform, 'usePlatform').mockReturnValueOnce({
|
|
102
|
+
isBrowser: true,
|
|
103
|
+
});
|
|
72
104
|
|
|
73
|
-
const { useTheme } = await import(
|
|
74
|
-
const { initializeTheme,
|
|
105
|
+
const { useTheme } = await import('./theme.service');
|
|
106
|
+
const { initializeTheme, themes, chosenTheme } = useTheme();
|
|
75
107
|
|
|
76
|
-
const localStorageSpy = vi.spyOn(window.localStorage,
|
|
77
|
-
|
|
108
|
+
const localStorageSpy = vi.spyOn(window.localStorage, 'getItem');
|
|
109
|
+
const customTheme = JSON.parse(JSON.stringify(themes[0]));
|
|
110
|
+
customTheme.name = 'custom';
|
|
111
|
+
localStorageSpy.mockReturnValueOnce(JSON.stringify(customTheme));
|
|
78
112
|
|
|
113
|
+
document.cookie = 'vuetiful-theme=custom';
|
|
79
114
|
initializeTheme();
|
|
80
115
|
|
|
81
|
-
expect(localStorageSpy).toHaveBeenCalledWith(
|
|
82
|
-
expect(chosenTheme.value).
|
|
116
|
+
expect(localStorageSpy).toHaveBeenCalledWith('vuetiful-custom-theme');
|
|
117
|
+
expect(chosenTheme.value).toEqual(customTheme);
|
|
83
118
|
});
|
|
119
|
+
|
|
120
|
+
test('should set the default theme if an invalid theme is stored', async () => {
|
|
121
|
+
const platform = await import('../platform/platform.service');
|
|
122
|
+
vi.spyOn(platform, 'usePlatform').mockReturnValueOnce({
|
|
123
|
+
isBrowser: true,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const { useTheme } = await import('./theme.service');
|
|
127
|
+
const { initializeTheme, themes, chosenTheme } = useTheme();
|
|
128
|
+
|
|
129
|
+
const localStorageSpy = vi.spyOn(window.localStorage, 'getItem');
|
|
130
|
+
localStorageSpy.mockReturnValueOnce('not-a-theme');
|
|
131
|
+
|
|
132
|
+
document.cookie = 'vuetiful-theme=custom';
|
|
133
|
+
initializeTheme();
|
|
134
|
+
|
|
135
|
+
expect(localStorageSpy).toHaveBeenCalledWith('vuetiful-custom-theme');
|
|
136
|
+
expect(chosenTheme.value).toEqual(themes[0]);
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('should set the default theme if no theme is stored', async () => {
|
|
140
|
+
const platform = await import('../platform/platform.service');
|
|
141
|
+
vi.spyOn(platform, 'usePlatform').mockReturnValueOnce({
|
|
142
|
+
isBrowser: true,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const { useTheme } = await import('./theme.service');
|
|
146
|
+
const { initializeTheme, themes, chosenTheme } = useTheme();
|
|
147
|
+
|
|
148
|
+
const localStorageSpy = vi.spyOn(window.localStorage, 'getItem');
|
|
149
|
+
localStorageSpy.mockReturnValueOnce(null);
|
|
150
|
+
|
|
151
|
+
document.cookie = 'vuetiful-theme=custom';
|
|
152
|
+
initializeTheme();
|
|
153
|
+
|
|
154
|
+
expect(localStorageSpy).toHaveBeenCalledWith('vuetiful-custom-theme');
|
|
155
|
+
expect(chosenTheme.value).toEqual(themes[0]);
|
|
156
|
+
})
|
|
84
157
|
});
|
|
158
|
+
|
|
85
159
|
});
|
|
86
160
|
});
|
|
87
161
|
|
|
88
|
-
describe(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
162
|
+
describe('registerTheme', () => {
|
|
163
|
+
test('should register a theme', async () => {
|
|
164
|
+
const { useTheme } = await import('./theme.service');
|
|
165
|
+
const { registerTheme, themes } = useTheme();
|
|
166
|
+
|
|
167
|
+
const newTheme = JSON.parse(JSON.stringify(themes[0]));
|
|
168
|
+
newTheme.name = 'new-theme';
|
|
169
|
+
|
|
170
|
+
registerTheme(newTheme);
|
|
171
|
+
expect(themes).toContain(newTheme);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('given the theme is already registered', () => {
|
|
175
|
+
test('should update the theme', async () => {
|
|
176
|
+
const { useTheme } = await import('./theme.service');
|
|
177
|
+
const { registerTheme, themes } = useTheme();
|
|
178
|
+
|
|
179
|
+
const newTheme = JSON.parse(JSON.stringify(themes[0]));
|
|
180
|
+
newTheme.customCss = 'new-custom-css';
|
|
93
181
|
|
|
94
|
-
|
|
182
|
+
registerTheme(newTheme);
|
|
95
183
|
|
|
96
|
-
expect(
|
|
184
|
+
expect(themes.find((theme) => theme.name === newTheme.name)).toEqual(newTheme);
|
|
97
185
|
});
|
|
98
186
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('getThemeFromCookie', () => {
|
|
190
|
+
describe('given there is no cookie', () => {
|
|
191
|
+
test('should return default theme', async () => {
|
|
192
|
+
const { useTheme } = await import('./theme.service');
|
|
193
|
+
const { getThemeFromCookie, themes } = useTheme();
|
|
103
194
|
|
|
104
|
-
|
|
195
|
+
const cookie = '';
|
|
196
|
+
const theme = getThemeFromCookie(cookie);
|
|
105
197
|
|
|
106
|
-
expect(
|
|
198
|
+
expect(theme).toEqual(themes[0]);
|
|
107
199
|
});
|
|
108
200
|
});
|
|
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
201
|
|
|
114
|
-
|
|
115
|
-
|
|
202
|
+
describe('given there is a cookie', () => {
|
|
203
|
+
test('should return the theme', async () => {
|
|
204
|
+
const { useTheme } = await import('./theme.service');
|
|
205
|
+
const { getThemeFromCookie, themes } = useTheme();
|
|
206
|
+
|
|
207
|
+
const cookie = 'vuetiful-theme=rocket';
|
|
116
208
|
|
|
117
|
-
|
|
209
|
+
const theme = getThemeFromCookie(cookie);
|
|
118
210
|
|
|
119
|
-
|
|
211
|
+
const rocketTheme = themes.find((theme) => theme.name === 'rocket');
|
|
212
|
+
expect(theme).toEqual(rocketTheme);
|
|
120
213
|
});
|
|
121
214
|
});
|
|
122
215
|
});
|
|
123
216
|
|
|
124
|
-
describe(
|
|
125
|
-
|
|
126
|
-
const { useTheme } = await import(
|
|
127
|
-
const {
|
|
217
|
+
describe('applyThemeSSR', () => {
|
|
218
|
+
test('should apply the theme', async () => {
|
|
219
|
+
const { useTheme } = await import('./theme.service');
|
|
220
|
+
const { applyThemeSSR, themes } = useTheme();
|
|
128
221
|
|
|
129
|
-
|
|
222
|
+
const theme = themes[0];
|
|
130
223
|
|
|
131
|
-
|
|
224
|
+
const preHtml = '<html><head></head><body></body></html>';
|
|
225
|
+
const html = applyThemeSSR(preHtml, theme);
|
|
226
|
+
|
|
227
|
+
const style = html.includes('id="vuetiful-theme"');
|
|
228
|
+
expect(style).toBe(true);
|
|
229
|
+
const body = html.includes('data-theme="vuetiful"');
|
|
230
|
+
expect(body).toBe(true);
|
|
132
231
|
});
|
|
133
|
-
});
|
|
134
232
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const {
|
|
138
|
-
const { registerTheme } = useTheme();
|
|
233
|
+
test('no customBase, no customHeadings, no gradients, no custom css', async () => {
|
|
234
|
+
const { useTheme } = await import('./theme.service');
|
|
235
|
+
const { applyThemeSSR, themes } = useTheme();
|
|
139
236
|
|
|
140
|
-
const theme
|
|
141
|
-
|
|
237
|
+
const theme = JSON.parse(JSON.stringify(themes[0]));
|
|
238
|
+
theme.fonts.customBase = '';
|
|
239
|
+
theme.fonts.customHeadings = '';
|
|
240
|
+
theme.gradients.light = '';
|
|
241
|
+
theme.gradients.dark = '';
|
|
242
|
+
theme.customCss = '';
|
|
243
|
+
|
|
244
|
+
const preHtml = '<html><head></head><body></body></html>';
|
|
245
|
+
const html = applyThemeSSR(preHtml, theme);
|
|
246
|
+
|
|
247
|
+
const style = html.includes('id="vuetiful-theme"');
|
|
248
|
+
expect(style).toBe(true);
|
|
249
|
+
const body = html.includes('data-theme="vuetiful"');
|
|
250
|
+
expect(body).toBe(true);
|
|
142
251
|
});
|
|
143
|
-
});
|
|
144
252
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const { useTheme } = await import("./theme.service");
|
|
149
|
-
const { saveThemeToStorage } = useTheme();
|
|
253
|
+
test('invalid hex colors', async () => {
|
|
254
|
+
const { useTheme } = await import('./theme.service');
|
|
255
|
+
const { applyThemeSSR, themes } = useTheme();
|
|
150
256
|
|
|
151
|
-
|
|
257
|
+
const theme = JSON.parse(JSON.stringify(themes[0]));
|
|
258
|
+
theme.colors.primary = 'invalid';
|
|
152
259
|
|
|
153
|
-
|
|
260
|
+
const preHtml = '<html><head></head><body></body></html>';
|
|
261
|
+
const html = applyThemeSSR(preHtml, theme);
|
|
154
262
|
|
|
155
|
-
|
|
156
|
-
|
|
263
|
+
const style = html.includes('id="vuetiful-theme"');
|
|
264
|
+
expect(style).toBe(true);
|
|
265
|
+
const body = html.includes('data-theme="vuetiful"');
|
|
266
|
+
expect(body).toBe(true);
|
|
157
267
|
});
|
|
158
268
|
});
|
|
159
269
|
});
|