Skip to content

Commit

Permalink
Added Dark Mode Context Menu
Browse files Browse the repository at this point in the history
  • Loading branch information
niemyjski committed Dec 4, 2023
1 parent a27b94e commit 107c2a9
Show file tree
Hide file tree
Showing 14 changed files with 313 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
<script lang="ts">
import IconMoonWaningCrescent from '~icons/mdi/moon-waning-crescent';
import IconWhiteBalanceSunny from '~icons/mdi/white-balance-sunny';
import * as ContextMenu from '$lib/components/ui/context-menu';
import { Button } from '$comp/ui/button';
import { toggleMode } from 'mode-watcher';
import { setMode, toggleMode, userPrefersMode } from 'mode-watcher';
</script>

<Button on:click={toggleMode} variant="outline" size="icon" title="Toggle dark mode">
<IconWhiteBalanceSunny
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
<IconMoonWaningCrescent
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
<span class="sr-only">Toggle theme</span>
</Button>
<ContextMenu.Root>
<ContextMenu.Trigger>
<Button on:click={toggleMode} variant="outline" size="icon" title="Toggle dark mode">
<IconWhiteBalanceSunny
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
<IconMoonWaningCrescent
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
<span class="sr-only">Toggle theme</span>
</Button>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.RadioGroup bind:value={$userPrefersMode} onValueChange={setMode}>
<ContextMenu.RadioItem value="light">Light</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="dark">Dark</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="system">System</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
</ContextMenu.Content>
</ContextMenu.Root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
import { Check } from 'radix-icons-svelte';
type $$Props = ContextMenuPrimitive.CheckboxItemProps;
let className: $$Props['class'] = undefined;
export { className as class };
export let checked: $$Props['checked'] = undefined;
</script>

<ContextMenuPrimitive.CheckboxItem
bind:checked
class={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuPrimitive.CheckboxIndicator>
<Check class="w-4 h-4" />
</ContextMenuPrimitive.CheckboxIndicator>
</span>
<slot />
</ContextMenuPrimitive.CheckboxItem>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
import { cn, flyAndScale } from '$lib/utils';
type $$Props = ContextMenuPrimitive.ContentProps;
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = flyAndScale;
export let transitionConfig: $$Props['transitionConfig'] = undefined;
export { className as class };
</script>

<ContextMenuPrimitive.Content
{transition}
{transitionConfig}
class={cn(
'z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none',
className
)}
{...$$restProps}
on:keydown
>
<slot />
</ContextMenuPrimitive.Content>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = ContextMenuPrimitive.ItemProps & {
inset?: boolean;
};
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
</script>

<ContextMenuPrimitive.Item
class={cn(
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
inset && 'pl-8',
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<slot />
</ContextMenuPrimitive.Item>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = ContextMenuPrimitive.LabelProps & {
inset?: boolean;
};
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
</script>

<ContextMenuPrimitive.Label
class={cn('px-2 py-1.5 text-sm font-semibold text-foreground', inset && 'pl-8', className)}
{...$$restProps}
>
<slot />
</ContextMenuPrimitive.Label>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
type $$Props = ContextMenuPrimitive.RadioGroupProps;
export let value: $$Props['value'] = undefined;
</script>

<ContextMenuPrimitive.RadioGroup {...$$restProps} bind:value>
<slot />
</ContextMenuPrimitive.RadioGroup>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
import { DotFilled } from 'radix-icons-svelte';
type $$Props = ContextMenuPrimitive.RadioItemProps;
let className: $$Props['class'] = undefined;
export let value: $$Props['value'];
export { className as class };
</script>

<ContextMenuPrimitive.RadioItem
class={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className
)}
{value}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuPrimitive.RadioIndicator>
<DotFilled class="w-4 h-4 fill-current" />
</ContextMenuPrimitive.RadioIndicator>
</span>
<slot />
</ContextMenuPrimitive.RadioItem>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = ContextMenuPrimitive.SeparatorProps;
let className: $$Props['class'] = undefined;
export { className as class };
</script>

<ContextMenuPrimitive.Separator
class={cn('-mx-1 my-1 h-px bg-border', className)}
{...$$restProps}
/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="ts">
import { cn } from '$lib/utils';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>

<span
class={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}
{...$$restProps}
>
<slot />
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
import { cn, flyAndScale } from '$lib/utils';
type $$Props = ContextMenuPrimitive.SubContentProps;
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = flyAndScale;
export let transitionConfig: $$Props['transitionConfig'] = undefined;
export { className as class };
</script>

<ContextMenuPrimitive.SubContent
{transition}
{transitionConfig}
class={cn(
'z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-lg focus:outline-none',
className
)}
{...$$restProps}
on:keydown
on:focusout
on:pointermove
>
<slot />
</ContextMenuPrimitive.SubContent>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script lang="ts">
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
import { ChevronRight } from 'radix-icons-svelte';
type $$Props = ContextMenuPrimitive.SubTriggerProps & {
inset?: boolean;
};
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
</script>

<ContextMenuPrimitive.SubTrigger
class={cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
inset && 'pl-8',
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
>
<slot />
<ChevronRight class="w-4 h-4 ml-auto" />
</ContextMenuPrimitive.SubTrigger>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';

import Item from './context-menu-item.svelte';
import Label from './context-menu-label.svelte';
import Content from './context-menu-content.svelte';
import Shortcut from './context-menu-shortcut.svelte';
import RadioItem from './context-menu-radio-item.svelte';
import Separator from './context-menu-separator.svelte';
import RadioGroup from './context-menu-radio-group.svelte';
import SubContent from './context-menu-sub-content.svelte';
import SubTrigger from './context-menu-sub-trigger.svelte';
import CheckboxItem from './context-menu-checkbox-item.svelte';

const Sub = ContextMenuPrimitive.Sub;
const Root = ContextMenuPrimitive.Root;
const Trigger = ContextMenuPrimitive.Trigger;
const Group = ContextMenuPrimitive.Group;

export {
Sub,
Root,
Item,
Label,
Group,
Trigger,
Content,
Shortcut,
Separator,
RadioItem,
SubContent,
SubTrigger,
RadioGroup,
CheckboxItem,
//
Root as ContextMenu,
Sub as ContextMenuSub,
Item as ContextMenuItem,
Label as ContextMenuLabel,
Group as ContextMenuGroup,
Content as ContextMenuContent,
Trigger as ContextMenuTrigger,
Shortcut as ContextMenuShortcut,
RadioItem as ContextMenuRadioItem,
Separator as ContextMenuSeparator,
RadioGroup as ContextMenuRadioGroup,
SubContent as ContextMenuSubContent,
SubTrigger as ContextMenuSubTrigger,
CheckboxItem as ContextMenuCheckboxItem
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
export { className as class };
</script>

<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<thead class={cn('[&_tr]:border-b', className)} {...$$restProps} on:click on:keydown>
<slot />
</thead>
2 changes: 2 additions & 0 deletions src/Exceptionless.Web/ClientApp/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

<div class="bg-background text-foreground">
<ModeWatcher defaultMode={'dark'} />

<QueryClientProvider client={queryClient}>
<slot />

<SvelteQueryDevtools />
</QueryClientProvider>

Expand Down

0 comments on commit 107c2a9

Please sign in to comment.