Skip to content

Commit b686053

Browse files
author
codewec
committed
feat: collapse sidebar
1 parent 196a2be commit b686053

9 files changed

Lines changed: 93 additions & 4 deletions

File tree

app/components/editoro/MainHeader.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<script setup lang="ts">
22
import type { EditorPinnedBadge, SaveStatusColor } from '~/types/editoro'
33
4+
const { t } = useI18n()
5+
46
const props = defineProps<{
7+
showExpandSidebarButton: boolean
58
editorModeLabel: string
69
editorModeIcon: string
710
editorModeTooltip: string
@@ -14,6 +17,7 @@ const props = defineProps<{
1417
}>()
1518
1619
const emit = defineEmits<{
20+
expandSidebar: []
1721
toggleMode: []
1822
selectBadge: [path: string]
1923
togglePin: [path: string]
@@ -24,6 +28,16 @@ const emit = defineEmits<{
2428

2529
<template>
2630
<header class="editoro-main-header">
31+
<UButton
32+
v-if="props.showExpandSidebarButton"
33+
size="xs"
34+
color="neutral"
35+
variant="soft"
36+
icon="i-lucide-panel-left-open"
37+
:aria-label="t('sidebar.expand')"
38+
@click="emit('expandSidebar')"
39+
/>
40+
2741
<EditoroHeaderModeToggle
2842
:label="props.editorModeLabel"
2943
:icon="props.editorModeIcon"

app/components/editoro/Sidebar.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const emit = defineEmits<{
3535
treeDragLeave: []
3636
refresh: []
3737
toggleHidden: []
38+
collapse: []
3839
openSettings: []
3940
closeSettings: []
4041
changeLocale: [value: string]
@@ -77,6 +78,15 @@ const {
7778
</h1>
7879

7980
<div class="editoro-actions">
81+
<UButton
82+
icon="i-lucide-panel-left-close"
83+
size="xs"
84+
color="neutral"
85+
variant="soft"
86+
:aria-label="t('sidebar.collapse')"
87+
@click="emit('collapse')"
88+
/>
89+
8090
<UButton
8191
icon="i-lucide-settings-2"
8292
size="xs"

app/components/editoro/Workspace.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const {
3737
<template>
3838
<div class="editoro-layout">
3939
<EditoroSidebar
40+
v-if="!editoro.ui.isSidebarCollapsed.value"
4041
v-model:selected-node="selectedNode"
4142
v-model:expanded-tree-paths="expandedPaths"
4243
v-bind="sidebarProps"
@@ -47,6 +48,7 @@ const {
4748
@close-settings="sidebarHandlers.closeSettings"
4849
@change-locale="sidebarHandlers.changeLocale"
4950
@change-color-mode="sidebarHandlers.changeColorMode"
51+
@collapse="sidebarHandlers.collapse"
5052
@sidebar-resize-start="sidebarHandlers.sidebarResizeStart"
5153
@root-drop="sidebarHandlers.rootDrop"
5254
@tree-drag-start="sidebarHandlers.treeDragStart"
@@ -59,6 +61,8 @@ const {
5961
<main class="editoro-main">
6062
<EditoroMainHeader
6163
v-bind="mainHeaderProps"
64+
:show-expand-sidebar-button="editoro.ui.isSidebarCollapsed.value"
65+
@expand-sidebar="mainHeaderHandlers.expandSidebar"
6266
@toggle-mode="mainHeaderHandlers.toggleMode"
6367
@select-badge="mainHeaderHandlers.selectBadge"
6468
@toggle-pin="mainHeaderHandlers.togglePin"

app/composables/api/buildUiApi.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export function buildUiApi(options: BuildEditoroApiOptions) {
1010

1111
return {
1212
sidebarWidth: uiRefs.sidebarWidth,
13+
isSidebarCollapsed: uiRefs.isSidebarCollapsed,
1314
minSidebarWidth: uiStore.minSidebarWidth,
1415
maxSidebarWidth: uiStore.maxSidebarWidth,
1516
createModalOpen: uiRefs.createModalOpen,
@@ -18,6 +19,9 @@ export function buildUiApi(options: BuildEditoroApiOptions) {
1819
renameModalOpen: uiRefs.renameModalOpen,
1920
renameInputName: uiRefs.renameInputName,
2021
deleteModalOpen: uiRefs.deleteModalOpen,
21-
onSidebarResizeStart: uiStore.onSidebarResizeStart
22+
onSidebarResizeStart: uiStore.onSidebarResizeStart,
23+
collapseSidebar: uiStore.collapseSidebar,
24+
expandSidebar: uiStore.expandSidebar,
25+
toggleSidebarCollapsed: uiStore.toggleSidebarCollapsed
2226
}
2327
}

app/composables/workspace/useEditoroMainHeaderBindings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
* Prepares main-header props and handlers for `Workspace.vue`.
33
* Used by `app/composables/useEditoroWorkspaceBindings.ts`.
44
*/
5+
import { unref } from 'vue'
56
import type { EditoroState } from '~/composables/workspace/types'
67

78
export function useEditoroMainHeaderBindings(state: EditoroState) {
89
const mainHeaderProps = computed(() => ({
10+
showExpandSidebarButton: unref(state.ui.isSidebarCollapsed),
911
editorModeLabel: state.editor.modeLabel.value,
1012
editorModeIcon: state.editor.modeIcon.value,
1113
editorModeTooltip: state.editor.modeTooltip.value,
@@ -18,6 +20,7 @@ export function useEditoroMainHeaderBindings(state: EditoroState) {
1820
}))
1921

2022
const mainHeaderHandlers = {
23+
expandSidebar: state.ui.expandSidebar,
2124
toggleMode: state.editor.toggleMode,
2225
selectBadge: (path: string) => {
2326
if (!path) {

app/composables/workspace/useEditoroSidebarBindings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export function useEditoroSidebarBindings(state: EditoroState) {
2929
closeSettings: state.settings.closeModal,
3030
changeLocale: state.settings.setLocale,
3131
changeColorMode: state.settings.setColorMode,
32+
collapse: state.ui.collapseSidebar,
3233
sidebarResizeStart: state.ui.onSidebarResizeStart,
3334
rootDrop: state.tree.onRootDrop,
3435
treeDragStart: state.tree.onDragStart,

app/stores/editoroUi.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,33 @@ function parseSidebarWidth(raw: string | undefined) {
2020
return clampSidebarWidth(parsed)
2121
}
2222

23+
function parseCollapsedState(raw: unknown) {
24+
if (!raw) {
25+
return false
26+
}
27+
28+
if (typeof raw === 'boolean') {
29+
return raw
30+
}
31+
32+
if (typeof raw === 'number') {
33+
return raw === 1
34+
}
35+
36+
if (typeof raw !== 'string') {
37+
return false
38+
}
39+
40+
const normalized = raw.trim().toLowerCase()
41+
return normalized === '1' || normalized === 'true' || normalized === 'yes'
42+
}
43+
2344
export const useEditoroUiStore = defineStore('editoro-ui', () => {
2445
const sidebarWidthCookie = useCookie<string>('editoro.sidebar.width', { path: '/', sameSite: 'lax' })
46+
const sidebarCollapsedCookie = useCookie<string>('editoro.sidebar.collapsed', { path: '/', sameSite: 'lax' })
2547

2648
const sidebarWidth = ref(parseSidebarWidth(sidebarWidthCookie.value))
49+
const isSidebarCollapsed = ref(parseCollapsedState(sidebarCollapsedCookie.value))
2750
const isResizingSidebar = ref(false)
2851
const sidebarResizeStartX = ref(0)
2952
const sidebarResizeStartWidth = ref(sidebarWidth.value)
@@ -59,7 +82,7 @@ export const useEditoroUiStore = defineStore('editoro-ui', () => {
5982
}
6083

6184
function onSidebarResizeStart(event: MouseEvent) {
62-
if (!import.meta.client) {
85+
if (!import.meta.client || isSidebarCollapsed.value) {
6386
return
6487
}
6588

@@ -72,6 +95,24 @@ export const useEditoroUiStore = defineStore('editoro-ui', () => {
7295
window.addEventListener('mouseup', stopSidebarResize)
7396
}
7497

98+
function collapseSidebar() {
99+
stopSidebarResize()
100+
isSidebarCollapsed.value = true
101+
}
102+
103+
function expandSidebar() {
104+
isSidebarCollapsed.value = false
105+
}
106+
107+
function toggleSidebarCollapsed() {
108+
if (isSidebarCollapsed.value) {
109+
expandSidebar()
110+
return
111+
}
112+
113+
collapseSidebar()
114+
}
115+
75116
function openCreateModal(type: CreateTargetType) {
76117
createTargetType.value = type
77118
createInputPath.value = ''
@@ -103,10 +144,15 @@ export const useEditoroUiStore = defineStore('editoro-ui', () => {
103144
sidebarWidthCookie.value = String(clampSidebarWidth(value))
104145
})
105146

147+
watch(isSidebarCollapsed, (value) => {
148+
sidebarCollapsedCookie.value = value ? '1' : '0'
149+
}, { immediate: true })
150+
106151
return {
107152
minSidebarWidth: MIN_SIDEBAR_WIDTH,
108153
maxSidebarWidth: MAX_SIDEBAR_WIDTH,
109154
sidebarWidth,
155+
isSidebarCollapsed,
110156
createModalOpen,
111157
createTargetType,
112158
createInputPath,
@@ -115,6 +161,9 @@ export const useEditoroUiStore = defineStore('editoro-ui', () => {
115161
deleteModalOpen,
116162
onSidebarResizeStart,
117163
stopSidebarResize,
164+
collapseSidebar,
165+
expandSidebar,
166+
toggleSidebarCollapsed,
118167
openCreateModal,
119168
closeCreateModal,
120169
openRenameModal,

i18n/locales/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
"createFolder": "Create folder",
1717
"loadingTree": "Loading tree...",
1818
"moveToRoot": "Drop here to move to root",
19-
"settings": "Settings"
19+
"settings": "Settings",
20+
"collapse": "Collapse sidebar",
21+
"expand": "Expand sidebar"
2022
},
2123
"settings": {
2224
"title": "Settings",

i18n/locales/ru.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
"createFolder": "Создать папку",
1717
"loadingTree": "Загрузка дерева...",
1818
"moveToRoot": "Перетащите сюда для перемещения в корень",
19-
"settings": "Настройки"
19+
"settings": "Настройки",
20+
"collapse": "Свернуть боковую панель",
21+
"expand": "Развернуть боковую панель"
2022
},
2123
"settings": {
2224
"title": "Настройки",

0 commit comments

Comments
 (0)