Skip to content

Commit f610a0a

Browse files
committed
Add app bar
1 parent d9a048b commit f610a0a

File tree

10 files changed

+267
-17
lines changed

10 files changed

+267
-17
lines changed

package-lock.json

Lines changed: 8 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
@@ -23,6 +23,7 @@
2323
"@types/md5": "^2.3.2",
2424
"@types/qs": "^6.9.14",
2525
"@typescript-eslint/eslint-plugin": "^8.46.0",
26+
"@vicons/ionicons5": "^0.13.0",
2627
"@vitejs/plugin-vue": "^6.0.1",
2728
"@vue/eslint-config-typescript": "^14.6.0",
2829
"@vue/tsconfig": "^0.8.1",

src/App.vue

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,33 @@
11
<template>
22
<n-config-provider>
3-
<n-split direction="horizontal" :resize-trigger-size="8" v-model:size="width">
4-
<template #1>
5-
<editor v-model:content="editorStore.content" v-model:selection="editorStore.selection"
6-
v-model:scroll="editorStore.scroll" :icons="iconStore.icons" :size="editorStore.size" />
7-
</template>
8-
<template #2>
9-
<scroller v-model:scroll="editorStore.scroll">
10-
<BSMap :map="ast" :size="editorStore.size" />
11-
</scroller>
12-
</template>
13-
<template #resize-trigger>
14-
<div :class="$style.resizer">
15-
</div>
16-
</template>
17-
</n-split>
3+
<div :class="$style.container">
4+
<n-split :class="$style.main" direction="horizontal" :resize-trigger-size="8" v-model:size="width">
5+
<template #1>
6+
<editor v-model:content="editorStore.content" v-model:selection="editorStore.selection"
7+
v-model:scroll="editorStore.scroll" :icons="iconStore.icons" :size="editorStore.size" />
8+
</template>
9+
<template #2>
10+
<scroller v-model:scroll="editorStore.scroll">
11+
<BSMap :map="ast" :size="editorStore.size" />
12+
</scroller>
13+
</template>
14+
<template #resize-trigger>
15+
<div :class="$style.resizer" />
16+
</template>
17+
</n-split>
18+
<app-bar>
19+
<template #1>
20+
<size-setter />
21+
</template>
22+
<template #2>
23+
<cursor-position :map="ast" />
24+
</template>
25+
<template #3>
26+
<icon-status />
27+
<help-menu />
28+
</template>
29+
</app-bar>
30+
</div>
1831
</n-config-provider>
1932
</template>
2033

