Skip to content
This repository was archived by the owner on May 1, 2025. It is now read-only.

Commit d7dcb03

Browse files
committed
ui: improve files tree panel bar
1 parent ed409ea commit d7dcb03

File tree

6 files changed

+123
-91
lines changed

6 files changed

+123
-91
lines changed

components/FileIcon.vue

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<script setup lang="ts">
2+
const props = defineProps<{
3+
path: string
4+
isDirectory?: boolean
5+
isDirectoryOpen?: boolean
6+
}>()
7+
8+
const FILE_ICONS = [
9+
{
10+
match: /\.vue$/,
11+
icon: 'i-logos-vue',
12+
},
13+
{
14+
match: /nuxt\.config\.\w+$/,
15+
icon: 'i-logos-nuxt-icon scale-110',
16+
},
17+
{
18+
match: /package\.json$/,
19+
icon: 'i-file-icons-npm text-red scale-110',
20+
},
21+
{
22+
match: /\.[mc]?tsx?$/,
23+
icon: 'i-file-icons-typescript-alt text-blue3',
24+
},
25+
{
26+
match: /\.[mc]?jsx?$/,
27+
icon: 'i-devicon-javascript',
28+
},
29+
]
30+
31+
const icon = computed(() => {
32+
if (props.isDirectory) {
33+
return props.isDirectoryOpen
34+
? 'i-ph:folder-open-duotone scale-120'
35+
: 'i-ph:folder-simple-duotone scale-120'
36+
}
37+
for (const { match, icon } of FILE_ICONS) {
38+
if (match.test(props.path))
39+
return icon
40+
}
41+
return 'i-ph:file-duotone scale-120'
42+
})
43+
</script>
44+
45+
<template>
46+
<div :class="icon" />
47+
</template>

