diff --git a/memento-note/app/(main)/layout.tsx b/memento-note/app/(main)/layout.tsx
index 579b063..5949e7a 100644
--- a/memento-note/app/(main)/layout.tsx
+++ b/memento-note/app/(main)/layout.tsx
@@ -7,6 +7,7 @@ import { detectUserLanguage, parseAcceptLanguage } from "@/lib/i18n/detect-user-
import { loadTranslations } from "@/lib/i18n/load-translations";
import { getAISettings } from "@/app/actions/ai-settings";
import { AIChatLayoutBridge } from "@/components/ai-chat-layout-bridge";
+import { SidebarResizeClient } from "@/components/sidebar-resize-client";
export default async function MainLayout({
@@ -36,8 +37,8 @@ export default async function MainLayout({
initialAiProcessingConsent={aiSettings?.aiProcessingConsent === true}
>
{/* No top-bar header — sidebar-only navigation (architectural-grid design) */}
-
-
}>
+
+ }>
@@ -47,9 +48,9 @@ export default async function MainLayout({
{children}
+
- {showAIAssistant &&
}
-
+ {showAIAssistant && }
);
}
diff --git a/memento-note/components/sidebar-resize-client.tsx b/memento-note/components/sidebar-resize-client.tsx
new file mode 100644
index 0000000..9329ef1
--- /dev/null
+++ b/memento-note/components/sidebar-resize-client.tsx
@@ -0,0 +1,19 @@
+'use client'
+
+import { type ReactNode } from 'react'
+import { useSidebarResize, SidebarResizeHandle } from '@/components/sidebar-resize'
+
+export function SidebarResizeClient({ children }: { children: ReactNode }) {
+ const { width, isDragging, onPointerDown } = useSidebarResize()
+
+ return (
+
+ )
+}
diff --git a/memento-note/components/sidebar-resize.tsx b/memento-note/components/sidebar-resize.tsx
new file mode 100644
index 0000000..1bf6bb7
--- /dev/null
+++ b/memento-note/components/sidebar-resize.tsx
@@ -0,0 +1,81 @@
+'use client'
+
+import { useCallback, useEffect, useRef, useState } from 'react'
+
+const STORAGE_KEY = 'memento-sidebar-width'
+const MIN = 280
+const MAX = 560
+
+export function useSidebarResize() {
+ const [width, setWidth] = useState(320)
+ const [isDragging, setIsDragging] = useState(false)
+ const startXRef = useRef(0)
+ const startWidthRef = useRef(320)
+
+ useEffect(() => {
+ const stored = localStorage.getItem(STORAGE_KEY)
+ if (stored) {
+ const parsed = parseInt(stored, 10)
+ if (!isNaN(parsed) && parsed >= MIN && parsed <= MAX) {
+ setWidth(parsed)
+ }
+ }
+ }, [])
+
+ const onPointerDown = useCallback((e: React.PointerEvent) => {
+ e.preventDefault()
+ setIsDragging(true)
+ startXRef.current = e.clientX
+ startWidthRef.current = width
+ document.body.style.cursor = 'col-resize'
+ document.body.style.userSelect = 'none'
+ }, [width])
+
+ useEffect(() => {
+ if (!isDragging) return
+
+ const onPointerMove = (e: PointerEvent) => {
+ const delta = e.clientX - startXRef.current
+ const newWidth = Math.max(MIN, Math.min(MAX, startWidthRef.current + delta))
+ setWidth(newWidth)
+ }
+
+ const onPointerUp = () => {
+ setIsDragging(false)
+ document.body.style.cursor = ''
+ document.body.style.userSelect = ''
+ setWidth(prev => {
+ localStorage.setItem(STORAGE_KEY, String(prev))
+ return prev
+ })
+ }
+
+ document.addEventListener('pointermove', onPointerMove)
+ document.addEventListener('pointerup', onPointerUp)
+ return () => {
+ document.removeEventListener('pointermove', onPointerMove)
+ document.removeEventListener('pointerup', onPointerUp)
+ }
+ }, [isDragging])
+
+ return { width, isDragging, onPointerDown }
+}
+
+export function SidebarResizeHandle({ onPointerDown, isDragging }: { onPointerDown: (e: React.PointerEvent) => void; isDragging: boolean }) {
+ return (
+
+ )
+}
+
+export { MIN as SIDEBAR_MIN_WIDTH, MAX as SIDEBAR_MAX_WIDTH }