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
5 changes: 4 additions & 1 deletion frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"svelte-preprocess": "catalog:",
"svelte-routing": "^2.12.0",
"svelte-ux": "^0.76.0",
"tabbable": "^6.2.0",
"type-fest": "^4.18.2"
}
}
5 changes: 3 additions & 2 deletions frontend/viewer/src/home/HomeView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import {Button} from '$lib/components/ui/button';
import {mode} from 'mode-watcher';
import * as ResponsiveMenu from '$lib/components/responsive-menu';
import {Icon} from '$lib/components/ui/icon';

const projectsService = useProjectsService();
const importFwdataService = useImportFwdataService();
Expand Down Expand Up @@ -104,7 +105,7 @@

<AppBar title={$t`Dictionaries`} class="bg-primary/15 min-h-12 shadow-md justify-between" menuIcon={null}>
<div slot="title" class="text-lg flex gap-2 items-center">
<img src={mode.current === 'dark' ? logoLight : logoDark} alt={$t`Lexbox logo`} class="h-6 shrink-0" />
<Icon src={mode.current === 'dark' ? logoLight : logoDark} alt={$t`Lexbox logo`} />
<h3>{$t`Dictionaries`}</h3>
</div>
<div slot="actions" class="flex">
Expand Down Expand Up @@ -222,7 +223,7 @@
<ButtonListItem href={`/fwdata/${project.code}`}>
<ListItem classes={{root: 'dark:bg-muted/50 bg-muted/80 hover:bg-muted/30 hover:dark:bg-muted' }}>
<ProjectTitle slot="title" {project}/>
<img slot="avatar" src={flexLogo} alt={$t`FieldWorks logo`} class="h-6 shrink-0" />
<Icon slot="avatar" src={flexLogo} alt={$t`FieldWorks logo`} />
<div slot="actions" class="shrink-0">
<DevContent invisible>
<UxButton
Expand Down
12 changes: 6 additions & 6 deletions frontend/viewer/src/home/Server.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@
</ButtonListItem>
{/if}
{/each}
<div class="text-center py-2">
<Button variant="link" target="_blank" href="{server?.authority}/wheresMyProject">
{$t`I don't see my project`}
<Icon icon="i-mdi-open-in-new" class="size-4" />
</Button>
</div>
</div>
<div class="text-center pt-2">
<Button variant="link" target="_blank" href="{server?.authority}/wheresMyProject">
{$t`I don't see my project`}
<Icon icon="i-mdi-open-in-new" class="size-4" />
</Button>
</div>
{/if}
</div>
Expand Down
3 changes: 2 additions & 1 deletion frontend/viewer/src/lib/OpenInFieldWorksButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import {t} from 'svelte-i18n-lingui';
import {mergeProps} from 'bits-ui';
import {cn} from './utils';
import {Icon} from './components/ui/icon';

