Skip to content

Commit 8542413

Browse files
authored
Merge pull request #3 from Linho1219/sober-ui
迁移到 Sober UI
2 parents b27e1bf + 806545f commit 8542413

File tree

19 files changed

+804
-505
lines changed

19 files changed

+804
-505
lines changed

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"json5": "^2.2.3",
1717
"lodash-es": "^4.17.21",
1818
"prettier": "^3.4.2",
19+
"sober": "^1.1.0",
1920
"utf8": "^3.0.0",
2021
"vue": "^3.5.13",
2122
"vue-draggable-plus": "^0.6.0",

patches/sober+1.1.0.patch

Lines changed: 184 additions & 0 deletions
Large diffs are not rendered by default.

public/fonts/KaTeX_AllInOne.woff2

31.2 KB
Binary file not shown.

src/App.vue

Lines changed: 167 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,138 @@
11
<template>
2-
<Navbar />
3-
<div id="content" :class="{ onresize: onResize }">
4-
<div id="editor" :style="{ width: sideRatio + 'vw' }">
5-
<div class="editor-inner">
6-
<VueDraggable
7-
v-model="graphData"
8-
:animation="150"
9-
handle=".datablock-drag"
10-
>
11-
<DataBlock
12-
v-for="(dataItem, i) in graphData"
13-
v-model="graphData[i]"
14-
@delete="graphData.splice(i, 1)"
15-
:key="dataItem.key"
16-
@require-full-update="fullUpdate"
17-
/>
18-
</VueDraggable>
19-
<div class="plot-data add-data">
20-
<div
21-
@click="
22-
graphData.push({
23-
key: Math.random(),
24-
fnType: 'linear',
25-
graphType: 'polyline',
26-
})
27-
"
28-
class="add-data-opt add"
29-
>
30-
+ {{ t("buttons.add") }}
31-
</div>
32-
<div @click="handleImport()" class="add-data-opt import">
33-
↓ {{ t("buttons.import") }}
2+
<s-page theme="auto" id="soberpage">
3+
<s-drawer>
4+
<Navbar @toggle-drawer="toogleDrawer" />
5+
<s-drawer
6+
theme="auto"
7+
id="content"
8+
:class="{ onresize: onResize }"
9+
ref="innerDrawer"
10+
>
11+
<div slot="start" id="editor" :style="{ width: sideRatio + 'vw' }">
12+
<div class="editor-inner">
13+
<s-scroll-view>
14+
<VueDraggable
15+
v-model="graphData"
16+
:animation="200"
17+
handle=".datablock-drag"
18+
:key="draggerKey"
19+
>
20+
<DataBlock
21+
v-for="(dataItem, i) in graphData"
22+
v-model="graphData[i]"
23+
@delete="graphData.splice(i, 1)"
24+
:key="dataItem.key"
25+
@require-full-update="fullUpdate"
26+
/>
27+
</VueDraggable>
28+
29+
<div
30+
class="plot-data add-data"
31+
@click="
32+
graphData.push({
33+
key: Math.random(),
34+
fnType: 'linear',
35+
graphType: 'polyline',
36+
})
37+
"
38+
>
39+
<s-icon name="add" />
40+
{{ t("buttons.add") }}
41+
<s-ripple attached></s-ripple>
42+
</div>
43+
</s-scroll-view>
44+
<s-dialog>
45+
<s-tooltip class="data-import" slot="trigger">
46+
<s-fab slot="trigger">
47+
<s-icon>
48+
<svg viewBox="0 -960 960 960">
49+
<path
50+
d="M480-120v-80h280v-560H480v-80h280q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H480Zm-80-160-55-58 102-102H120v-80h327L345-622l55-58 200 200-200 200Z"
51+
></path>
52+
</svg>
53+
</s-icon>
54+
</s-fab>
55+
{{ t("buttons.import") }}
56+
</s-tooltip>
57+
<div slot="headline">{{ t("title.source") }}</div>
58+
<s-text-field
59+
slot="text"
60+
label="JSON5 / JSON"
61+
multiLine
62+
style="min-height: 180px; min-width: 40vw"
63+
v-model.lazy="importStr"
64+
class="monospace"
65+
></s-text-field>
66+
<s-button slot="action" type="text">
67+
{{ t("buttons.cancel") }}
68+
</s-button>
69+
<s-button slot="action" type="text" @click="handleImport">
70+
{{ t("buttons.confirm") }}
71+
</s-button>
72+
</s-dialog>
3473
</div>
74+
<CodeDisplay :dataArr="toOriginalDatum(graphData, true)" />
75+
<div id="divider" @mousedown="handleDrag"></div>
76+
</div>
77+
<div id="graph" ref="shellRef">
78+
<Graph
79+
:data="toOriginalDatum(graphData)"
80+
:width="graphWidth"
81+
:height="graphHeight"
82+
:key="graphKey"
83+
@requireFullUpdate="fullUpdate"
84+
@requirePostUpdate="graphKey++"
85+
v-model="fullUpdateState"
86+
/>
3587
</div>
36-
</div>
37-
<CodeDisplay :dataArr="toOriginalDatum(graphData)" />
38-
</div>
39-
<div id="divider" @mousedown="handleDrag"></div>
40-
<div id="graph" ref="shellRef">
41-
<Graph
42-
:data="toOriginalDatum(graphData)"
43-
:width="graphWidth"
44-
:height="graphHeight"
45-
:key="key"
46-
@requireFullUpdate="fullUpdate"
47-
@requirePostUpdate="key++"
48-
v-model="fullUpdateState"
49-
/>
50-
</div>
51-
</div>
88+
</s-drawer>
89+
</s-drawer>
90+
</s-page>
5291
</template>
5392

5493
<script setup lang="ts">
55-
import { useI18n } from 'vue-i18n'
56-
const { t } = useI18n()
94+
import { useI18n } from "vue-i18n";
95+
const { t, locale } = useI18n();
5796
5897
import Navbar from "./components/nav.vue";
5998
import Graph from "./components/graph.vue";
6099
import DataBlock from "./components/dataBlock.vue";
61100
import CodeDisplay from "./components/codeDisplay.vue";
62101
import { VueDraggable } from "vue-draggable-plus";
63102
import type { FunctionPlotDatum } from "function-plot";
64-
import { onMounted, ref } from "vue";
103+
import { onMounted, ref, watch } from "vue";
65104
import JSON5 from "json5";
66105
import base64 from "base-64";
67106
import utf8 from "utf8";
68107
import { InternalDatum, toInternalDatum, toOriginalDatum } from "./consts";
108+
import { debounce } from "lodash-es";
69109
70110
const graphData = ref<InternalDatum[]>([
71111
{ fnType: "linear", graphType: "polyline", fn: "x^2", key: 1 },
72112
]);
73113
114+
const innerDrawer = ref<HTMLElementTagNameMap["s-drawer"]>();
74115
const graphWidth = ref(0),
75116
graphHeight = ref(0);
76-
const key = ref(0);
117+
const graphKey = ref(0);
77118
const fullUpdateState = ref(false);
78119
const sideRatio = ref(33);
79120
const onResize = ref(false);
121+
80122
const shellRef = ref<HTMLDivElement>();
81-
function handleResize() {
82-
if (shellRef.value) {
83-
graphWidth.value = shellRef.value.clientWidth;
84-
graphHeight.value = shellRef.value.clientHeight;
85-
}
86-
}
123+
onMounted(() => {
124+
const observer = new ResizeObserver(
125+
debounce(() => {
126+
graphWidth.value = shellRef.value!.clientWidth;
127+
graphHeight.value = shellRef.value!.clientHeight;
128+
}, 250)
129+
);
130+
observer.observe(shellRef.value!);
131+
});
87132
88133
function fullUpdate() {
89134
fullUpdateState.value = true;
90-
key.value++;
135+
graphKey.value++;
91136
}
92137
93138
onMounted(() => {
@@ -102,106 +147,117 @@ onMounted(() => {
102147
console.log(code);
103148
console.log(data);
104149
} catch (e) {}
105-
window.addEventListener("resize", handleResize);
106-
handleResize();
107150
});
108151
109152
function handleDrag() {
110153
onResize.value = true;
111154
const xfull = window.innerWidth;
155+
const restrictRange = (x: number, min: number, max: number) =>
156+
Math.max(min, Math.min(x, max));
112157
const mousemove = (event: MouseEvent) =>
113-
(sideRatio.value = (event.clientX / xfull) * 100);
158+
(sideRatio.value = restrictRange((event.clientX / xfull) * 100, 25, 75));
114159
document.addEventListener("mousemove", mousemove);
115160
document.addEventListener("mouseup", () => {
116161
document.removeEventListener("mousemove", mousemove);
117162
onResize.value = false;
118-
handleResize();
119163
});
120164
}
165+
function toogleDrawer() {
166+
innerDrawer.value?.toggle();
167+
}
121168
169+
const importStr = ref("");
170+
import { Snackbar } from "sober";
122171
function handleImport() {
123-
const raw = prompt("源数据:");
124-
if (!raw) return;
125-
graphData.value = toInternalDatum(
126-
(JSON5.parse(raw).data as FunctionPlotDatum[]) ?? []
127-
);
172+
if (importStr.value !== "") {
173+
try {
174+
graphData.value = toInternalDatum(
175+
(JSON5.parse(importStr.value).data as FunctionPlotDatum[]) ?? []
176+
);
177+
Snackbar.builder({
178+
text: t("title.importSuccess"),
179+
type: "success",
180+
});
181+
} catch (e) {
182+
Snackbar.builder({
183+
text: t("title.importFail"),
184+
type: "error",
185+
});
186+
}
187+
importStr.value = "";
188+
}
128189
}
190+
191+
const draggerKey = ref(0);
192+
watch(locale, () => draggerKey.value++);
129193
</script>
130194

131195
<style>
132-
#app {
133-
position: fixed;
196+
html,
197+
body {
134198
margin: 0;
135199
padding: 0;
200+
overflow: hidden;
201+
}
202+
s-page {
203+
position: absolute;
136204
top: 0;
137205
bottom: 0;
138206
left: 0;
139207
right: 0;
140-
height: 100vh;
141-
display: flex;
142-
flex-wrap: nowrap;
143-
flex-direction: column;
208+
}
209+
* {
210+
--s-color-outline: #6a757a;
144211
}
145212
#content {
146-
width: 100vw;
147213
flex-grow: 1;
148214
display: flex;
149-
max-height: calc(100vh - 50px);
150-
}
151-
#navbar {
152-
height: 50px;
153-
width: 100vw;
154-
box-sizing: border-box;
155-
background: var(--c-bk1);
156-
border-bottom: var(--c-border) 1px solid;
157-
position: relative;
158-
flex-shrink: 0;
159215
}
160216
#editor {
161-
border-right: var(--c-border) 1px solid;
217+
border-right: var(--s-color-outline-variant) 1px solid;
162218
position: relative;
163219
display: flex;
164220
flex-direction: column;
221+
margin-right: 3px; /* 为宽度调节条留空间 */
165222
}
166223
.editor-inner {
167-
overflow: scroll;
224+
height: 0;
168225
flex-grow: 1;
226+
position: relative;
227+
}
228+
229+
.editor-inner s-scroll-view {
230+
height: 100%;
169231
}
170232
171233
#graph {
172234
flex-grow: 1;
173235
position: relative;
174236
overflow: hidden;
175237
}
176-
.add-data {
177-
padding: 0;
238+
239+
.plot-data.add-data {
240+
position: relative;
241+
padding-top: 15px;
242+
padding-bottom: 15px;
243+
margin-bottom: 50px;
178244
display: flex;
179-
flex-direction: row;
180-
}
181-
.add-data-opt {
182-
padding: 10px 30px;
245+
gap: 5px;
183246
}
184-
.add-data-opt.add {
185-
flex-grow: 1;
186-
}
187-
.add-data-opt:not(:nth-child(1)) {
188-
border-left: 1px solid var(--c-border);
189-
}
190-
.editor-inner {
191-
padding-bottom: 50px;
192-
}
193-
.add-data-opt:hover {
194-
background: var(--c-bk3);
195-
}
196-
.add-data-opt:active {
197-
background: var(--c-bk1);
247+
248+
.data-import {
249+
position: absolute;
250+
bottom: 20px;
251+
right: 20px;
198252
}
199253
200254
#divider {
201-
width: 6px;
202-
background: var(--c-accent);
203-
margin-left: -3px;
204-
margin-right: -3px;
255+
position: absolute;
256+
right: -3px;
257+
top: 0;
258+
bottom: 0;
259+
width: 5px;
260+
background: var(--s-color-secondary);
205261
z-index: 999;
206262
opacity: 0;
207263
transition: opacity 0.1s;

0 commit comments

Comments
 (0)