console: add a theme provider to not rely on CSS only

This commit is contained in:
Vincent Bernat
2022-05-10 15:54:56 +02:00
parent 2319262340
commit 1c0c660451
8 changed files with 164 additions and 119 deletions

View File

@@ -1,11 +1,13 @@
<template>
<AppNotifications />
<div class="flex max-h-screen flex-col">
<NavigationBar class="flex-none" />
<main class="relative flex grow overflow-y-auto">
<router-view />
</main>
</div>
<ThemeProvider>
<AppNotifications />
<div class="flex max-h-screen flex-col">
<NavigationBar class="flex-none" />
<main class="relative flex grow overflow-y-auto">
<router-view />
</main>
</div>
</ThemeProvider>
</template>
<script setup>
@@ -13,4 +15,5 @@ import "./tailwind.css";
import NavigationBar from "./components/NavigationBar.vue";
import AppNotifications from "./components/AppNotifications.vue";
import ThemeProvider from "./components/ThemeProvider.vue";
</script>

View File

@@ -1,42 +0,0 @@
<template>
<button
type="button"
class="rounded-lg p-2.5 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-700"
@click="toggle()"
>
<MoonIcon v-if="!dark" class="h-5 w-5" />
<SunIcon v-if="dark" class="h-5 w-5" />
</button>
</template>
<script setup>
import { ref, watch } from "vue";
import { SunIcon, MoonIcon } from "@heroicons/vue/solid";
const dark = ref(false);
if (
localStorage.getItem("color-theme") === "dark" ||
(!("color-theme" in localStorage) &&
window.matchMedia("(prefers-color-scheme: dark)").matches)
) {
dark.value = true;
}
watch(
dark,
(dark) => {
if (dark) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
},
{ immediate: true }
);
const toggle = () => {
dark.value = !dark.value;
localStorage.setItem("color-theme", dark.value ? "dark" : "light");
};
</script>

View File

@@ -0,0 +1,16 @@
<template>
<button
type="button"
class="rounded-lg p-2.5 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-700"
@click="toggle()"
>
<MoonIcon v-if="!isDark()" class="h-5 w-5" />
<SunIcon v-if="isDark()" class="h-5 w-5" />
</button>
</template>
<script setup>
import { inject } from "vue";
import { SunIcon, MoonIcon } from "@heroicons/vue/solid";
const { isDark, toggle } = inject("darkMode");
</script>

View File

