Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 57 additions & 38 deletions src/renderer/components/custom/documentation-dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import React, { useEffect, useState } from 'react';

import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion';
import { Button } from '@/components/ui/button';
import {
Dialog,
Expand Down Expand Up @@ -62,45 +68,58 @@ export default function DocumentationDialog({ open, onOpenChange }: Documentatio
</DialogDescription>
</DialogHeader>

<div className="py-2 overflow-auto flex-1">
<h3 className="text-sm font-semibold mb-2">Lost the window?</h3>
<p className="text-sm text-muted-foreground mb-4">
In stealth mode {APP_NAME} leaves the taskbar and the macOS Dock so it is not visible
when you share your screen, which also means a minimized window has no button to click.
Just launch {APP_NAME} again: it does not start a second copy, it brings this window
back. Outside stealth mode the usual taskbar button and Dock icon are there.
</p>
<div className="overflow-auto flex-1">
<Accordion type="multiple" defaultValue={['hotkeys']} className="w-full">
<AccordionItem value="lost-window">
<AccordionTrigger className="text-sm font-semibold">
Lost the window?
</AccordionTrigger>
<AccordionContent>
<p className="text-sm text-muted-foreground">
In stealth mode {APP_NAME} leaves the taskbar and the macOS Dock so it is not
visible when you share your screen, which also means a minimized window has no
button to click. Just launch {APP_NAME} again: it does not start a second copy, it
brings this window back. Outside stealth mode the usual taskbar button and Dock
icon are there.
</p>
</AccordionContent>
</AccordionItem>

<h3 className="text-sm font-semibold mb-2">Hotkeys</h3>
{HOTKEY_GROUPS.map((group) => (
<div key={group.label} className="mb-4">
<h4 className="text-xs font-medium mb-1">{group.label}</h4>
<div className="grid grid-cols-3 gap-2">
{group.keys.map((hk) => {
const info = HOTKEYS[hk];
return (
<React.Fragment key={hk}>
<div className="col-span-1">
<div
className={cn(
'px-2 py-1 rounded text-[11px] font-semibold min-w-22.5',
hk === Hotkey.StopAll
? 'bg-destructive/80 text-primary-foreground'
: hk === Hotkey.ToggleStealth
? 'bg-primary/80 text-primary-foreground'
: 'bg-muted'
)}
>
{info.combo}
</div>
</div>
<div className="col-span-2 text-sm">{info.description}</div>
</React.Fragment>
);
})}
</div>
</div>
))}
<AccordionItem value="hotkeys">
<AccordionTrigger className="text-sm font-semibold">Hotkeys</AccordionTrigger>
<AccordionContent>
{HOTKEY_GROUPS.map((group) => (
<div key={group.label} className="mb-4 last:mb-0">
<h4 className="text-xs font-medium mb-1">{group.label}</h4>
<div className="grid grid-cols-3 gap-2">
{group.keys.map((hk) => {
const info = HOTKEYS[hk];
return (
<React.Fragment key={hk}>
<div className="col-span-1">
<div
className={cn(
'px-2 py-1 rounded text-[11px] font-semibold min-w-22.5',
hk === Hotkey.StopAll
? 'bg-destructive/80 text-primary-foreground'
: hk === Hotkey.ToggleStealth
? 'bg-primary/80 text-primary-foreground'
: 'bg-muted'
)}
>
{info.combo}
</div>
</div>
<div className="col-span-2 text-sm">{info.description}</div>
</React.Fragment>
);
})}
</div>
</div>
))}
</AccordionContent>
</AccordionItem>
</Accordion>
</div>

<DialogFooter>
Expand Down
62 changes: 62 additions & 0 deletions src/renderer/components/ui/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ChevronDownIcon } from 'lucide-react';
import { Accordion as AccordionPrimitive } from 'radix-ui';
import * as React from 'react';

import { cn } from '@/lib/utils';

function Accordion({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
}

function AccordionItem({
className,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
return (
<AccordionPrimitive.Item
data-slot="accordion-item"
className={cn('border-b last:border-b-0', className)}
{...props}
/>
);
}

function AccordionTrigger({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
return (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
data-slot="accordion-trigger"
className={cn(
'flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180',
className
)}
{...props}
>
{children}
<ChevronDownIcon className="pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
);
}

function AccordionContent({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
return (
<AccordionPrimitive.Content
data-slot="accordion-content"
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div className={cn('pt-0 pb-4', className)}>{children}</div>
</AccordionPrimitive.Content>
);
}

export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };