Keep canvas floating controls visible with the sidebar open
This commit is contained in:
@@ -33,6 +33,7 @@ export default function DashboardSidebar() {
|
||||
const [status, setStatus] = useState<"loading" | "ready" | "error">("loading");
|
||||
const [error, setError] = useState("");
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [accountAnchor, setAccountAnchor] = useState<"sidebar" | "floating">("sidebar");
|
||||
const [query, setQuery] = useState("");
|
||||
const [creating, setCreating] = useState(false);
|
||||
const [panel, setPanel] = useState<"settings" | "workspace" | null>(null);
|
||||
@@ -172,13 +173,13 @@ export default function DashboardSidebar() {
|
||||
return (
|
||||
<>
|
||||
<AnimatePresence initial={false}>
|
||||
{collapsed && (
|
||||
<motion.div key="sidebar-controls" className={`${toolbar.surface} ${toolbar.relaxed} ${styles.floating}`} aria-label="侧边栏快捷操作"
|
||||
{(collapsed || Boolean(params.board)) && (
|
||||
<motion.div key="sidebar-controls" className={`${toolbar.surface} ${toolbar.relaxed} ${styles.floating}`} data-sidebar-collapsed={collapsed} aria-label={params.board ? "画布快捷操作" : "侧边栏快捷操作"}
|
||||
initial={{ opacity: 0, y: reduceMotion ? 0 : -6 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: reduceMotion ? 0 : -6 }}
|
||||
transition={{ duration: reduceMotion ? 0 : 0.14 }}>
|
||||
<IconButton ref={expandButton} icon={PanelLeftOpen} label="展开侧边栏" aria-expanded={false} aria-controls="workspace-sidebar" onClick={() => toggleSidebar(false)} />
|
||||
{collapsed && <IconButton ref={expandButton} icon={PanelLeftOpen} label="展开侧边栏" aria-expanded={false} aria-controls="workspace-sidebar" onClick={() => toggleSidebar(false)} />}
|
||||
<Link href="/" className={styles.logoLink} aria-label="啡跃 Endoleap 主页" title="返回主页">
|
||||
<img src="/brand/png/logo-light/endoleap-32.png"
|
||||
srcSet="/brand/png/logo-light/endoleap-32.png 1x, /brand/png/logo-light/endoleap-64.png 2x, /brand/png/logo-light/endoleap-128.png 4x"
|
||||
@@ -189,7 +190,7 @@ export default function DashboardSidebar() {
|
||||
editable={Boolean(params.board && activeBoard && matchesRef(activeBoard, params.board) && activeBoard.workspace_id === workspace && canCreate)}
|
||||
onSave={renameTitle} className={styles.floatingTitle} />
|
||||
<span className={toolbar.divider} aria-hidden="true" />
|
||||
<button type="button" className={styles.floatingAvatarButton} popoverTarget="workspace-account" aria-label="账户和工作空间">
|
||||
<button type="button" className={styles.floatingAvatarButton} popoverTarget="workspace-account" aria-label="账户和工作空间" onClick={() => setAccountAnchor("floating")}>
|
||||
<UserAvatar name={name} url={profile?.avatar_url} />
|
||||
</button>
|
||||
{error && <p className={styles.floatingError} role="alert">{error}</p>}
|
||||
@@ -220,7 +221,7 @@ export default function DashboardSidebar() {
|
||||
</nav>
|
||||
{error && <p className={styles.error} role="alert">{error}</p>}
|
||||
<div className={styles.accountArea}>
|
||||
<button type="button" className={styles.accountButton} popoverTarget="workspace-account" aria-label="账户和工作空间">
|
||||
<button type="button" className={styles.accountButton} popoverTarget="workspace-account" aria-label="账户和工作空间" onClick={() => setAccountAnchor("sidebar")}>
|
||||
<UserAvatar name={name} url={profile?.avatar_url} />
|
||||
<span className={styles.accountText}><strong>{name}</strong><small>{currentWorkspace?.name || (demo ? "本地演示" : "个人账户")}</small></span>
|
||||
<ChevronsUpDown size={14} strokeWidth={1.6} />
|
||||
@@ -228,7 +229,7 @@ export default function DashboardSidebar() {
|
||||
</div>
|
||||
</motion.aside>
|
||||
</motion.div>
|
||||
<div ref={accountPopup} id="workspace-account" popover="auto" className={styles.accountPopup} data-floating={collapsed} aria-label="账户和工作空间菜单">
|
||||
<div ref={accountPopup} id="workspace-account" popover="auto" className={styles.accountPopup} data-floating={accountAnchor === "floating"} data-sidebar-collapsed={collapsed} aria-label="账户和工作空间菜单">
|
||||
<div className={styles.accountHeading}>
|
||||
<span className={styles.workspaceAvatar} aria-hidden="true">{(currentWorkspace?.name || "啡跃").slice(0, 1)}</span>
|
||||
<div><strong>{currentWorkspace?.name || "你的工作空间"}</strong><small>{roleLabel}{demo ? " · 本地演示" : ""}</small></div>
|
||||
|
||||
@@ -94,7 +94,8 @@
|
||||
.newWorkspace { color: #2383e2; }
|
||||
.logout { color: #78746d; font-size: 12px; }
|
||||
.separator { height: 1px; margin: 6px 7px; background: #eeece8; }
|
||||
.floating { position: fixed; left: 12px; top: 12px; max-width: calc(100vw - 24px); z-index: 40; }
|
||||
.floating { --floating-left: 12px; position: fixed; left: var(--floating-left); top: 12px; max-width: calc(100vw - var(--floating-left) - 12px); z-index: 40; transition: left 240ms cubic-bezier(0.22, 1, 0.36, 1), max-width 240ms cubic-bezier(0.22, 1, 0.36, 1); }
|
||||
.floating[data-sidebar-collapsed="false"], .accountPopup[data-sidebar-collapsed="false"] { --floating-left: calc(min(var(--sidebar-width), calc(100vw - 40px)) + 12px); }
|
||||
.floatingError { position: absolute; left: 0; top: 42px; width: 240px; padding: 10px; background: white; border: 1px solid #e7e2db; border-radius: 8px; color: #b14b3c; font-size: 12px; }
|
||||
.settingsPanel { color: #37352f; border-color: #e6e2dc; border-radius: 12px; }
|
||||
.settingsForm { display: flex; flex-direction: column; gap: 16px; padding-top: 4px; }
|
||||
@@ -119,11 +120,17 @@
|
||||
|
||||
.floatingAvatarButton { display: grid; place-items: center; flex: 0 0 auto; box-sizing: border-box; width: var(--toolbar-control-width, 32px); height: var(--toolbar-control-height, 32px); border-radius: 5px; }
|
||||
.floatingAvatarButton:hover { background: #e9e7e3; }
|
||||
.accountPopup[data-floating="true"] { inset: 62px auto auto 12px; max-height: calc(100dvh - 76px); transform-origin: top left; }
|
||||
.accountPopup[data-floating="true"] { inset: 62px auto auto clamp(8px, var(--floating-left, 12px), max(8px, calc(100vw - 308px))); max-height: calc(100dvh - 76px); transform-origin: top left; }
|
||||
|
||||
.floatingAvatarButton .avatar { flex-basis: var(--toolbar-icon-size, 20px); width: var(--toolbar-icon-size, 20px); height: var(--toolbar-icon-size, 20px); font-size: 14px; }
|
||||
.floatingTitle { flex: 1 1 auto; min-width: 0; max-width: 240px; margin: 0; color: #37352f; font-size: 14px; line-height: var(--toolbar-control-height, 32px); font-weight: 500; overflow: visible; }
|
||||
@media (max-width: 700px) { .floatingTitle { max-width: 180px; } }
|
||||
@media (max-width: 420px) {
|
||||
.floating[data-sidebar-collapsed="false"] .logoLink,
|
||||
.floating[data-sidebar-collapsed="false"] .floatingTitle,
|
||||
.floating[data-sidebar-collapsed="false"] > span[aria-hidden="true"] { display: none; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) { .floating { transition: none; } }
|
||||
|
||||
.directoryList { list-style: none; padding: 0; margin: 0; }
|
||||
.directoryRow { display: flex; align-items: center; min-width: 0; }
|
||||
|
||||
Reference in New Issue
Block a user