@@ -17,7 +17,7 @@
>
</router-link>
<div class="flex md:order-2">
<DarkMode />
<DarkModeSwitcher />
<DisclosureButton
class="ml-3 inline-flex items-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600 md:hidden"
>
@@ -70,7 +70,7 @@ import {
XIcon,
PresentationChartLineIcon,
} from "@heroicons/vue/solid";
import DarkMode from "./DarkMode.vue";
import DarkModeSwitcher from "./DarkModeSwitcher.vue";
const route = useRoute();
const navigation = computed(() => [

View File

@@ -0,0 +1,40 @@
<template>
<slot></slot>
</template>
<script setup>
import { ref, provide, watch } from "vue";
const isDark = ref(false);
const toggleDarkMode = () => {
isDark.value = !isDark.value;
localStorage.setItem("color-theme", isDark.value ? "dark" : "light");
};
if (
localStorage.getItem("color-theme") === "dark" ||
(!("color-theme" in localStorage) &&
window.matchMedia("(prefers-color-scheme: dark)").matches)
) {
isDark.value = true;
}
watch(
isDark,
(isDark) => {
if (isDark) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
},
{ immediate: true }
);
provide("darkMode", {
isDark() {
return isDark.value;
},
toggle: toggleDarkMode,
});
</script>

View File

@@ -7,12 +7,14 @@
</template>
<script setup>
import { ref, watch } from "vue";
import { ref, watch, inject } from "vue";
import { use, graphic } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { LineChart } from "echarts/charts";
import { TooltipComponent, GridComponent } from "echarts/components";
import VChart from "vue-echarts";
import { dataColor } from "../utils/palette.js";
const { isDark } = inject("darkMode");
use([CanvasRenderer, LineChart, TooltipComponent, GridComponent]);
@@ -55,21 +57,30 @@ const option = ref({
type: "line",
symbol: "none",
lineStyle: {
color: "#5470c6",
width: 1,
},
areaStyle: {
opacity: 1,
color: new graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#5470c6" },
{ offset: 1, color: "#5572c8" },
]),
},
data: [],
},
],
});
watch(
isDark,
(isDark) => {
const theme = isDark ? "dark" : "light";
option.value.darkMode = isDark;
option.value.series[0].areaStyle = {
opacity: 0.9,
color: new graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: dataColor(0, false, theme) },
{ offset: 1, color: dataColor(0, true, theme) },
]),
};
option.value.series[0].lineStyle.color = dataColor(0, false, theme);
},
{ immediate: true }
);
watch(
() => props.refresh,
async () => {

View File

@@ -8,12 +8,14 @@
</template>
<script setup>
import { ref, watch } from "vue";
import { ref, watch, inject } from "vue";
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { PieChart } from "echarts/charts";
import { TooltipComponent, LegendComponent } from "echarts/components";
import VChart from "vue-echarts";
import { dataColor, dataColorGrey } from "../utils/palette.js";
const { isDark } = inject("darkMode");
use([CanvasRenderer, PieChart, TooltipComponent, LegendComponent]);
@@ -45,7 +47,6 @@ const option = ref({
itemGap: 5,
itemWidth: 14,
itemHeight: 14,
backgroundColor: "rgba(255, 255, 255, 0.4)",
textStyle: { fontSize: 10 },
formatter(name) {
return name.split(": ")[0];
@@ -57,21 +58,29 @@ const option = ref({
label: { show: false },
center: ["50%", "40%"],
radius: "60%",
itemStyle: {
color({ name, dataIndex }) {
if (name === "Others") {
return "#aaa";
}
return ["#5470c6", "#91cc75", "#fac858", "#ee6666", "#73c0de"][
dataIndex % 5
];
},
},
data: [],
},
],
});
watch(
isDark,
(isDark) => {
const theme = isDark ? "dark" : "light";
option.value.darkMode = isDark;
option.value.series.itemStyle = {
color({ name, dataIndex }) {
if (name === "Others") {
return dataColorGrey(0, false, theme);
}
return dataColor(dataIndex, false, theme);
},
};
option.value.legend.textStyle.color = isDark ? "#eee" : "#111";
},
{ immediate: true }
);
watch(
() => props.refresh,
async () => {

View File

@@ -65,7 +65,7 @@
</template>
<script setup>
import { ref, watch } from "vue";
import { ref, watch, inject } from "vue";
import { notify } from "notiwind";
import { Date as SugarDate } from "sugar-date";
import { use, graphic } from "echarts/core";
@@ -75,6 +75,7 @@ import { TooltipComponent, GridComponent } from "echarts/components";
import VChart from "vue-echarts";
import { ResizeRow } from "vue-resizer";
import { dataColor, dataColorGrey } from "../utils/palette.js";
const { isDark } = inject("darkMode");
use([CanvasRenderer, LineChart, TooltipComponent, GridComponent]);
@@ -139,6 +140,7 @@ const request = ref({
],
},
});
const fetchedData = ref({});
watch(
request,
@@ -161,56 +163,62 @@ watch(
return;
}
const data = await response.json();
fetchedData.value = data;
},
{ immediate: true }
);
// Graphic
graph.value.xAxis.data = data.t.slice(1, -1);
graph.value.series = data.rows.map((rows, idx) => {
watch([fetchedData, isDark], ([data, isDark]) => {
const theme = isDark ? "dark" : "light";
// Graphic
graph.value.darkMode = isDark;
graph.value.xAxis.data = data.t.slice(1, -1);
graph.value.series = data.rows.map((rows, idx) => {
const color = rows.some((name) => name === "Other")
? dataColorGrey
: dataColor;
return {
type: "line",
name: rows.join(" — "),
symbol: "none",
itemStyle: {
color: color(idx, false, theme),
},
lineStyle: {
color: color(idx, false, theme),
width: 1,
},
areaStyle: {
opacity: 0.95,
color: new graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: color(idx, false, theme) },
{ offset: 1, color: color(idx, true, theme) },
]),
},
emphasis: {
focus: "series",
},
stack: "all",
data: data.t.map((t, idx2) => [t, data.points[idx][idx2]]).slice(1, -1),
};
});
// Table
table.value = {
columns: request.value.dimensions,
rows: data.rows.map((rows, idx) => {
const color = rows.some((name) => name === "Other")
? dataColorGrey
: dataColor;
return {
type: "line",
name: rows.join(" — "),
symbol: "none",
itemStyle: {
color: color(idx),
},
lineStyle: {
color: color(idx),
width: 1,
},
areaStyle: {
opacity: 0.95,
color: new graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: color(idx) },
{ offset: 1, color: color(idx, true) },
]),
},
emphasis: {
focus: "series",
},
stack: "all",
data: data.t.map((t, idx2) => [t, data.points[idx][idx2]]).slice(1, -1),
dimensions: rows,
style: `background-color: ${color(idx, false, theme)}`,
min: data.min[idx],
max: data.max[idx],
average: data.average[idx],
};
});
// Table
table.value = {
columns: request.value.dimensions,
rows: data.rows.map((rows, idx) => {
const color = rows.some((name) => name === "Other")
? dataColorGrey
: dataColor;
return {
dimensions: rows,
style: `background-color: ${color(idx)}`,
min: data.min[idx],
max: data.max[idx],
average: data.average[idx],
};
}),
};
},
{ immediate: true }
);
}),
};
});
</script>