diff --git a/src/App.vue b/src/App.vue index 9a5f72b..3504b31 100644 --- a/src/App.vue +++ b/src/App.vue @@ -24,7 +24,7 @@ import Graph from "./graph/index.vue"; import Editor from "./editor/index.vue"; import { computed, ref, watch, watchEffect } from "vue"; -import { useTheme } from "@/consts"; +import { useTheme } from "@/states"; const theme = useTheme(); const soberPage = ref(); watchEffect(() => diff --git a/src/consts.ts b/src/consts.ts index 15f4561..f31878f 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -392,34 +392,3 @@ export const fnTypeArr = [ }, ] as const satisfies FnType[]; -// Datum define -import { defineStore } from "pinia"; -import { computed, ref } from "vue"; -export const useProfile = defineStore("profile", () => { - const data = ref([ - { fnType: "linear", graphType: "polyline", fn: "x^2", key: 1 }, - ]); - const getOriginalCopy = (forExport?: boolean) => - toOriginalDatum(data.value, forExport); - return { data, getOriginalCopy }; -}); - -// Theme define -export const useTheme = defineStore("theme", () => { - const themeValues = ["auto", "dark", "light"] as const; - const initialIndex = (() => { - if (typeof localStorage !== "undefined") { - const savedTheme = Number(localStorage.getItem("theme")); - if ([0, 1, 2].includes(savedTheme)) return savedTheme as 0 | 1 | 2; - } - return 0; - })(); - const index = ref(initialIndex); - const initialValue = themeValues[initialIndex]; - const value = computed(() => themeValues[index.value]); - const toogle = () => { - index.value = ((index.value + 1) % themeValues.length) as 0 | 1 | 2; - localStorage.setItem("theme", index.value.toString()); - }; - return { initialIndex,initialValue, index, value, toogle }; -}); diff --git a/src/editor/datum.vue b/src/editor/datum.vue index bdb9e44..f494094 100644 --- a/src/editor/datum.vue +++ b/src/editor/datum.vue @@ -142,7 +142,7 @@ const blockFolded = ref(true); const foldShell = ref(); import { Snackbar } from "sober"; -import { useProfile } from "../consts"; +import { useProfile } from "@/states"; const profile = useProfile(); function deleteDatum() { const backup = cloneDeep(dataItem.value)!; diff --git a/src/editor/datumList.vue b/src/editor/datumList.vue index cc4071d..7efe928 100644 --- a/src/editor/datumList.vue +++ b/src/editor/datumList.vue @@ -34,7 +34,7 @@ import AnimatedListItem from "@/ui/animatedList/animatedListItem.vue"; import Datum from "./datum.vue"; import { getNewDatum } from "@/consts"; -import { useProfile } from "@/consts"; +import { useProfile } from "@/states"; const profile = useProfile(); diff --git a/src/editor/import.vue b/src/editor/import.vue index b84ea63..346ef93 100644 --- a/src/editor/import.vue +++ b/src/editor/import.vue @@ -30,28 +30,13 @@ const { t } = useI18n(); import SIconImport from "@/ui/icons/import.vue"; -import { useProfile } from "@/consts"; +import { useProfile } from "@/states"; const profile = useProfile(); -import { onMounted, ref } from "vue"; +import { ref } from "vue"; import JSON5 from "json5"; -import base64 from "base-64"; -import utf8 from "utf8"; import type { FunctionPlotDatum } from "function-plot"; import { toInternalDatum } from "@/consts"; -onMounted(() => { - const rawCode = window.location.search.match(/\?code=(.+)$/)?.[1]; - if (rawCode) - try { - const code = utf8.decode(base64.decode(decodeURIComponent(rawCode))); - const data = toInternalDatum( - (JSON5.parse(code).data as FunctionPlotDatum[]) ?? [] - ); - profile.data = toInternalDatum(data); - console.log(code); - console.log(data); - } catch (e) {} -}); const importStr = ref(""); import { Snackbar } from "sober"; @@ -60,10 +45,13 @@ function handleImport() { try { const parsed = JSON5.parse(importStr.value); if (typeof parsed !== "object" || parsed === null) throw null; - if(typeof parsed.data !== "object" || !Array.isArray(parsed.data)) throw null; - profile.data = toInternalDatum( + if (typeof parsed.data !== "object" || !Array.isArray(parsed.data)) + throw null; + const newData = toInternalDatum( (JSON5.parse(importStr.value).data as FunctionPlotDatum[]) ?? [] ); + profile.data = []; + profile.data = newData; Snackbar.builder({ text: t("title.importSuccess"), type: "success", diff --git a/src/editor/output.vue b/src/editor/output.vue index ce0841d..5cbdc99 100644 --- a/src/editor/output.vue +++ b/src/editor/output.vue @@ -32,19 +32,28 @@ const { t } = useI18n(); import SIconCopy from "@/ui/icons/copy.vue"; import JSON5 from "json5"; +import base64 from "base-64"; +import utf8 from "utf8"; + import prettier from "prettier/standalone"; import prettierPluginBabel from "prettier/plugins/babel"; import prettierPluginEstree from "prettier/plugins/estree"; import { ref, watch } from "vue"; -import { useProfile } from "@/consts"; +import { useProfile } from "@/states"; const profile = useProfile(); const formatted = ref(""); watch( profile, () => { + const code = JSON5.stringify({ data: profile.getOriginalCopy(true) }); + const url = + window.location.href.match(/https?:\/\/[^/]+\//) + + "?code=" + + encodeURIComponent(base64.encode(utf8.encode(code)).replace(/=+$/, "")); + window.history.replaceState(null, "", url); prettier - .format(JSON5.stringify({ data: profile.getOriginalCopy(true) }), { + .format(code, { parser: "json5", printWidth: 40, plugins: [prettierPluginBabel, prettierPluginEstree], diff --git a/src/graph/index.vue b/src/graph/index.vue index 001340a..4a86174 100644 --- a/src/graph/index.vue +++ b/src/graph/index.vue @@ -14,7 +14,7 @@ import Graph from "./graph.vue"; import { computed, onMounted, ref } from "vue"; import { throttle } from "lodash-es"; -import { useProfile } from "@/consts"; +import { useProfile } from "@/states"; const graphWidth = ref(0), graphHeight = ref(0); diff --git a/src/i18n.ts b/src/i18n.ts index a637f0f..9871056 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -1,9 +1,22 @@ import type { createI18n } from "vue-i18n"; type I18nOpt = Parameters[0]; +const locale = (() => { + if (localStorage) { + const localLocale = localStorage.getItem("lang"); + const langStr = localLocale ?? navigator.language; + if (langStr.startsWith("zh")) return "zh-CN"; + if (langStr.startsWith("en")) return "en-US"; + } + return "en-US"; +})(); + +if (localStorage && !localStorage.getItem("lang")) + localStorage.setItem("lang", locale); + export default { legacy: false, - locale: "zh-CN", + locale, messages: { "zh-CN": { buttons: { @@ -24,7 +37,7 @@ export default { undo: "撤销", }, graphType: { - interval: "默认", + interval: "微矩形", polyline: "多段线", scatter: "散点", text: "文本", diff --git a/src/public.css b/src/public.css index 1dcf8eb..e5c1c37 100644 --- a/src/public.css +++ b/src/public.css @@ -44,3 +44,9 @@ input[type="number"] { .monospace::part(input) { font-family: "Jetbrains Mono", monospace; } + +@media (prefers-color-scheme: dark) { + :root { + background-color: #111415; + } +} diff --git a/src/states.ts b/src/states.ts new file mode 100644 index 0000000..1903990 --- /dev/null +++ b/src/states.ts @@ -0,0 +1,47 @@ +import JSON5 from "json5"; +import base64 from "base-64"; +import utf8 from "utf8"; +import { defineStore } from "pinia"; +import { computed, ref } from "vue"; +import { InternalDatum, toInternalDatum, toOriginalDatum } from "./consts"; +import { FunctionPlotDatum } from "function-plot"; + +// Datum define +export const useProfile = defineStore("profile", () => { + const data = ref( + (() => { + const rawCode = window?.location.search.match(/\?code=(.+)$/)?.[1]; + if (rawCode) + try { + const code = utf8.decode(base64.decode(decodeURIComponent(rawCode))); + const data = toInternalDatum( + (JSON5.parse(code).data as FunctionPlotDatum[]) ?? [] + ); + return toInternalDatum(data); + } catch (e) {} + })() ?? [{ fnType: "linear", graphType: "polyline", fn: "x^2", key: 1 }] + ); + const getOriginalCopy = (forExport?: boolean) => + toOriginalDatum(data.value, forExport); + return { data, getOriginalCopy }; +}); + +// Theme define +export const useTheme = defineStore("theme", () => { + const themeValues = ["auto", "dark", "light"] as const; + const initialIndex = (() => { + if (typeof localStorage !== "undefined") { + const savedTheme = Number(localStorage.getItem("theme")); + if ([0, 1, 2].includes(savedTheme)) return savedTheme as 0 | 1 | 2; + } + return 0; + })(); + const index = ref(initialIndex); + const initialValue = themeValues[initialIndex]; + const value = computed(() => themeValues[index.value]); + const toogle = () => { + index.value = ((index.value + 1) % themeValues.length) as 0 | 1 | 2; + localStorage.setItem("theme", index.value.toString()); + }; + return { initialIndex, initialValue, index, value, toogle }; +}); diff --git a/src/ui/navbar.vue b/src/ui/navbar.vue index a58a5f3..8117d24 100644 --- a/src/ui/navbar.vue +++ b/src/ui/navbar.vue @@ -46,33 +46,26 @@