@appscode/design-system 1.0.43-alpha.21 → 1.0.43-alpha.211

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.
Files changed (132) hide show
  1. package/base/utilities/_all.scss +7 -0
  2. package/base/utilities/_customize-bulma.scss +191 -0
  3. package/base/utilities/_default.scss +313 -67
  4. package/base/utilities/_derived-variables.scss +6 -1
  5. package/base/utilities/_grid.scss +29 -0
  6. package/base/utilities/_initial-variables.scss +27 -17
  7. package/base/utilities/_mixin.scss +1 -17
  8. package/base/utilities/_typography.scss +18 -14
  9. package/base/utilities/dark-theme.scss +9 -145
  10. package/components/_ac-accordion.scss +14 -5
  11. package/components/_ac-alert-box.scss +41 -7
  12. package/components/_ac-card.scss +48 -10
  13. package/components/_ac-code-highlight.scss +5 -1
  14. package/components/_ac-content-layout.scss +2 -2
  15. package/components/_ac-drag.scss +2 -0
  16. package/components/_ac-input.scss +64 -23
  17. package/components/_ac-modal.scss +1 -1
  18. package/components/_ac-multi-select.scss +247 -9
  19. package/components/_ac-options.scss +24 -9
  20. package/components/_ac-select-box.scss +13 -3
  21. package/components/_ac-table.scss +7 -5
  22. package/components/_ac-tabs.scss +46 -5
  23. package/components/_ac-terminal.scss +270 -0
  24. package/components/_all.scss +27 -0
  25. package/components/_app-drawer.scss +2 -2
  26. package/components/_breadcumb.scss +2 -0
  27. package/components/_buttons.scss +50 -37
  28. package/components/_card-body-wrapper.scss +2 -2
  29. package/components/_dashboard-header.scss +32 -0
  30. package/components/_direct-deploy.scss +69 -0
  31. package/components/_go-to-top.scss +1 -1
  32. package/components/_graph.scss +45 -0
  33. package/components/_image-upload.scss +5 -3
  34. package/components/_left-sidebar-menu.scss +124 -73
  35. package/components/_monaco-editor.scss +1 -1
  36. package/components/_navbar.scss +170 -10
  37. package/components/_overview-info.scss +3 -3
  38. package/components/_pagination.scss +8 -0
  39. package/components/_payment-card.scss +10 -1
  40. package/components/_preview-modal.scss +18 -5
  41. package/components/_pricing-table.scss +1 -1
  42. package/components/_progress-bar.scss +4 -4
  43. package/components/_subscription-card.scss +11 -4
  44. package/components/_table-of-content.scss +1 -1
  45. package/components/_tfa.scss +69 -0
  46. package/components/_transitions.scss +261 -0
  47. package/components/_wizard.scss +16 -3
  48. package/components/bbum/_all.scss +9 -0
  49. package/components/bbum/_card-team.scss +1 -1
  50. package/components/bbum/_information-center.scss +15 -1
  51. package/components/bbum/_sign-up-notification.scss +1 -1
  52. package/components/bbum/_single-post-preview.scss +2 -2
  53. package/components/bbum/_user-profile.scss +2 -3
  54. package/components/ui-builder/_ui-builder.scss +76 -1
  55. package/components/ui-builder/_vue-open-api.scss +104 -0
  56. package/layouts/_all.scss +2 -0
  57. package/layouts/_code-preview.scss +5 -2
  58. package/main.scss +6 -54
  59. package/package.json +2 -7
  60. package/plugins/theme.js +4 -0
  61. package/plugins/time-convert.js +49 -0
  62. package/plugins/vue-toaster.js +3 -0
  63. package/vue-components/v2/banner/Banner.vue +2 -2
  64. package/vue-components/v2/breadcrumbs/Breadcrumb.vue +97 -0
  65. package/vue-components/v2/button/Button.vue +5 -0
  66. package/vue-components/v2/button/DownloadBtn.vue +45 -0
  67. package/vue-components/v2/card/Card.vue +1 -0
  68. package/vue-components/v2/card/PaymentCards.vue +11 -2
  69. package/vue-components/v2/content/ContentTable.vue +12 -7
  70. package/vue-components/v2/editor/Editor.vue +43 -24
  71. package/vue-components/v2/editor/FilteredFileEditor.vue +189 -0
  72. package/vue-components/v2/editor/MonacoEditor.vue +125 -0
  73. package/vue-components/v2/editor/ResourceKeyValueEditor.vue +209 -0
  74. package/vue-components/v2/form-fields/Input.vue +1 -1
  75. package/vue-components/v2/loaders/ResourceLoader.vue +101 -0
  76. package/vue-components/v2/loaders/SidebarLoader.vue +43 -0
  77. package/vue-components/v2/modal/Modal.vue +38 -4
  78. package/vue-components/v2/modals/DeleteConfirmationModal.vue +79 -0
  79. package/vue-components/v2/modals/JsonShowModal.vue +12 -2
  80. package/vue-components/v2/navbar/Appdrawer.vue +10 -9
  81. package/vue-components/v2/navbar/ThemeMode.vue +50 -44
  82. package/vue-components/v2/navbar/User.vue +229 -17
  83. package/vue-components/v2/notification/Notification.vue +101 -0
  84. package/vue-components/v2/notification/NotificationItem.vue +44 -0
  85. package/vue-components/v2/pagination/Pagination.vue +16 -3
  86. package/vue-components/v2/preloader/Preloader.vue +5 -5
  87. package/vue-components/v2/sidebar/ClusterSwitcher.vue +126 -0
  88. package/vue-components/v2/sidebar/SidebarItem.vue +23 -1
  89. package/vue-components/v2/sidebar/SidebarItemWithDropDown.vue +19 -20
  90. package/vue-components/v2/tab/TabItem.vue +1 -1
  91. package/vue-components/v2/table/Table.vue +44 -8
  92. package/vue-components/v2/table/TableRow.vue +12 -2
  93. package/vue-components/v2/table/table-cell/CellValue.vue +33 -4
  94. package/vue-components/v2/table/table-cell/GenericCell.vue +56 -0
  95. package/vue-components/v2/table/table-cell/ObjectCell.vue +4 -1
  96. package/vue-components/v2/tabs/EditorTabs.vue +1 -1
  97. package/vue-components/v3/button/Button.vue +6 -1
  98. package/vue-components/v3/content/ContentTable.vue +17 -2
  99. package/vue-components/v3/editor/Editor.vue +42 -33
  100. package/vue-components/v3/editor/FilteredFileEditor.vue +186 -0
  101. package/vue-components/v3/editor/MonacoEditor.vue +131 -0
  102. package/vue-components/v3/editor/ResourceKeyValueEditor.vue +125 -0
  103. package/vue-components/v3/form/Form.vue +63 -0
  104. package/vue-components/v3/form-fields/Input.vue +11 -10
  105. package/vue-components/v3/header/HeaderItem.vue +5 -0
  106. package/vue-components/v3/header/HeaderItems.vue +5 -0
  107. package/vue-components/v3/loaders/ResourceLoader.vue +83 -0
  108. package/vue-components/v3/loaders/SidebarLoader.vue +34 -0
  109. package/vue-components/v3/long-running-tasks/LongRunningTaskItem.vue +92 -0
  110. package/vue-components/v3/modal/Modal.vue +38 -6
  111. package/vue-components/v3/modals/DeleteConfirmationModal.vue +85 -0
  112. package/vue-components/v3/modals/JsonShowModal.vue +25 -16
  113. package/vue-components/v3/modals/LongRunningTasksModal.vue +337 -0
  114. package/vue-components/v3/navbar/Appdrawer.vue +12 -7
  115. package/vue-components/v3/navbar/ThemeMode.vue +49 -47
  116. package/vue-components/v3/navbar/User.vue +242 -18
  117. package/vue-components/v3/notification/Notification.vue +98 -0
  118. package/vue-components/v3/notification/NotificationItem.vue +52 -0
  119. package/vue-components/v3/pagination/Pagination.vue +16 -3
  120. package/vue-components/v3/sidebar/ClusterSwitcher.vue +133 -0
  121. package/vue-components/v3/sidebar/SidebarItemWithDropDown.vue +120 -0
  122. package/vue-components/v3/tab/TabItem.vue +1 -1
  123. package/vue-components/v3/table/MultiInfoTable.vue +143 -0
  124. package/vue-components/v3/table/Table.vue +40 -12
  125. package/vue-components/v3/table/TableContainer.vue +34 -0
  126. package/vue-components/v3/table/TableRow.vue +62 -3
  127. package/vue-components/v3/table/table-cell/CellValue.vue +28 -3
  128. package/vue-components/v3/table/table-cell/GenericCell.vue +75 -0
  129. package/vue-components/v3/table/table-cell/ObjectCell.vue +5 -1
  130. package/vue-components/v3/tabs/EditorTabs.vue +1 -1
  131. package/vue-components/v3/tag/Tag.vue +1 -1
  132. package/vue-components/v3/terminal/LongRunningTaskTerminal.vue +148 -0
@@ -10,14 +10,16 @@
10
10
  <ac-button
11
11
  modifier-classes="is-square is-primary"
12
12
  icon-class="copy"
13
- v-clipboard:copy="`${editorTitle}: &quot;${editorContent}&quot;`"
13
+ v-clipboard:copy="
14
+ `${editorTitle}: ${JSON.stringify(parsedContent, null, 4)}`
15
+ "
14
16
  v-clipboard:success="onCopy"
15
17
  v-clipboard:error="onError"
16
18
  />
17
19
  </header-item>
18
20
  </template>
19
21
  <editor
20
- :value="JSON.stringify(parsedContent, null, 4)"
22
+ :model-value="JSON.stringify(parsedContent, null, 4)"
21
23
  :read-only="true"
22
24
  language="json"
23
25
  :show-minimap="false"
@@ -28,36 +30,43 @@
28
30
  <script>
29
31
  import { defineComponent, defineAsyncComponent } from "vue";
30
32
  import { useToast } from "vue-toastification";
33
+ import Preloader from "../../v2/preloader/Preloader.vue";
34
+ import Banner from "../../v2/banner/Banner.vue";
31
35
 
32
36
  export default defineComponent({
33
37
  props: {
34
38
  open: {
35
39
  type: Boolean,
36
- default: false,
40
+ default: false
37
41
  },
38
42
  editorTitle: {
39
43
  type: String,
40
- default: "",
44
+ default: ""
41
45
  },
42
46
  editorContent: {
43
47
  type: null,
44
- default: () => ({}),
45
- },
48
+ default: () => ({})
49
+ }
46
50
  },
47
51
  emits: ["closemodal"],
48
52
  components: {
49
53
  Modal: defineAsyncComponent(() =>
50
- import("../modal/Modal.vue").then((module) => module.default)
51
- ),
52
- Editor: defineAsyncComponent(() =>
53
- import("../editor/Editor.vue").then((module) => module.default)
54
+ import("../modal/Modal.vue").then(module => module.default)
54
55
  ),
56
+ Editor: defineAsyncComponent({
57
+ loader: () =>
58
+ import("../editor/Editor.vue").then(module => module.default),
59
+ loadingComponent: Preloader,
60
+ delay: 200,
61
+ errorComponent: Banner,
62
+ timeout: 100000,
63
+ }),
55
64
  AcButton: defineAsyncComponent(() =>
56
- import("../button/Button.vue").then((module) => module.default)
65
+ import("../button/Button.vue").then(module => module.default)
57
66
  ),
58
67
  HeaderItem: defineAsyncComponent(() =>
59
- import("../../v2/header/HeaderItem.vue").then((module) => module.default)
60
- ),
68
+ import("../../v2/header/HeaderItem.vue").then(module => module.default)
69
+ )
61
70
  },
62
71
  computed: {
63
72
  parsedContent() {
@@ -66,7 +75,7 @@ export default defineComponent({
66
75
  } catch (e) {
67
76
  return this.editorContent;
68
77
  }
69
- },
78
+ }
70
79
  },
71
80
  setup() {
72
81
  const toast = useToast();
@@ -81,7 +90,7 @@ export default defineComponent({
81
90
  },
82
91
  closeModal() {
83
92
  this.$emit("closemodal", true);
84
- },
85
- },
93
+ }
94
+ }
86
95
  });
87
96
  </script>
@@ -0,0 +1,337 @@
1
+ <template>
2
+ <modal
3
+ :open="open"
4
+ :title="title"
5
+ :is-close-option-disabled="!enableModalClose"
6
+ :ignore-outside-click="true"
7
+ :hide-action-footer="!enableModalFooter"
8
+ @closemodal="$emit('close')"
9
+ >
10
+ <div v-if="connectionError" class="task-simple-wrapper">
11
+ <div class="task-cogs-icon">
12
+ <i class="fa fa-times-circle has-text-danger fa-5x fa-fw"></i>
13
+ </div>
14
+ <div class="task-log">
15
+ <span class="task-title">
16
+ <i class="fa fa-times-circle mr-5 is-failed" />
17
+ <span> Connection error </span>
18
+ </span>
19
+ <span>{{ connectionError }}</span>
20
+ </div>
21
+ </div>
22
+ <div
23
+ v-else-if="isNatsConnectionLoading || !activeStep"
24
+ class="is-justify-content-center"
25
+ :class="simple ? 'task-simple-wrapper' : 'task-complex-wrapper'"
26
+ >
27
+ <preloader
28
+ :style="{ height: '100%' }"
29
+ class="is-fullheight"
30
+ message="Connecting..."
31
+ />
32
+ </div>
33
+ <div v-else-if="simple" class="task-simple-wrapper">
34
+ <div class="task-cogs-icon">
35
+ <i class="fa fa-cog fa-spin fa-5x fa-fw"></i>
36
+ <span class="is-flex is-flex-direction-column">
37
+ <i class="fa fa-cog fa-spin fa-3x fa-bw"></i>
38
+ <i class="fa fa-cog fa-spin fa-3x fa-bw"></i>
39
+ </span>
40
+ </div>
41
+ <div class="task-log">
42
+ <span class="task-title">
43
+ <i
44
+ v-if="activeTask?.status === 'Running'"
45
+ class="fa fa-circle-o-notch fa-spin mr-5"
46
+ />
47
+ <i
48
+ v-else-if="activeTask?.status === 'Success'"
49
+ class="fa fa-check-circle mr-5 is-success"
50
+ />
51
+ <i
52
+ v-else-if="activeTask?.status === 'Failed'"
53
+ class="fa fa-times-circle mr-5 is-failed"
54
+ />
55
+ <span>
56
+ {{ activeTask?.step }}
57
+ </span>
58
+ </span>
59
+ <span>{{ activeTask?.logs[activeTask?.logs.length - 1] }}</span>
60
+ </div>
61
+ </div>
62
+ <div v-else class="task-complex-wrapper">
63
+ <ul class="task-list">
64
+ <li v-for="task in tasks" :key="task.step">
65
+ <long-running-task-item
66
+ :title="task.step"
67
+ :status="task.status"
68
+ :class="{ 'is-active': activeStep === task.step }"
69
+ />
70
+ </li>
71
+ </ul>
72
+ <long-running-task-terminal
73
+ :key="activeTask?.step"
74
+ :theme="theme"
75
+ :logs="activeTask?.logs"
76
+ class="task-log"
77
+ />
78
+ </div>
79
+
80
+ <template #modal-footer-controls>
81
+ <ac-button
82
+ title="Close"
83
+ modifier-classes="is-outlined"
84
+ @click.stop="$emit('close')"
85
+ />
86
+ <ac-button
87
+ v-if="showSuccessButton"
88
+ :title="successCtx?.btnTitle"
89
+ :is-loader-active="successCtx?.isLoaderActive"
90
+ modifier-classes="is-primary"
91
+ icon-class="step-forward"
92
+ @click="successCtx.onSuccessBtnClick"
93
+ />
94
+ <ac-button
95
+ v-if="showReportButton"
96
+ title="Report Issue"
97
+ modifier-classes="is-danger"
98
+ icon-class="external-link"
99
+ @click="onReportIssueClick"
100
+ />
101
+ </template>
102
+ </modal>
103
+ </template>
104
+ <script setup lang="ts">
105
+ import {
106
+ computed,
107
+ getCurrentInstance,
108
+ onBeforeUnmount,
109
+ Ref,
110
+ toRefs,
111
+ watch,
112
+ watchEffect,
113
+ } from "vue";
114
+ import { defineAsyncComponent, ref } from "vue";
115
+ import { Task, TaskLog } from "../../../typings/long-running-tasks.ts";
116
+ import { Subscription, StringCodec } from "nats.ws";
117
+
118
+ const Modal = defineAsyncComponent(() => import("../modal/Modal.vue"));
119
+ const LongRunningTaskItem = defineAsyncComponent(
120
+ () => import("../long-running-tasks/LongRunningTaskItem.vue")
121
+ );
122
+ const LongRunningTaskTerminal = defineAsyncComponent(
123
+ () => import("../terminal/LongRunningTaskTerminal.vue")
124
+ );
125
+ const Preloader = defineAsyncComponent(
126
+ () => import("../../v2/preloader/Preloader.vue")
127
+ );
128
+ const AcButton = defineAsyncComponent(() => import("../button/Button.vue"));
129
+
130
+ defineEmits(["close"]);
131
+
132
+ const props = withDefaults(
133
+ defineProps<{
134
+ open: boolean;
135
+ theme: string;
136
+ title: string;
137
+ simple: boolean;
138
+ natsSubject: string;
139
+ isNatsConnectionLoading: boolean;
140
+ errorCtx?: {
141
+ connectionError: string;
142
+ onError: (msg: string) => void;
143
+ };
144
+ successCtx?: {
145
+ btnTitle?: string;
146
+ isLoaderActive?: boolean;
147
+ onSuccess: () => void;
148
+ onSuccessBtnClick?: () => void;
149
+ };
150
+ }>(),
151
+ {
152
+ open: true,
153
+ theme: "light",
154
+ simple: true,
155
+ title: "Sample title",
156
+ natsSubject: "",
157
+ isNatsConnectionLoading: false,
158
+ errorCtx: undefined,
159
+ successCtx: undefined,
160
+ }
161
+ );
162
+
163
+ const { natsSubject, open, errorCtx, successCtx } = toRefs(props);
164
+ const connectionError = computed(() => errorCtx.value?.connectionError);
165
+ const currentInstance = getCurrentInstance();
166
+ const $nats = currentInstance?.appContext.config.globalProperties.$nc;
167
+ let subscription: Subscription;
168
+
169
+ const tasks: Ref<Array<Task>> = ref([]);
170
+ const activeStep: Ref<string> = ref("");
171
+ const activeTask = computed(() => {
172
+ const task = tasks.value.find((task) => task.step === activeStep.value);
173
+ return task;
174
+ });
175
+
176
+ function handleTaskLog(log: TaskLog) {
177
+ if (log.step) {
178
+ // log has a step
179
+ // so add new task
180
+ tasks.value.push({
181
+ ...log,
182
+ logs: [(log.msg && log.msg) || ""],
183
+ });
184
+ activeStep.value = log.step;
185
+ } else {
186
+ const task = tasks.value.find((task) => task.step === activeStep.value);
187
+ if (task) {
188
+ task.status = log.status;
189
+ if (log.status === "Failed") {
190
+ task.logs.push(log.error || "");
191
+ } else {
192
+ task.logs.push(log.msg || "");
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ async function subscribeToChannel(channelId: string) {
199
+ subscription = $nats?.subscribe(channelId);
200
+
201
+ console.log("Started listening", channelId);
202
+
203
+ if (subscription) {
204
+ // listen to channel events
205
+ for await (const msg of subscription) {
206
+ console.log("Long Running Tasks Modal=>");
207
+ console.log({ data: StringCodec().decode(msg.data) });
208
+ const log: TaskLog = JSON.parse(StringCodec().decode(msg.data));
209
+ console.log({ log });
210
+ handleTaskLog(log);
211
+ }
212
+ console.log("Stopped listening", channelId);
213
+ console.log("Closed Channel", channelId);
214
+ }
215
+ }
216
+
217
+ watchEffect(() => {
218
+ if (natsSubject.value) {
219
+ subscribeToChannel(natsSubject.value);
220
+ }
221
+ });
222
+
223
+ watch(open, (n) => {
224
+ if (!n) {
225
+ subscription && subscription.unsubscribe();
226
+ }
227
+ });
228
+ onBeforeUnmount(() => {
229
+ subscription && subscription.unsubscribe();
230
+ });
231
+
232
+ // modal close / footer feature
233
+ const enableModalClose = computed(() => {
234
+ return (
235
+ connectionError.value ||
236
+ activeTask.value?.status === "Failed" ||
237
+ activeTask.value?.status === "Success"
238
+ );
239
+ });
240
+ const enableModalFooter = computed(() => {
241
+ return showReportButton.value || showSuccessButton.value;
242
+ });
243
+
244
+ // report button
245
+ const showReportButton = computed(() => activeTask.value?.status === "Failed");
246
+ function onReportIssueClick() {
247
+ const url = `https://github.com/bytebuilders/community/issues/new?title=Chart Install: ${
248
+ activeStep.value
249
+ }&labels[]=bug&body=${window.location.href} %0A%0A %60%60%60 %0A ${
250
+ activeTask.value?.logs[activeTask.value?.logs.length - 1 || 0]
251
+ } %0A %60%60%60`;
252
+ window.open(url, "_blank");
253
+ }
254
+
255
+ // success button
256
+ const showSuccessButton = computed(
257
+ () => activeTask.value?.status === "Success" && successCtx.value?.btnTitle
258
+ );
259
+
260
+ // execute on success and on error functions
261
+ watch(
262
+ () => activeTask.value?.status,
263
+ (n) => {
264
+ if (n === "Success") {
265
+ successCtx.value.onSuccess();
266
+ } else if (n === "Failed") {
267
+ errorCtx.value.onError(
268
+ activeTask.value?.logs[activeTask.value?.logs.length - 1 || 0] || ""
269
+ );
270
+ }
271
+ }
272
+ );
273
+ </script>
274
+
275
+ <style scoped lang="scss">
276
+ .task-simple-wrapper {
277
+ display: flex;
278
+ flex-direction: column;
279
+ justify-content: space-between;
280
+ width: 40vw;
281
+ height: 40vh;
282
+ .task-cogs-icon {
283
+ width: 100%;
284
+ height: 70%;
285
+ display: flex;
286
+ align-items: center;
287
+ justify-content: center;
288
+ font-size: 20px;
289
+ color: var(--ac-primary);
290
+ }
291
+ .task-log {
292
+ width: 100%;
293
+ height: 30%;
294
+ display: flex;
295
+ flex-direction: column;
296
+ align-items: center;
297
+ justify-content: center;
298
+ .task-title {
299
+ span,
300
+ i {
301
+ font-size: 16px;
302
+ }
303
+ i {
304
+ color: var(--ac-primary);
305
+ &.is-success {
306
+ color: #158748;
307
+ }
308
+ &.is-failed {
309
+ color: #ff3729;
310
+ }
311
+ }
312
+ font-weight: 500;
313
+ }
314
+ span {
315
+ font-size: 14px;
316
+ }
317
+ }
318
+ }
319
+ .task-complex-wrapper {
320
+ display: flex;
321
+ flex-direction: row;
322
+ justify-content: space-between;
323
+ width: 60vw;
324
+ height: 60vh;
325
+
326
+ .task-list {
327
+ width: 25%;
328
+ height: 100%;
329
+ }
330
+ .task-log {
331
+ width: 70%;
332
+ height: 100%;
333
+ border-radius: 1rem;
334
+ font-size: 13px;
335
+ }
336
+ }
337
+ </style>
@@ -1,10 +1,13 @@
1
1
  <template>
2
- <div class="app-drawer-wrapper">
3
- <div class="drawer-icon">
2
+ <div class="app-drawer-wrapper is-flex">
3
+ <div
4
+ class="drawer-icon is-flex is-justify-content-center is-align-items-center"
5
+ >
4
6
  <svg
5
7
  class="gb_We"
6
8
  focusable="false"
7
9
  viewBox="0 0 24 24"
10
+ style="width: 22px;margin-top: 2px;"
8
11
  :style="{ fill: 'white' }"
9
12
  >
10
13
  <path
@@ -46,13 +49,15 @@ export default defineComponent({
46
49
  props: {
47
50
  apps: {
48
51
  type: Array,
49
- default: () => [],
50
- },
52
+ default: () => []
53
+ }
51
54
  },
52
55
  components: {
53
56
  NavbarItemContent: defineAsyncComponent(() =>
54
- import("../../v2/navbar/NavbarItemContent.vue").then((module) => module.default)
55
- ),
56
- },
57
+ import("../../v2/navbar/NavbarItemContent.vue").then(
58
+ module => module.default
59
+ )
60
+ )
61
+ }
57
62
  });
58
63
  </script>
@@ -1,7 +1,24 @@
1
1
  <template>
2
- <button v-if="themeMode" class="button ac-nav-button" @click="toggleTheme" :title="themeModeIconTooltip" >
3
- <i :class="`fa ${themeModeIconClass} width-15`" />
4
- </button>
2
+ <li class="mt-10 b-t-1 pt-10">
3
+ <ul class="ac-vscrollbar">
4
+ <li>
5
+ <div class="ac-menu-contentt theme-choicee">
6
+ <ul class="is-flex is-flex-direction-row is-justify-content-center">
7
+ <li
8
+ v-for="theme of Object.keys(themeModes)"
9
+ :title="themeModes[theme].displayName"
10
+ @click="themeMode = theme"
11
+ class="p-10 pl-30 pr-30 is-flex-grow-1 has-text-centered"
12
+ :class="{ 'is-active': themeMode === theme }"
13
+ :key="theme"
14
+ >
15
+ <i :class="['fa', themeModes[theme].iconClass]" />
16
+ </li>
17
+ </ul>
18
+ </div>
19
+ </li>
20
+ </ul>
21
+ </li>
5
22
  </template>
6
23
  <script>
7
24
  import { defineComponent } from "vue";
@@ -10,41 +27,31 @@ export default defineComponent({
10
27
  data() {
11
28
  return {
12
29
  themeMode: "",
30
+ themeModes: {
31
+ light: {
32
+ displayName: "Light Theme",
33
+ iconClass: "fa-sun-o",
34
+ },
35
+ dark: {
36
+ displayName: "Dark Theme",
37
+ iconClass: "fa-moon-o",
38
+ },
39
+ system: {
40
+ displayName: "System Theme",
41
+ iconClass: "fa-desktop",
42
+ },
43
+ },
13
44
  };
14
45
  },
15
46
 
16
- emits: ['set:theme'],
17
-
18
- computed: {
19
- // to set icon class for theme mode
20
- themeModeIconClass() {
21
- if(this.themeMode === "system") {
22
- return "fa-desktop";
23
- } else if(this.themeMode === "light") {
24
- return "fa-sun-o";
25
- } else if(this.themeMode === "dark") {
26
- return "fa-moon-o";
27
- }
28
- },
29
-
30
- // to set icon tooltip for theme mode
31
- themeModeIconTooltip() {
32
- if(this.themeMode === "system") {
33
- return "System theme";
34
- } else if(this.themeMode === "light") {
35
- return "Light theme";
36
- } else if(this.themeMode === "dark") {
37
- return "Dark theme";
38
- }
39
- }
40
- },
47
+ emits: ["set:theme"],
41
48
 
42
49
  mounted() {
43
50
  // get theme mode from localStorage or set default one
44
51
  this.themeMode = localStorage.getItem("themeMode") || "light";
45
52
  },
46
53
 
47
- destroyed() {
54
+ unmounted() {
48
55
  this.removeColorSchemeEventListener();
49
56
  },
50
57
 
@@ -52,19 +59,16 @@ export default defineComponent({
52
59
  themeMode: {
53
60
  handler(n) {
54
61
  this.onThemeModeChange(n);
55
- }
56
- }
62
+ },
63
+ },
57
64
  },
58
65
 
59
66
  methods: {
60
67
  // handle theme mode button click
61
68
  toggleTheme() {
62
- if(this.themeMode === "light")
63
- this.themeMode = "dark";
64
- else if(this.themeMode === "dark")
65
- this.themeMode = "system";
66
- else if(this.themeMode === "system")
67
- this.themeMode = "light";
69
+ if (this.themeMode === "light") this.themeMode = "dark";
70
+ else if (this.themeMode === "dark") this.themeMode = "system";
71
+ else if (this.themeMode === "system") this.themeMode = "light";
68
72
  },
69
73
 
70
74
  // triggered when theme mode is updated
@@ -72,8 +76,10 @@ export default defineComponent({
72
76
  localStorage.setItem("themeMode", n);
73
77
 
74
78
  let theme = n;
75
- if(n === "system") {
76
- const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
79
+ if (n === "system") {
80
+ const isDarkMode =
81
+ window.matchMedia &&
82
+ window.matchMedia("(prefers-color-scheme: dark)").matches;
77
83
  this.addColorSchemeEventListener();
78
84
  theme = isDarkMode ? "dark" : "light";
79
85
  } else {
@@ -85,7 +91,7 @@ export default defineComponent({
85
91
 
86
92
  // add proper css class to update the ui theme
87
93
  handleDarkThemeClass(currentTheme) {
88
- if(currentTheme === "light") {
94
+ if (currentTheme === "light") {
89
95
  document.documentElement.classList.remove("is-dark-theme");
90
96
  } else {
91
97
  document.documentElement.classList.add("is-dark-theme");
@@ -96,23 +102,19 @@ export default defineComponent({
96
102
  addColorSchemeEventListener() {
97
103
  window
98
104
  .matchMedia("(prefers-color-scheme: dark)")
99
- .addEventListener(
100
- "change", this.handleSystemThemeChange
101
- );
105
+ .addEventListener("change", this.handleSystemThemeChange);
102
106
  },
103
107
 
104
108
  // remove system theme listener event
105
109
  removeColorSchemeEventListener() {
106
110
  window
107
111
  .matchMedia("(prefers-color-scheme: dark)")
108
- .removeEventListener(
109
- "change", this.handleSystemThemeChange
110
- );
112
+ .removeEventListener("change", this.handleSystemThemeChange);
111
113
  },
112
114
 
113
115
  handleSystemThemeChange() {
114
116
  this.onThemeModeChange(this.themeMode);
115
117
  },
116
- }
118
+ },
117
119
  });
118
120
  </script>