feat(ui): let users hide context rail surfaces
A trailing configure button on the rail — outside the sortable list and the digit shortcuts — opens a dialog that toggles each surface. The choice is stored as the hidden set so newly added surfaces appear for everyone, and the rail and the mod+alt+digit switcher share the same visibility filter, so badges and shortcuts always agree. Hidden surfaces keep their data and stay reachable from the command palette.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import React from 'react';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { useUIStore } from '@/stores/useUIStore';
|
||||
import { SettingsCheckboxRow } from '@/components/sections/shared/SettingsSection';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { sortContextSurfaces } from '@/lib/surfaces/registry';
|
||||
|
||||
/**
|
||||
* Which surfaces the context rail shows. Everything is on by default and the
|
||||
* choice is stored as the *hidden* set, so a surface added in a later release
|
||||
* appears for everyone rather than staying invisible to whoever had saved
|
||||
* settings before it existed. Hidden surfaces also leave the digit shortcuts
|
||||
* (the rail and the shortcut share one visibility filter).
|
||||
*/
|
||||
export const ContextRailSurfacesDialog: React.FC<{
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}> = ({ open, onOpenChange }) => {
|
||||
const { t } = useI18n();
|
||||
const contextRailOrder = useUIStore((state) => state.contextRailOrder);
|
||||
const hidden = useUIStore((state) => state.contextRailHiddenSurfaces);
|
||||
const setSurfaceVisible = useUIStore((state) => state.setContextRailSurfaceVisible);
|
||||
const setHiddenSurfaces = useUIStore((state) => state.setContextRailHiddenSurfaces);
|
||||
|
||||
// The full registry in the user's rail order — including surfaces a runtime
|
||||
// filter currently drops, so a choice made on desktop is editable anywhere.
|
||||
const surfaces = React.useMemo(() => sortContextSurfaces(contextRailOrder), [contextRailOrder]);
|
||||
|
||||
const allVisible = hidden.length === 0;
|
||||
const noneVisible = surfaces.every((surface) => hidden.includes(surface.id));
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('contextRail.configure.dialogTitle')}</DialogTitle>
|
||||
<DialogDescription>{t('contextRail.configure.dialogDescription')}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="flex flex-col">
|
||||
{surfaces.map((surface) => (
|
||||
<SettingsCheckboxRow
|
||||
key={surface.id}
|
||||
settingsItem={`layout.context-rail.surface.${surface.id}`}
|
||||
checked={!hidden.includes(surface.id)}
|
||||
onChange={(checked) => setSurfaceVisible(surface.id, checked)}
|
||||
label={t(surface.labelKey)}
|
||||
ariaLabel={t(surface.labelKey)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{!allVisible ? (
|
||||
<div className="flex items-center justify-between border-t pt-3">
|
||||
{noneVisible ? (
|
||||
<span className="text-xs text-destructive">{t('contextRail.configure.noneWarning')}</span>
|
||||
) : <span />}
|
||||
<Button
|
||||
variant="link"
|
||||
size="xs"
|
||||
onClick={() => setHiddenSurfaces([])}
|
||||
className="normal-case text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{t('contextRail.configure.showAll')}
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user