@@ -33,6 +46,12 @@ import { useIconStore } from '@/stores/icon';
3346
import Scroller from './components/Scroller.vue';
3447
import BSMap from './components/BSMap.vue';
3548
import Editor from './components/Editor.vue';
49+
import AppBar from './components/AppBar.vue';
50+
51+
import SizeSetter from './components/AppBar/SizeSetter.vue';
52+
import CursorPosition from './components/AppBar/CursorPosition.vue';
53+
import IconStatus from './components/AppBar/IconStatus.vue';
54+
import HelpMenu from './components/AppBar/HelpMenu.vue';
3655
3756
const editorStore = useEditorStore();
3857
const iconStore = useIconStore();
@@ -63,6 +82,17 @@ const ast = computed(() => parseMap(editorStore.content));
6382
overscroll-behavior: none;
6483
}
6584
85+
.container {
86+
display: flex;
87+
flex-direction: column;
88+
height: 100vh;
89+
}
90+
91+
.main {
92+
flex: 1 1 auto;
93+
min-height: 0;
94+
}
95+
6696
.resizer {
6797
height: 100%;
6898
background: #cccccc;

src/components/AppBar.vue

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<template>
2+
<n-flex align="center" justify="space-between" :class="$style.appBar">
3+
<n-space align="center">
4+
<n-space align="center">
5+
<slot name="1" />
6+
</n-space>
7+
<n-divider vertical />
8+
<n-space align="center">
9+
<slot name="2" />
10+
</n-space>
11+
</n-space>
12+
<n-space align="center">
13+
<slot name="3" />
14+
</n-space>
15+
</n-flex>
16+
</template>
17+
18+
<script lang="ts" setup>
19+
import { NDivider, NFlex, NSpace } from 'naive-ui';
20+
</script>
21+
22+
<style lang="scss" module>
23+
.appBar {
24+
border-top: 1px solid #ddd;
25+
padding: 2px 16px;
26+
}
27+
</style>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<template>
2+
<n-element :class="$style.position">
3+
Ln {{ rowIndex + 1 }}{{ position ? `, ${position}` : '' }} | Row {{ currentCols }} / Max {{ maxCols }}
4+
</n-element>
5+
</template>
6+
7+
<script lang="ts" setup>
8+
import { computed } from 'vue';
9+
import { NElement } from 'naive-ui';
10+
import { max } from 'radash';
11+
12+
import type { RDTMap } from '@/ast';
13+
import { useEditorStore } from '@/stores/editor';
14+
15+
const props = defineProps<{
16+
map: RDTMap;
17+
}>();
18+
19+
const editorStore = useEditorStore();
20+
21+
const rowIndex = computed(() => editorStore.selection?.row ?? 0);
22+
23+
const position = computed(() => {
24+
const { selection } = editorStore;
25+
if (!selection) return undefined;
26+
27+
const row = props.map.rows[selection.row];
28+
if (!row || row.kind !== 'row') return undefined;
29+
30+
const lInfo = row.lInfo.find(({ offset, length }) =>
31+
selection.offset >= offset - row.offset && selection.offset <= offset - row.offset + length
32+
);
33+
if (lInfo) {
34+
return `Left Info #${lInfo.column}`;
35+
}
36+
37+
const rInfo = row.rInfo.find(({ offset, length }) =>
38+
selection.offset >= offset - row.offset && selection.offset <= offset - row.offset + length
39+
);
40+
if (rInfo) {
41+
return `Right Info #${rInfo.column}`;
42+
}
43+
44+
const cell = row.cells.findIndex(({ offset, length }) =>
45+
selection.offset >= offset - row.offset && selection.offset <= offset - row.offset + length
46+
);
47+
if (cell != -1) {
48+
return `Col ${cell + 1}`;
49+
}
50+
51+
return undefined;
52+
});
53+
54+
const currentCols = computed(() => {
55+
const row = props.map.rows[rowIndex.value];
56+
if (!row || row.kind !== 'row') return 0;
57+
return row.cells.length;
58+
});
59+
60+
const maxCols = computed(() => max(props.map.rows
61+
.filter((row) => row.kind == 'row')
62+
.map((row) => row.cells.length)
63+
) || 1);
64+
</script>
65+
66+
<style lang="scss" module>
67+
.position {
68+
font-size: var(--font-size-tiny);
69+
color: var(--text-color-1);
70+
}
71+
</style>

src/components/AppBar/HelpMenu.vue

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<template>
2+
<n-dropdown trigger="click" placement="top-end" :show-arrow="false" :options="options">
3+
<n-button quaternary size="tiny" block>
4+
<template #icon>
5+
<n-icon>
6+
<EllipsisHorizontal />
7+
</n-icon>
8+
</template>
9+
</n-button>
10+
</n-dropdown>
11+
</template>
12+
13+
<script lang="ts" setup>
14+
import { h } from 'vue';
15+
import {
16+
NButton,
17+
NDropdown,
18+
NIcon,
19+
type DropdownOption,
20+
} from 'naive-ui';
21+
import { EllipsisHorizontal } from '@vicons/ionicons5';
22+
23+
const options: DropdownOption[] = [
24+
{
25+
key: 'feedback',
26+
label: () => h('a', {
27+
href: 'https://github.com/xingrz/rdt-editor/issues/new',
28+
target: '_blank',
29+
}, 'Feedback'),
30+
},
31+
{
32+
key: 'about',
33+
label: () => h('a', {
34+
href: 'https://github.com/xingrz/rdt-editor',
35+
target: '_blank',
36+
}, 'About RDT Editor'),
37+
},
38+
];
39+
</script>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<template>
2+
<n-element :class="$style.status">
3+
<template v-if="loading > 0">
4+
Loading {{ loading }} icons…
5+
</template>
6+
<template v-else>
7+
<n-icon :size="14" :color="themeVars.textColor2" :style="{ marginRight: '0.5em' }">
8+
<CheckmarkDone />
9+
</n-icon>
10+
Cached {{ ready }} icons
11+
</template>
12+
</n-element>
13+
</template>
14+
15+
<script lang="ts" setup>
16+
import { NElement, NIcon, useThemeVars } from 'naive-ui';
17+
import { computed } from 'vue';
18+
import { CheckmarkDone } from '@vicons/ionicons5';
19+
20+
import { useIconStore } from '@/stores/icon';
21+
22+
const themeVars = useThemeVars();
23+
const iconStore = useIconStore();
24+
25+
const loading = computed(() => Object.values(iconStore.icons).filter((icon) => icon.status === 'loading').length);
26+
const ready = computed(() => Object.values(iconStore.icons).filter((icon) => icon.status === 'ready').length);
27+
</script>
28+
29+
<style lang="scss" module>
30+
.status {
31+
font-size: var(--font-size-tiny);
32+
color: var(--text-color-1);
33+
display: flex;
34+
align-items: center;
35+
}
36+
</style>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<template>
2+
<n-popover trigger="click" placement="top-start" :show-arrow="false">
3+
<template #trigger>
4+
<n-button quaternary size="tiny" block>
5+
<template #icon>
6+
<n-icon>
7+
<CopyOutline />
8+
</n-icon>
9+
</template>
10+
{{ editorStore.size }}px
11+
</n-button>
12+
</template>
13+
<div :class="$style.setter">
14+
<n-slider v-model:value="editorStore.size" :min="20" :max="60" />
15+
</div>
16+
</n-popover>
17+
</template>
18+
19+
<script lang="ts" setup>
20+
import {
21+
NButton,
22+
NIcon,
23+
NPopover,
24+
NSlider,
25+
} from 'naive-ui';
26+
import { CopyOutline } from '@vicons/ionicons5';
27+
28+
import { useEditorStore } from '@/stores/editor';
29+
30+
const editorStore = useEditorStore();
31+
</script>
32+
33+
<style lang="scss" module>
34+
.setter {
35+
width: 200px;
36+
padding: 8px var(--n-option-prefix-width);
37+
}
38+
</style>

src/components/Editor.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div ref="holder" :style="{
33
width: `100%`,
4-
height: `100vh`,
4+
height: `100%`,
55
lineHeight: `${size}px`,
66
}" />
77
</template>

src/components/Scroller.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function onScroll(): void {
3333

3434
<style lang="scss" module>
3535
.scroller {
36-
height: 100vh;
36+
height: 100%;
3737
overflow-y: scroll;
3838
overflow-x: hidden;
3939
background: #f9f9f9;

0 commit comments

Comments
 (0)