type Props = {
entry: IEntry
Expand Down Expand Up @@ -52,6 +53,6 @@

<!--button must be a link otherwise it won't follow the redirect to a protocol handler-->
<button class={cn(buttonVariants({ variant: 'ghost'}), className)} {...mergedProps}>
<img src={flexLogo} alt={$t`FieldWorks logo`} class="h-6 max-w-fit"/>
<Icon src={flexLogo} alt={$t`FieldWorks logo`} />
{$t`Open in FieldWorks`}
</button>
4 changes: 2 additions & 2 deletions frontend/viewer/src/lib/components/editor/editor-root.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

type EditorRootProps = WithElementRef<HTMLAttributes<HTMLDivElement>>;

const {
let {
class: className,
children,
ref = $bindable(null),
...restProps
}: EditorRootProps = $props();
</script>

<div class={cn('@container/editor', className)} {...restProps}>
<div class={cn('@container/editor', className)} {...restProps} bind:this={ref}>
{@render children?.()}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type {WithElementRef} from 'bits-ui';
import type {HTMLAttributes} from 'svelte/elements';

type EditorSubGridProps = WithElementRef<HTMLAttributes<HTMLDivElement>>;
export type EditorSubGridProps = WithElementRef<HTMLAttributes<HTMLDivElement>>;

const {
class: className,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<DropdownMenu.Group {...mergedProps}>
{#each displayItems as item, i}
{@const reorderName = getDisplayName(item) || '–'}
<DropdownMenu.Item class="grid grid-cols-subgrid col-span-full justify-items-start items-center cursor-pointer"
<DropdownMenu.Item class="grid grid-cols-subgrid col-span-full justify-items-start items-center"
onmouseover={() => displayIndex = i}
onfocus={() => displayIndex = i}
onSelect={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import * as ContextMenu from '$lib/components/ui/context-menu';
import { IsMobile } from '$lib/hooks/is-mobile.svelte';
import Button, {buttonVariants} from '$lib/components/ui/button/button.svelte';
import {buttonVariants} from '$lib/components/ui/button/button.svelte';
import type {Snippet} from 'svelte';
import {useResponsiveMenuItemList} from './responsive-menu.svelte';
import type {ButtonProps} from 'node_modules/bits-ui/dist/bits/toolbar/exports';
import {mergeProps, type ContextMenuItemProps} from 'bits-ui';
import type {ContextMenuItemProps} from 'bits-ui';
import type {DrawerCloseProps} from 'vaul-svelte';
import {cn} from '$lib/utils';
import {DrawerClose} from '../ui/drawer';

type Props = {
children?: Snippet;
icon?: IconClass;
onSelect?: () => void;
href?: string;
} & ContextMenuItemProps & ButtonProps;
} & Omit<ContextMenuItemProps & DrawerCloseProps, 'onclick'>;

let {
icon,
Expand All @@ -28,14 +29,6 @@
}: Props = $props();

const state = useResponsiveMenuItemList();

const buttonProps = $derived({
variant: 'ghost',
class: cn(buttonVariants({ variant: 'ghost', class: 'w-full justify-start gap-2' }), className),
onclick: onSelect,
} as const);

const mergedProps = $derived(mergeProps(buttonProps, rest));
</script>

{#snippet content()}
Expand All @@ -52,21 +45,21 @@
{/snippet}

{#if state.contextMenu}
<ContextMenu.Item class={cn('cursor-pointer gap-2 w-full', className)} onclick={onSelect} bind:ref
<ContextMenu.Item class={cn('gap-2 w-full', className)} {onSelect} bind:ref
child={rest.href ? anchorChild : undefined} {...rest}>
{@render content()}
</ContextMenu.Item>
{:else if !IsMobile.value}
<DropdownMenu.Item class={cn('cursor-pointer gap-2 w-full', className)} {onSelect} bind:ref
<DropdownMenu.Item class={cn('gap-2 w-full', className)} {onSelect} bind:ref
child={rest.href ? anchorChild : undefined} {...rest}>
{@render content()}
</DropdownMenu.Item>
{:else if rest.child}
{@render rest.child({ props: mergedProps})}
{:else}
<Button
{...buttonProps}
<DrawerClose
class={cn(buttonVariants({ variant: 'ghost', class: 'w-full justify-start gap-2' }), className)}
onclick={onSelect}
{...rest}
bind:ref>
{@render content()}
</Button>
</DrawerClose>
{/if}
11 changes: 7 additions & 4 deletions frontend/viewer/src/lib/components/ui/button/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import Root, {
import XButton from './x-button.svelte';

export {
//
Root as Button,
Root,
XButton,
buttonVariants, Root, type ButtonProps,
type ButtonProps,
type ButtonSize,
type ButtonVariant, type ButtonProps as Props
type ButtonVariant,
buttonVariants,
//
Root as Button,
type ButtonProps as Props
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<ContextMenuPrimitive.Item
bind:ref
class={cn(
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
inset && 'pl-8',
className
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<DropdownMenuPrimitive.Item
bind:ref
class={cn(
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
inset && 'pl-8',
className,
)}
Expand Down
34 changes: 25 additions & 9 deletions frontend/viewer/src/lib/components/ui/icon/icon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,34 @@
import type {IconClass} from '$lib/icon-class';
import {cn} from '$lib/utils';
import type {WithElementRef, WithoutChildren} from 'bits-ui';
import type {HTMLAttributes} from 'svelte/elements';
import type {HTMLAttributes, HTMLImgAttributes} from 'svelte/elements';
import {tv} from 'tailwind-variants';

export type IconProps = WithoutChildren<WithElementRef<HTMLAttributes<HTMLSpanElement>>> & {
icon: IconClass;
};
export const iconVariants = tv({
base: 'inline-block shrink-0',
variants: {
size: {
default: 'size-6'
}
},
defaultVariants: {
size: 'default',
},
});

export type IconProps = WithoutChildren<WithElementRef<HTMLAttributes<HTMLSpanElement>>> &
({ icon: IconClass; } | ({ src: string, alt: string } & HTMLImgAttributes));
</script>

<script lang="ts">
const { icon, class: className, ...restProps }: IconProps = $props();
const { class: className, ...restProps }: IconProps = $props();
</script>

<span {...restProps} class={cn('size-6 inline-block shrink-0', className, icon)}>
<!-- ensures that baseline alignment works for consumers of this component -->
&nbsp;
</span>
{#if 'src' in restProps}
<img {...restProps} class={cn(iconVariants(), className)} />
{:else}
<span {...restProps} class={cn(iconVariants(), className, restProps.icon)}>
<!-- ensures that baseline alignment works for consumers of this component -->
&nbsp;
</span>
{/if}
Comment thread
myieye marked this conversation as resolved.
12 changes: 9 additions & 3 deletions frontend/viewer/src/lib/components/ui/icon/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import Icon from './icon.svelte';

export {Icon};
import Icon, {
type IconProps,
iconVariants,
} from './icon.svelte';

export {
Icon,
type IconProps,
iconVariants
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
before?: Snippet,
after?: Snippet,
} = $props();

const focusRingClass = 'has-[.real-input:focus-visible]:ring-ring has-[.real-input:focus-visible]:outline-none has-[.real-input:focus-visible]:ring-2 has-[.real-input:focus-visible]:ring-offset-2';
</script>

<InputShell bind:ref class={className} {...restProps}>
<InputShell bind:ref {focusRingClass} class={className} {...restProps}>
{@render before?.()}
<Input variant="ghost" {placeholder} class="grow" bind:ref={inputRef} bind:value />
<Input variant="ghost" {placeholder} class="grow real-input" bind:ref={inputRef} bind:value />
{@render after?.()}
</InputShell>
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@
import type {HTMLAttributes} from 'svelte/elements';
import {inputVariants} from './input.svelte';

type Props = WithElementRef<HTMLAttributes<HTMLDivElement>>;
interface Props extends WithElementRef<HTMLAttributes<HTMLDivElement>> {
focusRingClass?: string;
}

const anyChildHasFocusRing = 'has-[:focus-visible]:ring-ring has-[:focus-visible]:outline-none has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2';

let {
ref = $bindable(null),
class: className,
focusRingClass = anyChildHasFocusRing,
children,
...restProps
}: Props = $props();
</script>

<div
bind:this={ref}
class={cn(inputVariants({ variant: 'shell' }), className)}
class={cn(inputVariants({ variant: 'shell' }), focusRingClass, className)}
{...restProps}
>
{@render children?.()}
Expand Down
2 changes: 1 addition & 1 deletion frontend/viewer/src/lib/components/ui/input/input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
default: 'border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-base file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
ghost: 'outline-none min-w-0 bg-transparent',
// shell variant has a dedicated component
shell: 'border-input bg-background ring-offset-background placeholder:text-muted-foreground has-[:focus-visible]:ring-ring flex h-10 w-full rounded-md border text-base has-[:focus-visible]:outline-none has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50 md:text-sm flex gap-2 items-center justify-between',
shell: 'border-input bg-background ring-offset-background placeholder:text-muted-foreground flex h-10 w-full rounded-md border text-base has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50 md:text-sm flex gap-2 items-center justify-between',
},
},
defaultVariants: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

let {
ref = $bindable(null),
viewportRef = $bindable(null),
class: className,
type: explicitType,
orientation = 'vertical',
Expand All @@ -17,13 +18,14 @@
orientation?: 'vertical' | 'horizontal' | 'both' | undefined;
scrollbarXClasses?: string | undefined;
scrollbarYClasses?: string | undefined;
viewportRef?: HTMLElement | null;
} = $props();

const type = $derived(explicitType ?? (IsMobile.value ? 'scroll' : 'auto'));
</script>

<ScrollAreaPrimitive.Root {type} bind:ref {...restProps} class={cn('relative overflow-hidden', className)}>
<ScrollAreaPrimitive.Viewport class="h-full w-full rounded-[inherit]">
<ScrollAreaPrimitive.Viewport bind:ref={viewportRef} class="h-full w-full rounded-[inherit]">
{@render children?.()}
</ScrollAreaPrimitive.Viewport>
{#if orientation === 'vertical' || orientation === 'both'}
Expand Down
12 changes: 7 additions & 5 deletions frontend/viewer/src/lib/entry-editor/EntryOrSenseItemList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
{...rest}
getDisplayName={getHeadword}>
{#snippet menuItems(entry)}
<DropdownMenu.Item>
<Link to="browse?entryId={getEntryId(entry)}">
<Icon icon="i-mdi-book-outline" />
{$t`Go to ${getHeadword(entry) || '–'}`}
</Link>
<DropdownMenu.Item class="cursor-pointer">
{#snippet child({props})}
<Link {...props} to="browse?entryId={getEntryId(entry)}">
<Icon icon="i-mdi-book-outline" />
{$t`Go to ${getHeadword(entry) || '–'}`}
</Link>
{/snippet}
</DropdownMenu.Item>
{/snippet}
</ItemList>
2 changes: 1 addition & 1 deletion frontend/viewer/src/lib/entry-editor/ItemListItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
</Reorderer.Root>
</DropdownMenu.Sub>
{/if}
<DropdownMenu.Item onSelect={() => remove(item)}>
<DropdownMenu.Item class="cursor-pointer" onSelect={() => remove(item)}>
<Icon icon="i-mdi-trash-can-outline" />
{$t`Remove`}
</DropdownMenu.Item>
Expand Down
Loading
Loading