Skip to content

Commit 3c2cefc

Browse files
feat(Components): Create AppSettings And Handle Change Language And Theme
1 parent 13e59a0 commit 3c2cefc

File tree

7 files changed

+190
-5
lines changed

7 files changed

+190
-5
lines changed

src/bootstrap.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import ApiService from '@/services/api.service';
22
import TokenService from '@/services/token.service';
3+
import ThemeService from '@/services/theme.service';
34
import LanguageService from '@/services/language.service';
45

56
import AuthenticateUser from '@/services/middleware/AuthenticateUser';
@@ -14,6 +15,8 @@ if (TokenService.isExist()) {
1415
ApiService.setHeader(HttpHeader.AUTHORIZATION, `Bearer ${TokenService.get()}`);
1516
}
1617

18+
ThemeService.updateDOM();
19+
1720
if (LanguageService.isRtl()) {
1821
import('@/assets/scss/app-rtl.scss');
1922
} else {

src/components/layout/AppSettings.vue

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<template>
2+
<button
3+
type="button"
4+
class="btn btn-sm text-white"
5+
@click="offcanvasShow = true"
6+
>
7+
<i class="bi-gear h4"></i>
8+
</button>
9+
10+
<VOffcanvas v-model="offcanvasShow">
11+
<template #title>{{ $t('Settings') }}</template>
12+
13+
<VForm id="settings-form" class="row">
14+
<div class="col-6">
15+
<VSelect
16+
v-model="language"
17+
:items="languageItems"
18+
item-text="text"
19+
item-key="key"
20+
>
21+
<template #label>{{ $t('Language') }}</template>
22+
</VSelect>
23+
</div>
24+
25+
<div class="col-6">
26+
<VSelect
27+
v-model="theme"
28+
:items="themeItems"
29+
item-text="text"
30+
item-key="key"
31+
>
32+
<template #label>{{ $t('Theme') }}</template>
33+
</VSelect>
34+
</div>
35+
</VForm>
36+
</VOffcanvas>
37+
</template>
38+
39+
<script>
40+
import { ref, watch } from 'vue';
41+
42+
// Components
43+
import VOffcanvas from '@/components/VOffcanvas.vue';
44+
import VForm from '@/components/form/VForm.vue';
45+
import VSelect from '@/components/form/VSelect.vue';
46+
47+
// Services
48+
import LanguageService, { t } from '@/services/language.service';
49+
import ThemeService from '@/services/theme.service';
50+
51+
export default {
52+
name: 'AppSettings',
53+
54+
components: {
55+
VOffcanvas,
56+
VForm,
57+
VSelect
58+
},
59+
60+
setup() {
61+
const offcanvasShow = ref(false);
62+
63+
const language = ref(LanguageService.get());
64+
const languageItems = [
65+
{
66+
key: 'en',
67+
text: 'English'
68+
},
69+
{
70+
key: 'fa',
71+
text: 'فارسی'
72+
}
73+
];
74+
75+
watch(language, (value) => LanguageService.set(value));
76+
77+
const theme = ref(ThemeService.get());
78+
const themeItems = [
79+
{
80+
key: 'light',
81+
text: t('Light')
82+
},
83+
{
84+
key: 'dark',
85+
text: t('Dark')
86+
},
87+
{
88+
key: 'system',
89+
text: t('System')
90+
}
91+
];
92+
93+
watch(theme, (value) => ThemeService.set(value));
94+
95+
return {
96+
offcanvasShow,
97+
98+
language,
99+
languageItems,
100+
101+
theme,
102+
themeItems
103+
};
104+
}
105+
}
106+
</script>

src/components/layout/VHeader.vue

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
<div class="ms-auto">
1717
<slot name="end"></slot>
1818

19+
<AppSettings />
20+
1921
<button
2022
type="button"
2123
class="btn btn-sm text-white"
@@ -28,14 +30,21 @@
2830
</template>
2931

3032
<script>
31-
import { useRouter } from "vue-router";
33+
import { useRouter } from 'vue-router';
34+
35+
// Components
36+
import AppSettings from '@/components/layout/AppSettings.vue';
3237
3338
// Services
34-
import AuthenticationService from "@/services/authentication.service";
39+
import AuthenticationService from '@/services/authentication.service';
3540
3641
export default {
3742
name: 'VHeader',
3843
44+
components: {
45+
AppSettings
46+
},
47+
3948
setup() {
4049
const router = useRouter();
4150

src/locales/en/messages.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export default {
33
"Username": "Username",
44
"Password": "Password",
55
"Submit": "Submit",
6+
"Cancel": "Cancel",
67
"Dashboard": "Dashboard",
78
"Users": "Users",
89
"Authorization Error": "Authorization Error",
@@ -26,5 +27,11 @@ export default {
2627
"Not completed": "Not completed",
2728
"Filter by title": "Filter by title",
2829
"Filter by user": "Filter by user",
29-
"Filter by status": "Filter by status"
30+
"Filter by status": "Filter by status",
31+
"Language": "Language",
32+
"Theme": "Theme",
33+
"Light": "Light",
34+
"Dark": "Dark",
35+
"System": "System",
36+
"Settings": "Settings",
3037
};

src/locales/fa/messages.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export default {
33
"Username": "نام کاریری",
44
"Password": "رمز عبور",
55
"Submit": "ارسال",
6+
"Cancel": "انصراف",
67
"Dashboard": "داشبورد",
78
"Users": "کاربران",
89
"Authorization Error": "خطای دسترسی",
@@ -26,5 +27,11 @@ export default {
2627
"Not completed": "تکمیل نشده",
2728
"Filter by title": "فیلتر بر اساس عنوان",
2829
"Filter by user": "فیلتر بر اساس کاربر",
29-
"Filter by status": "فیلتر بر اساس وضعیت"
30+
"Filter by status": "فیلتر بر اساس وضعیت",
31+
"Language": "زبان",
32+
"Theme": "زمینه",
33+
"Light": "روشن",
34+
"Dark": "تیره",
35+
"System": "سیستم",
36+
"Settings": "تنظیمات",
3037
};

src/services/language.service.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ class LanguageService {
3131
* @returns void
3232
*/
3333
static set(value) {
34-
vueI18N.global.locale = value;
3534
StorageService.set(this.STORAGE_KEY, value);
35+
location.reload();
3636
}
3737

3838
/**

src/services/theme.service.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import StorageService from './storage.service';
2+
3+
class ThemeService {
4+
/**
5+
* Storage key
6+
*
7+
* @returns {String}
8+
*/
9+
static get STORAGE_KEY() {
10+
return 'theme';
11+
}
12+
13+
/**
14+
* Default theme
15+
*
16+
* @returns {String}
17+
*/
18+
static get DEFAULT() {
19+
return 'light';
20+
}
21+
22+
/**
23+
* Set theme
24+
*
25+
* @param {String} value
26+
* @returns void
27+
*/
28+
static set(value) {
29+
StorageService.set(this.STORAGE_KEY, value);
30+
this.updateDOM();
31+
}
32+
33+
/**
34+
* Update dom based on current theme
35+
*
36+
* @returns void
37+
*/
38+
static updateDOM() {
39+
const rootEl = document.documentElement;
40+
rootEl.setAttribute('data-bs-theme', this.get());
41+
}
42+
43+
/**
44+
* Get theme
45+
*
46+
* @returns {String}
47+
*/
48+
static get() {
49+
return StorageService.get(this.STORAGE_KEY) ?? this.DEFAULT;
50+
}
51+
}
52+
53+
export default ThemeService;

0 commit comments

Comments
 (0)