Skip to content

Commit 2ba2d63

Browse files
committed
chore(refactor): update nav bar, add column view option for mobile
1 parent c543760 commit 2ba2d63

File tree

10 files changed

+94
-195
lines changed

10 files changed

+94
-195
lines changed

source/components/AppEditor.vue

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
<script setup>
2-
import {
3-
Tabs,
4-
TabsList,
5-
TabsTrigger,
6-
} from "@/components/ui/tabs";
2+
import { Button } from '@/components/ui/button';
73
import CodeMirror from "./CodeMirror.vue";
84
import { useAppStore } from "@/store";
5+
import { ref } from 'vue'
96
107
const store = useAppStore();
118
129
const update = (file, data) => {
1310
store.code[file] = data;
1411
};
1512
13+
const currentTab = ref('html')
14+
1615
const tabs = [
1716
["html", "index.html"],
1817
["css", "style.css"],
@@ -21,17 +20,24 @@ const tabs = [
2120
</script>
2221

2322
<template>
24-
<div class="flex flex-col h-full">
25-
<Tabs default-value="html" v-model="store.tab">
26-
<TabsList class="w-full">
27-
<TabsTrigger v-for="tab in tabs" :key="tab[0]" :value="tab[0]">
23+
<div class="flex flex-col h-full relative">
24+
<div
25+
class="flex items-center flex-none pl-5 sm:pl-6 pr-4 lg:pr-6 antialiased border">
26+
<div class="flex">
27+
<Button
28+
v-for="tab in tabs" :key="tab[0]"
29+
variant="ghost"
30+
@click="currentTab = tab[0]"
31+
:class="tab[0] === currentTab ? 'text-blue-500' : 'text-muted-foreground'"
32+
class="relative rounded-none text-sm leading-6 font-semibold">
33+
<span class="absolute bottom-0 inset-x-0 bg-blue-500 h-0.5 rounded-full transition-opacity duration-150" :class="{'opacity-0': tab[0] !== currentTab}"></span>
2834
<span class="uppercase sm:hidden">{{ tab[0] }}</span>
2935
<span class="hidden sm:inline">{{ tab[1] }}</span>
30-
</TabsTrigger>
31-
</TabsList>
32-
</Tabs>
36+
</Button>
37+
</div>
38+
</div>
3339
<div class="flex-grow overflow-y-auto">
34-
<CodeMirror v-for="tab in tabs" :key="tab[0]" :class="store.tab !== tab[0] ? 'hidden' : ''" :file="tab[1]"
40+
<CodeMirror v-for="tab in tabs" :key="tab[0]" :class="currentTab !== tab[0] ? 'hidden' : ''" :file="tab[1]"
3541
:content="store.code[tab[0]]" :lang="tab[0]" @change="(d) => update(tab[0], d)" />
3642
</div>
3743
</div>

source/components/BaseHeader.vue

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,13 @@ import {
1111
MenubarSubTrigger,
1212
MenubarSubContent,
1313
} from './ui/menubar'
14-
import {
15-
Tooltip,
16-
TooltipContent,
17-
TooltipProvider,
18-
TooltipTrigger,
19-
} from './ui/tooltip'
2014
import BaseLogo from './BaseLogo.vue'
21-
import { Button } from './ui/button'
15+
import IconButton from './IconButton.vue'
2216
import SplitView from './icons/SplitView.vue'
2317
import SideView from './icons/SideView.vue'
2418
import { useAppStore } from '@/store'
25-
import { useFullscreen } from '@/helpers/fullscreen';
19+
import { useFullscreen } from '@/helpers/fullscreen'
20+
import { onMounted, onBeforeUnmount } from 'vue'
2621
2722
const fullscreen = useFullscreen()
2823
const store = useAppStore()
@@ -32,6 +27,20 @@ const newTab = () => window.open(window.location.href)
3227
const closeTab = () => window.close()
3328
const reloadTab = () => window.location.reload()
3429
30+
function newTabHandler(ev) {
31+
if (ev.key?.toLowerCase() === 'n' && ev.ctrlKey && ev.altKey) {
32+
newTab()
33+
}
34+
}
35+
36+
onMounted(() => {
37+
document.addEventListener('keydown', newTabHandler, false)
38+
})
39+
40+
onBeforeUnmount(() => {
41+
document.removeEventListener('keydown', newTabHandler)
42+
})
43+
3544
</script>
3645
3746
<template>
@@ -61,8 +70,8 @@ const reloadTab = () => window.location.reload()
6170
<MenubarSubContent>
6271
<MenubarItem @click="switchView('left')">Editor - only</MenubarItem>
6372
<MenubarItem @click="switchView('right')">Preview - only</MenubarItem>
64-
<MenubarItem @click="switchView('split')" class="hidden sm:inline-block">Split View
65-
</MenubarItem>
73+
<MenubarItem @click="switchView('column')">Column View</MenubarItem>
74+
<MenubarItem @click="switchView('row')" class="hidden sm:flex">Row View</MenubarItem>
6675
</MenubarSubContent>
6776
</MenubarSub>
6877
<MenubarSeparator />
@@ -93,41 +102,21 @@ const reloadTab = () => window.location.reload()
93102
</MenubarContent>
94103
</MenubarMenu>
95104
<div class="flex-grow"></div>
96-
<TooltipProvider>
97-
<Tooltip>
98-
<TooltipTrigger>
99-
<Button variant="ghost" size="icon" @click="store.layout = 'left'">
100-
<SideView />
101-
</Button>
102-
</TooltipTrigger>
103-
<TooltipContent>
104-
<p>Editor</p>
105-
</TooltipContent>
106-
</Tooltip>
107-
</TooltipProvider>
108-
<TooltipProvider>
109-
<Tooltip>
110-
<TooltipTrigger>
111-
<Button variant="ghost" size="icon" @click="store.layout = 'split'" class="hidden sm:flex">
112-
<SplitView />
113-
</Button>
114-
</TooltipTrigger>
115-
<TooltipContent>
116-
<p>Split view</p>
117-
</TooltipContent>
118-
</Tooltip>
119-
</TooltipProvider>
120-
<TooltipProvider>
121-
<Tooltip>
122-
<TooltipTrigger>
123-
<Button variant="ghost" size="icon" @click="store.layout = 'right'">
124-
<SideView class="rotate-180" />
125-
</Button>
126-
</TooltipTrigger>
127-
<TooltipContent>
128-
<p>Preview</p>
129-
</TooltipContent>
130-
</Tooltip>
131-
</TooltipProvider>
105+
<IconButton text="Editor" :mobile="true" :active="store.layout === 'left'"
106+
@trigger="() => store.layout = 'left'">
107+
<SideView />
108+
</IconButton>
109+
<IconButton text="Row view" :mobile="false" :active="store.layout === 'row'"
110+
@trigger="() => store.layout = 'row'">
111+
<SplitView />
112+
</IconButton>
113+
<IconButton text="Column view" :mobile="true" :active="store.layout === 'column'"
114+
@trigger="() => store.layout = 'column'">
115+
<SplitView class="rotate-90" />
116+
</IconButton>
117+
<IconButton text="Preview" :mobile="true" :active="store.layout === 'right'"
118+
@trigger="() => store.layout = 'right'">
119+
<SideView class="rotate-180" />
120+
</IconButton>
132121
</Menubar>
133122
</template>

source/components/BaseView.vue

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@ const store = useAppStore()
1212
const panelLeft = ref()
1313
const panelRight = ref()
1414
15+
const verticalAlign = ref(false)
16+
1517
watchEffect(() => {
1618
const view = store.layout
1719
if (view === 'left') viewLeft()
1820
else if (view === 'right') viewRight()
19-
else splitView()
21+
else if (view === 'column') splitView(true)
22+
else splitView(false)
2023
})
2124
22-
function splitView() {
25+
function splitView(column = false) {
2326
panelLeft.value?.expand()
2427
panelRight.value?.expand()
28+
verticalAlign.value = !!column
2529
}
2630
2731
function viewLeft() {
@@ -31,15 +35,16 @@ function viewLeft() {
3135
function viewRight() {
3236
!panelLeft.value?.isCollapsed && panelLeft.value?.collapse()
3337
}
38+
3439
</script>
3540
3641
<template>
37-
<ResizablePanelGroup id="demo-group-1" direction="horizontal" class="bg-yello-300 box">
42+
<ResizablePanelGroup id="demo-group-1" :direction="verticalAlign ? 'vertical' : 'horizontal'" class="bg-yello-300 box">
3843
<ResizablePanel ref="panelLeft" id="demo-panel-1" :default-size="50" collapsible :collapsed-size="0"
3944
:min-size="35" class="overflow-y-auto">
4045
<slot name="left"></slot>
4146
</ResizablePanel>
42-
<ResizableHandle id="demo-handle-1" class="hover:w-1" />
47+
<ResizableHandle id="demo-handle-1" :class="{ 'hover:w-1': !verticalAlign }" />
4348
<ResizablePanel ref="panelRight" id="demo-panel-2" :default-size="50" collapsible :collapsed-size="0"
4449
:min-size="35" class="overflow-y-auto">
4550
<slot name="right"></slot>

source/components/IconButton.vue

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script setup>
2+
import {
3+
Tooltip,
4+
TooltipContent,
5+
TooltipProvider,
6+
TooltipTrigger,
7+
} from './ui/tooltip'
8+
import { Button } from './ui/button'
9+
10+
defineProps(['text', 'active', 'mobile'])
11+
12+
const emit = defineEmits(['trigger'])
13+
</script>
14+
15+
<template>
16+
<TooltipProvider :delay-duration="0">
17+
<Tooltip>
18+
<TooltipTrigger>
19+
<Button variant="ghost" size="icon" @click="emit('trigger')"
20+
:class="[active ? 'text-blue-500' : 'text-muted-foreground', mobile ? '' : 'hidden sm:inline-flex']">
21+
<slot></slot>
22+
</Button>
23+
</TooltipTrigger>
24+
<TooltipContent>
25+
<p>{{ text }}</p>
26+
</TooltipContent>
27+
</Tooltip>
28+
</TooltipProvider>
29+
</template>

source/components/ui/tabs/Tabs.vue

Lines changed: 0 additions & 22 deletions
This file was deleted.

source/components/ui/tabs/TabsContent.vue

Lines changed: 0 additions & 33 deletions
This file was deleted.

source/components/ui/tabs/TabsList.vue

Lines changed: 0 additions & 32 deletions
This file was deleted.

source/components/ui/tabs/TabsTrigger.vue

Lines changed: 0 additions & 37 deletions
This file was deleted.

source/components/ui/tabs/index.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

source/store/index.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ import { useToast } from '@/components/ui/toast/use-toast'
66
const prevSession = restore() || template
77

88
export const useAppStore = defineStore("app", () => {
9-
const layout = ref("split");
10-
11-
const tab = ref("html");
9+
const layout = ref(window.innerWidth < 768 ? 'column' : 'row');
1210

1311
const code = reactive({
1412
html: prevSession['index.html'],
@@ -40,5 +38,5 @@ export const useAppStore = defineStore("app", () => {
4038
}
4139
});
4240

43-
return { layout, code, tab, saveSession };
41+
return { layout, code, saveSession };
4442
});

0 commit comments

Comments
 (0)