ui: Settings window shell — header nav, empty body, footer status bar, more-menu modal

This commit is contained in:
Hermes Agent committed 2026-09-19 12:57:16 +02:00
1 parent c7aa5033d2
commit 0fdd6164ed
1 file changed
+58 -20
+58 -20
View File
@@ -4,9 +4,16 @@ import {
Text,
Muted,
VerticalSpace,
Divider,
Button,
Stack,
Modal,
IconButton,
IconExpand24,
IconCollapse24
IconCollapse24,
IconMore24,
IconWand24,
IconComponent24
} from '@create-figma-plugin/ui'
import { emit, on } from '@create-figma-plugin/utilities'
import { h, Fragment } from 'preact'
@@ -17,6 +24,9 @@ const MIN_WINDOW_SIZE = { width: 320, height: 200 }
// and the upper bound of drag-resize also comes from there. useWindowResize max is set
// very high — actual clamp is done by main via clampWindowSize (bounds*zoom).
// Full plugin version shown in the footer status bar. Keep in sync with package.json "version".
const PLUGIN_VERSION = '0.1.0'
function Plugin () {
const [currentWindowSize, setCurrentWindowSize] = useState(MIN_WINDOW_SIZE)
const resizeRef = useRef({ active: false, dir: '', startX: 0, startY: 0, startW: 0, startH: 0, fixedAxis: 'none' as 'none' | 'x' | 'y' })
@@ -275,6 +285,7 @@ function Plugin () {
})
}
const [moreOpen, setMoreOpen] = useState(false)
const [isMaxToggled, setIsMaxToggled] = useState(false)
// Resize-handle visibility is state-driven (not CSS :hover/:has) for Figma webview
// reliability. Handles appear only after the cursor has rested in the window for 500ms
@@ -310,27 +321,54 @@ function Plugin () {
return (
<div className="plugin-root" style={{ position: 'relative', width: '100%', height: '100%' }}>
<Container space="medium" style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
<div
style={{
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column'
}}
>
<Text style={{ fontSize: '13px', fontWeight: 600 }}>Hello, Figma ✦</Text>
<VerticalSpace space="small" />
<Muted>AI assistant (MVP) — bootstrap</Muted>
{/* Header — navigation bar: title (left) | spacer (middle) | icon buttons (right) */}
<div style={{ display: 'flex', alignItems: 'center', flexDirection: 'row' }}>
<Text style={{ fontSize: '13px', fontWeight: 600 }}>Settings</Text>
<div style={{ flex: 1 }} />
<div style={{ display: 'flex', alignItems: 'center' }}>
<IconButton title="Stub action" onClick={function () {}}>
<IconWand24 />
</IconButton>
<IconButton title="Stub action" onClick={function () {}}>
<IconComponent24 />
</IconButton>
<IconButton
title={isMaximized ? 'Restore window' : 'Maximize window'}
onClick={toggleWindowSize}
>
{isMaximized ? <IconCollapse24 /> : <IconExpand24 />}
</IconButton>
<IconButton title="More" onClick={function () { setMoreOpen(true) }}>
<IconMore24 />
</IconButton>
</div>
</div>
<VerticalSpace space="small" />
<Divider />
<VerticalSpace space="small" />
{/* Body — empty placeholder for now */}
<div style={{ flex: 1 }} />
{/* Footer — status bar */}
<Divider />
<VerticalSpace space="small" />
<Muted style={{ fontSize: '11px' }}>Version {PLUGIN_VERSION}</Muted>
</Container>
<IconButton
title={isMaximized ? 'Restore window' : 'Maximize window'}
onClick={toggleWindowSize}
style={{ position: 'absolute', top: 6, right: 6, zIndex: 4 }}
>
{isMaximized ? <IconCollapse24 /> : <IconExpand24 />}
</IconButton>
{/* More-menu modal (opened by the three-dots button in the header) — stubs for now */}
{moreOpen && (
<Modal
title="Menu"
open={true}
position="right"
onCloseButtonClick={function () { setMoreOpen(false) }}
onOverlayClick={function () { setMoreOpen(false) }}
>
<Stack space="small">
<Muted>Stub actions</Muted>
<Button onClick={function () { setMoreOpen(false) }}>Stub action 1</Button>
<Button onClick={function () { setMoreOpen(false) }}>Stub action 2</Button>
</Stack>
</Modal>
)}
{/* Decorative drag-handle icon in the bottom-right corner (as in the old plugin).
pointerEvents:none — the actual drag is caught by the invisible corner div. */}
<div