components/PanelDocs.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ const sourceUrl = computed(() => page.value?._file
1111
<div h-full grid="~ rows-[min-content_1fr_min-content]">
1212
<div flex="~ gap-2 items-center" border="b base dashed" bg-faded px4 py2>
1313
<div i-ph-book-duotone />
14-
<span text-sm>Guide</span>
14+
<NuxtLink to="/" text-sm>
15+
Guide
16+
</NuxtLink>
1517
</div>
1618
<article class="max-w-none prose" of-auto p6>
1719
<ContentDoc />

components/PanelEditor.vue

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -44,60 +44,75 @@ const panelInitEditor = computed(() => isMounted.value || {
4444
</script>
4545

4646
<template>
47-
<div
48-
h-full
49-
grid="~ rows-[min-content_1fr]"
47+
<Splitpanes
48+
of-hidden
49+
:class="guide.features.fileTree === false ? 'disabled' : ''"
50+
@resize="startDragging"
51+
@resized="endDragging"
5052
>
51-
<div
52-
flex="~ gap-2 items-center"
53-
border="b base dashed"
54-
bg-faded px4 py2
53+
<Pane
54+
flex="~ col" h-full of-auto
55+
:size="ui.panelFileTree"
56+
:style="panelInitFileTree"
5557
>
56-
<div i-ph-text-t-duotone />
57-
<span text-sm>Editor</span>
58-
<div flex-auto />
59-
<button
60-
v-if="guide.currentGuide?.solutions"
61-
my--1 mr--3 rounded px2 py1 text-sm op50
62-
hover="bg-active op100"
63-
flex="~ gap-2 items-center"
64-
@click="guide.toggleSolutions()"
58+
<div
59+
h-full
60+
grid="~ rows-[min-content_1fr]"
6561
>
66-
<div v-if="!guide.showingSolution " i-ph-lightbulb-filament-duotone />
67-
<div v-else i-ph-arrow-counter-clockwise-duotone />
68-
{{ guide.showingSolution ? 'Reset challenge' : 'Show solution' }}
69-
</button>
70-
</div>
71-
<Splitpanes
72-
of-hidden
73-
:class="guide.features.fileTree === false ? 'disabled' : ''"
74-
@resize="startDragging"
75-
@resized="endDragging"
62+
<div
63+
flex="~ gap-2 items-center"
64+
border="b base dashed"
65+
bg-faded px4 py2
66+
>
67+
<div i-ph-tree-structure-duotone />
68+
<span text-sm>Files</span>
69+
</div>
70+
<div py2>
71+
<PanelEditorFileSystemTree
72+
v-model="play.fileSelected"
73+
:directory="directory"
74+
:depth="-1"
75+
/>
76+
</div>
77+
</div>
78+
</Pane>
79+
<PaneSplitter />
80+
<Pane
81+
:size="100 - ui.panelFileTree"
82+
:style="panelInitEditor"
7683
>
77-
<Pane
78-
flex="~ col" h-full of-auto py1
79-
:size="ui.panelFileTree"
80-
:style="panelInitFileTree"
81-
>
82-
<PanelEditorFileSystemTree
83-
v-model="play.fileSelected"
84-
:directory="directory"
85-
:depth="-1"
86-
/>
87-
</Pane>
88-
<PaneSplitter />
89-
<Pane
90-
:size="100 - ui.panelFileTree"
91-
:style="panelInitEditor"
84+
<div
85+
h-full
86+
grid="~ rows-[min-content_1fr]"
9287
>
88+
<div
89+
flex="~ gap-2 items-center"
90+
border="b base dashed"
91+
bg-faded px4 py2
92+
>
93+
<FileIcon :path="play.fileSelected?.filepath || ''" />
94+
<span text-sm>{{ play.fileSelected?.filepath || 'Editor' }}</span>
95+
<div flex-auto />
96+
<button
97+
v-if="guide.currentGuide?.solutions"
98+
my--1 mr--3 rounded px2 py1 text-sm op50
99+
hover="bg-active op100"
100+
flex="~ gap-2 items-center"
101+
@click="guide.toggleSolutions()"
102+
>
103+
<div v-if="!guide.showingSolution " i-ph-lightbulb-filament-duotone />
104+
<div v-else i-ph-arrow-counter-clockwise-duotone />
105+
{{ guide.showingSolution ? 'Reset challenge' : 'Show solution' }}
106+
</button>
107+
</div>
93108
<LazyPanelEditorMonaco
94109
v-if="play.fileSelected"
95110
v-model="input"
96111
:filepath="play.fileSelected.filepath"
97112
h-full w-full
98113
@change="onTextInput"
99114
/>
100-
</Pane>
101-
</Splitpanes>
102-
</div>
115+
</div>
116+
</Pane>
117+
</Splitpanes>
103118
</template>

components/PanelEditorFileSystemTree.vue

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,6 @@
11
<script lang="ts">
22
import type { VirtualFile } from '~/structures/VirtualFile'
33
import type { VirtualFileSystemTree } from '~/structures/VirtualFileSystemTree'
4-
5-
const FILE_ICONS = [
6-
{
7-
match: /\.vue$/,
8-
icon: 'i-logos-vue',
9-
},
10-
{
11-
match: /nuxt\.config\.\w+$/,
12-
icon: 'i-logos-nuxt-icon scale-110',
13-
},
14-
{
15-
match: /package\.json$/,
16-
icon: 'i-file-icons-npm text-red scale-110',
17-
},
18-
{
19-
match: /\.[mc]?tsx?$/,
20-
icon: 'i-file-icons-typescript-alt text-blue3',
21-
},
22-
{
23-
match: /\.[mc]?jsx?$/,
24-
icon: 'i-devicon-javascript',
25-
},
26-
]
27-
28-
function getFileIcon(filepath: string): string {
29-
for (const { match, icon } of FILE_ICONS) {
30-
if (match.test(filepath))
31-
return icon
32-
}
33-
return 'i-ph:file-duotone scale-120'
34-
}
354
</script>
365

376
<script setup lang="ts">
@@ -67,17 +36,6 @@ const sortedDirectory = computed(() => props.directory && Object.fromEntries(
6736
}),
6837
))
6938
70-
const icon = computed(() => {
71-
if (props.directory) {
72-
return isDirectoryOpen.value
73-
? 'i-ph:folder-open-duotone scale-120'
74-
: 'i-ph:folder-simple-duotone scale-120'
75-
}
76-
else {
77-
return getFileIcon(props.name!)
78-
}
79-
})
80-
8139
const folderCaret = computed(() => {
8240
const icon = 'i-ph-caret-right transition-transform duration-300 op50'
8341
if (props.directory) {
@@ -104,7 +62,12 @@ const folderCaret = computed(() => {
10462
@click="handleClick"
10563
>
10664
<div :class="folderCaret" h-4 w-4 flex-none />
107-
<div :class="icon" h-4 w-4 flex-none />
65+
<FileIcon
66+
h-4 w-4 flex-none
67+
:path="name"
68+
:is-directory="!!props.directory"
69+
:is-directory-open="isDirectoryOpen"
70+
/>
10871
<span ml1>{{ name }}</span>
10972
</button>
11073
<div v-if="directory" v-show="isDirectoryOpen">

stores/guide.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import type { Raw } from 'vue'
22
import type { GuideMeta, PlaygroundFeatures } from '~/types/guides'
33

4+
const defaultFeatures: PlaygroundFeatures = Object.freeze({
5+
fileTree: false,
6+
terminal: false,
7+
})
8+
49
export const useGuideStore = defineStore('guide', () => {
510
const play = usePlaygroundStore()
611
const ui = useUiState()
712
const preview = usePreviewStore()
813

9-
const features = ref<PlaygroundFeatures>({})
14+
const features = ref<PlaygroundFeatures>(defaultFeatures)
1015
const currentGuide = shallowRef<Raw<GuideMeta>>()
1116
const showingSolution = ref(false)
1217
const embeddedDocs = ref('')
@@ -41,7 +46,7 @@ export const useGuideStore = defineStore('guide', () => {
4146
preview.location.fullPath = guide?.startingUrl || '/'
4247
preview.updateUrl()
4348

44-
features.value = guide?.features || {}
49+
features.value = guide?.features || defaultFeatures
4550
currentGuide.value = guide
4651
showingSolution.value = withSolution
4752

stores/ui.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const useUiState = defineStore('ui', () => {
88
panelDocs: 30,
99
panelEditor: 60,
1010
panelPreview: 40,
11-
panelFileTree: 0,
11+
panelFileTree: 20,
1212
showTerminal: false,
1313
}
1414
}

0 commit comments

Comments
 (0)