@brumaombra/ui-vintage 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +41 -0
- package/COMPONENTS.md +88 -17
- package/README.md +296 -262
- package/module.mjs +5 -11
- package/package.json +30 -12
- package/src/components/blog/BlogContentRenderer.vue +1 -1
- package/src/components/blog/BlogHeaderSection.vue +93 -19
- package/src/components/blog/BlogInfoSection.vue +39 -36
- package/src/components/blog/BlogPostHeader.vue +181 -0
- package/src/components/blog/BlogProgressBar.vue +3 -5
- package/src/components/blog/BlogSectionTitle.vue +8 -6
- package/src/components/blog/BlogTagsSection.vue +16 -7
- package/src/components/blog/CategoryCard.vue +18 -23
- package/src/components/blog/HeaderCarousel.vue +15 -6
- package/src/components/blog/PostCard.vue +13 -20
- package/src/components/blog/SocialShareSidebar.vue +24 -14
- package/src/components/blog/TableOfContents.vue +61 -28
- package/src/components/blog/index.ts +1 -0
- package/src/components/card-grid/CardGrid.vue +2 -2
- package/src/components/confirm-dialog/ConfirmDialog.vue +5 -0
- package/src/components/confirm-dialog/confirm-dialog-state.ts +22 -22
- package/src/components/content/BlogList.vue +28 -52
- package/src/components/content/BlogTable.vue +26 -30
- package/src/components/content/CodeBlock.vue +96 -22
- package/src/components/content/Flow.vue +29 -35
- package/src/components/content/ProseHr.vue +5 -5
- package/src/components/content/ProsePre.vue +9 -4
- package/src/components/content/Terminal.vue +42 -20
- package/src/components/cookie-consent/CookieConsent.vue +1 -1
- package/src/components/dashboard-shell/DashboardShell.vue +24 -7
- package/src/components/empty-state-card/EmptyStateCard.vue +2 -2
- package/src/components/error-page/ErrorPage.vue +3 -3
- package/src/components/info-card/InfoCard.vue +4 -4
- package/src/components/landing/landing-footer/LandingFooter.vue +16 -11
- package/src/components/landing/landing-navbar/LandingNavbar.vue +22 -6
- package/src/components/landing/landing-shell/LandingShell.vue +2 -7
- package/src/components/language-flag/index.ts +1 -0
- package/src/components/language-selector/LanguageSelector.vue +18 -10
- package/src/components/load-more-button/LoadMoreButton.vue +7 -12
- package/src/components/loading-state-card/LoadingStateCard.vue +2 -2
- package/src/components/message-dialog/MessageDialog.vue +11 -11
- package/src/components/message-dialog/message-dialog-state.ts +1 -4
- package/src/components/message-toast/MessageToast.vue +24 -9
- package/src/components/message-toast/message-toast-state.ts +20 -0
- package/src/components/page-header/PageHeader.vue +1 -1
- package/src/components/progress-component/ProgressComponent.vue +7 -3
- package/src/components/single-value-card/SingleValueCard.vue +37 -39
- package/src/components/slider-form-component/SliderFormComponent.vue +1 -1
- package/src/components/stat-strip/StatStrip.vue +36 -0
- package/src/components/stat-strip/index.ts +2 -0
- package/src/components/switch-form-component/SwitchFormComponent.vue +5 -5
- package/src/components/text-link/TextLink.vue +1 -1
- package/src/components/theme-selector/ThemeSelector.vue +2 -2
- package/src/components/theme-selector/theme-transition.ts +15 -3
- package/src/components/ui/accordion/Accordion.vue +18 -18
- package/src/components/ui/alert/AlertTitle.vue +1 -1
- package/src/components/ui/alert/index.ts +1 -1
- package/src/components/ui/avatar/AvatarFallback.vue +2 -1
- package/src/components/ui/avatar/AvatarGroup.vue +13 -3
- package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +2 -2
- package/src/components/ui/busy/Busy.vue +5 -7
- package/src/components/ui/button/Button.vue +4 -2
- package/src/components/ui/button/index.ts +1 -4
- package/src/components/ui/calendar/Calendar.vue +12 -7
- package/src/components/ui/calendar/CalendarCell.vue +1 -1
- package/src/components/ui/calendar/CalendarCellTrigger.vue +1 -1
- package/src/components/ui/calendar/CalendarHeadCell.vue +1 -1
- package/src/components/ui/calendar/CalendarNextButton.vue +1 -1
- package/src/components/ui/calendar/CalendarPrevButton.vue +1 -1
- package/src/components/ui/card/Card.vue +5 -15
- package/src/components/ui/checkbox/Checkbox.vue +5 -1
- package/src/components/ui/combobox/ComboboxInput.vue +5 -1
- package/src/components/ui/command/CommandGroup.vue +17 -3
- package/src/components/ui/command/CommandInput.vue +1 -1
- package/src/components/ui/command/CommandList.vue +5 -1
- package/src/components/ui/data-table/DataTable.vue +11 -3
- package/src/components/ui/date-picker/DatePicker.vue +7 -1
- package/src/components/ui/date-time-picker/DateTimePicker.vue +5 -1
- package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +1 -1
- package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +1 -1
- package/src/components/ui/dropdown-menu/classes.ts +2 -0
- package/src/components/ui/field/Field.vue +4 -0
- package/src/components/ui/field/FieldLabel.vue +6 -2
- package/src/components/ui/field/field-context.ts +62 -0
- package/src/components/ui/field/index.ts +1 -0
- package/src/components/ui/file-dropzone/FileDropzone.vue +4 -4
- package/src/components/ui/input/Input.vue +5 -1
- package/src/components/ui/native-select/NativeSelect.vue +6 -2
- package/src/components/ui/number-field/NumberField.vue +5 -1
- package/src/components/ui/pagination/PaginationItem.vue +1 -1
- package/src/components/ui/pin-input/PinInputInput.vue +2 -2
- package/src/components/ui/progress/Progress.vue +2 -2
- package/src/components/ui/radio-group/RadioGroupCard.vue +1 -1
- package/src/components/ui/select/SelectItem.vue +1 -1
- package/src/components/ui/select/SelectItemContent.vue +1 -1
- package/src/components/ui/select/SelectTrigger.vue +5 -1
- package/src/components/ui/sidebar/Sidebar.vue +1 -1
- package/src/components/ui/sidebar/SidebarGroupAction.vue +1 -1
- package/src/components/ui/sidebar/SidebarGroupLabel.vue +1 -1
- package/src/components/ui/sidebar/SidebarInset.vue +1 -1
- package/src/components/ui/sidebar/SidebarMenuAction.vue +1 -1
- package/src/components/ui/sidebar/SidebarMenuBadge.vue +1 -1
- package/src/components/ui/sidebar/SidebarMenuSkeleton.vue +2 -2
- package/src/components/ui/sidebar/SidebarMenuSubButton.vue +1 -1
- package/src/components/ui/sidebar/SidebarProvider.vue +17 -6
- package/src/components/ui/sidebar/index.ts +2 -2
- package/src/components/ui/sidebar/utils.ts +1 -1
- package/src/components/ui/slider/Slider.vue +5 -4
- package/src/components/ui/spinner/Spinner.vue +3 -2
- package/src/components/ui/stepper/StepperDescription.vue +5 -3
- package/src/components/ui/stepper/StepperIndicator.vue +2 -2
- package/src/components/ui/stepper/StepperTitle.vue +5 -3
- package/src/components/ui/switch/Switch.vue +6 -2
- package/src/components/ui/tabs/TabsList.vue +1 -1
- package/src/components/ui/tabs/TabsTrigger.vue +1 -1
- package/src/components/ui/textarea/Textarea.vue +5 -1
- package/src/components/ui/time-picker/TimePicker.vue +2 -2
- package/src/components/ui/toggle-group/ToggleGroup.vue +1 -1
- package/src/components/ui/tooltip/TooltipContent.vue +1 -1
- package/src/i18n/de.json +16 -6
- package/src/i18n/en.json +16 -6
- package/src/i18n/es.json +16 -6
- package/src/i18n/fr.json +16 -6
- package/src/i18n/it.json +16 -6
- package/src/i18n/ja.json +16 -6
- package/src/i18n/pt.json +16 -6
- package/src/i18n/ru.json +16 -6
- package/src/i18n/zh.json +16 -6
- package/src/lib/color-tokens.ts +1 -1
- package/src/lib/i18n.ts +32 -4
- package/src/lib/utils.ts +21 -1
- package/src/runtime/ui-vintage-i18n-plugin.ts +11 -1
- package/src/styles.css +12 -16
- package/skills/ui-vintage/SKILL.md +0 -42
|
@@ -36,7 +36,7 @@ const props = defineProps<{
|
|
|
36
36
|
|
|
37
37
|
<!-- Description -->
|
|
38
38
|
<span v-if="props.description" data-slot="select-item-content-description" :class="cn(
|
|
39
|
-
'font-
|
|
39
|
+
'font-normal text-[11px] sm:text-xs leading-4 sm:leading-5 text-muted-foreground',
|
|
40
40
|
props.descriptionClass
|
|
41
41
|
)
|
|
42
42
|
">
|
|
@@ -6,6 +6,7 @@ import { ArrowDown01Icon } from '@hugeicons/core-free-icons';
|
|
|
6
6
|
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
7
7
|
import { SelectIcon, SelectTrigger, useForwardProps } from 'reka-ui';
|
|
8
8
|
import { cn } from '../../../lib/utils';
|
|
9
|
+
import { useFieldControlId } from '../field/field-context';
|
|
9
10
|
|
|
10
11
|
// Props
|
|
11
12
|
const props = withDefaults(defineProps<SelectTriggerProps & {
|
|
@@ -15,10 +16,13 @@ const props = withDefaults(defineProps<SelectTriggerProps & {
|
|
|
15
16
|
|
|
16
17
|
const delegatedProps = reactiveOmit(props, 'class', 'size');
|
|
17
18
|
const forwardedProps = useForwardProps(delegatedProps);
|
|
19
|
+
|
|
20
|
+
// Let a surrounding Field label point to this control
|
|
21
|
+
const fieldControlId = useFieldControlId();
|
|
18
22
|
</script>
|
|
19
23
|
|
|
20
24
|
<template>
|
|
21
|
-
<SelectTrigger data-slot="select-trigger" :data-size="size" v-bind="forwardedProps" :class="cn(
|
|
25
|
+
<SelectTrigger :id="fieldControlId" data-slot="select-trigger" :data-size="size" v-bind="forwardedProps" :class="cn(
|
|
22
26
|
'group/select-trigger uv-field flex w-fit cursor-pointer items-center justify-between gap-2 rounded border border-input bg-secondary px-4 py-3 text-xs font-semibold whitespace-nowrap text-foreground shadow-elevated-sm outline-none data-placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-60 data-[size=default]:h-13 data-[size=sm]:h-10 sm:text-sm',
|
|
23
27
|
'*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2',
|
|
24
28
|
'[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 [&_svg:not([class*=\'text-\'])]:text-muted-foreground',
|
|
@@ -78,7 +78,7 @@ function handleMobileSidebarClick(event: MouseEvent) {
|
|
|
78
78
|
props.class
|
|
79
79
|
)
|
|
80
80
|
" v-bind="$attrs">
|
|
81
|
-
<div data-sidebar="sidebar" class="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded
|
|
81
|
+
<div data-sidebar="sidebar" class="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded group-data-[variant=floating]:border group-data-[variant=floating]:shadow-elevated-sm">
|
|
82
82
|
<slot />
|
|
83
83
|
</div>
|
|
84
84
|
</div>
|
|
@@ -10,7 +10,7 @@ const props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>(
|
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
12
|
<Primitive data-slot="sidebar-group-action" data-sidebar="group-action" :as="as" :as-child="asChild" :class="cn(
|
|
13
|
-
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded
|
|
13
|
+
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
14
14
|
'after:absolute after:-inset-2 md:after:hidden',
|
|
15
15
|
'group-data-[collapsible=icon]:hidden',
|
|
16
16
|
props.class
|
|
@@ -10,7 +10,7 @@ const props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>(
|
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
12
|
<Primitive data-slot="sidebar-group-label" data-sidebar="group-label" :as="as" :as-child="asChild" :class="cn(
|
|
13
|
-
'text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded
|
|
13
|
+
'text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded px-2 text-xs font-semibold outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 group-data-[compact=true]/sidebar-wrapper:h-7 group-data-[compact=true]/sidebar-wrapper:px-1.5 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
14
14
|
'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
|
|
15
15
|
props.class
|
|
16
16
|
)
|
|
@@ -11,7 +11,7 @@ const props = defineProps<{
|
|
|
11
11
|
<template>
|
|
12
12
|
<main data-slot="sidebar-inset" :class="cn(
|
|
13
13
|
'bg-background relative flex w-full flex-1 flex-col',
|
|
14
|
-
'md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded
|
|
14
|
+
'md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded md:peer-data-[variant=inset]:shadow-elevated-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2',
|
|
15
15
|
props.class
|
|
16
16
|
)
|
|
17
17
|
">
|
|
@@ -15,7 +15,7 @@ const props = withDefaults(defineProps<PrimitiveProps & {
|
|
|
15
15
|
|
|
16
16
|
<template>
|
|
17
17
|
<Primitive data-slot="sidebar-menu-action" data-sidebar="menu-action" :class="cn(
|
|
18
|
-
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded
|
|
18
|
+
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
19
19
|
'after:absolute after:-inset-2 md:after:hidden',
|
|
20
20
|
'peer-data-[size=sm]/menu-button:top-1',
|
|
21
21
|
'peer-data-[size=default]/menu-button:top-1.5',
|
|
@@ -10,7 +10,7 @@ const props = defineProps<{
|
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
12
|
<div data-slot="sidebar-menu-badge" data-sidebar="menu-badge" :class="cn(
|
|
13
|
-
'text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded
|
|
13
|
+
'text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded px-1 text-xs font-semibold tabular-nums select-none',
|
|
14
14
|
'peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground',
|
|
15
15
|
'peer-data-[size=sm]/menu-button:top-1',
|
|
16
16
|
'peer-data-[size=default]/menu-button:top-1.5',
|
|
@@ -14,11 +14,11 @@ const width = '72%';
|
|
|
14
14
|
|
|
15
15
|
<template>
|
|
16
16
|
<div data-slot="sidebar-menu-skeleton" data-sidebar="menu-skeleton" :class="cn(
|
|
17
|
-
'flex h-8 items-center gap-2 rounded
|
|
17
|
+
'flex h-8 items-center gap-2 rounded px-2 group-data-[compact=true]/sidebar-wrapper:h-7 group-data-[compact=true]/sidebar-wrapper:gap-1.5 group-data-[compact=true]/sidebar-wrapper:px-1.5',
|
|
18
18
|
props.class
|
|
19
19
|
)
|
|
20
20
|
">
|
|
21
|
-
<Skeleton v-if="showIcon" class="size-4 rounded
|
|
21
|
+
<Skeleton v-if="showIcon" class="size-4 rounded group-data-[compact=true]/sidebar-wrapper:size-3.5" data-sidebar="menu-skeleton-icon" />
|
|
22
22
|
|
|
23
23
|
<Skeleton class="h-4 max-w-(--skeleton-width) flex-1" data-sidebar="menu-skeleton-text" :style="{ '--skeleton-width': width }" />
|
|
24
24
|
</div>
|
|
@@ -17,7 +17,7 @@ const props = withDefaults(defineProps<PrimitiveProps & {
|
|
|
17
17
|
|
|
18
18
|
<template>
|
|
19
19
|
<Primitive data-slot="sidebar-menu-sub-button" data-sidebar="menu-sub-button" :as="as" :as-child="asChild" :data-size="size" :data-active="isActive" :class="cn(
|
|
20
|
-
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex min-h-7 min-w-0 -translate-x-px items-center gap-2 rounded
|
|
20
|
+
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex min-h-7 min-w-0 -translate-x-px items-center gap-2 rounded px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 group-data-[compact=true]/sidebar-wrapper:min-h-6 group-data-[compact=true]/sidebar-wrapper:gap-1.5 group-data-[compact=true]/sidebar-wrapper:px-1.5 group-data-[compact=true]/sidebar-wrapper:[&>svg]:size-3.5 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
21
21
|
'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
|
|
22
22
|
size === 'sm' && 'text-xs',
|
|
23
23
|
size === 'md' &&
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { HTMLAttributes, Ref } from 'vue';
|
|
3
|
-
import {
|
|
3
|
+
import { useEventListener, useMediaQuery, useMounted, useVModel } from '@vueuse/core';
|
|
4
|
+
import { useCookie } from 'nuxt/app';
|
|
4
5
|
import { TooltipProvider } from 'reka-ui';
|
|
5
6
|
import { computed, ref } from 'vue';
|
|
6
7
|
import { cn } from '../../../lib/utils';
|
|
@@ -13,7 +14,7 @@ const props = withDefaults(defineProps<{
|
|
|
13
14
|
compact?: boolean;
|
|
14
15
|
class?: HTMLAttributes['class'];
|
|
15
16
|
}>(), {
|
|
16
|
-
defaultOpen:
|
|
17
|
+
defaultOpen: undefined,
|
|
17
18
|
open: undefined,
|
|
18
19
|
compact: false
|
|
19
20
|
});
|
|
@@ -23,19 +24,29 @@ const emits = defineEmits<{
|
|
|
23
24
|
'update:open': [open: boolean];
|
|
24
25
|
}>();
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
// Remembered open state, read per instance on both server and client so the first render matches
|
|
28
|
+
const sidebarCookie = useCookie<boolean | null>(SIDEBAR_COOKIE_NAME, {
|
|
29
|
+
default: () => null,
|
|
30
|
+
maxAge: SIDEBAR_COOKIE_MAX_AGE,
|
|
31
|
+
path: '/'
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// The mobile layout only exists in the browser: render the desktop markup until hydration is done
|
|
35
|
+
const isMounted = useMounted();
|
|
36
|
+
const matchesMobile = useMediaQuery('(max-width: 768px)');
|
|
37
|
+
const isMobile = computed(() => isMounted.value && matchesMobile.value);
|
|
27
38
|
const openMobile = ref(false);
|
|
28
39
|
|
|
29
40
|
const open = useVModel(props, 'open', emits, {
|
|
30
|
-
defaultValue: props.defaultOpen ?? false,
|
|
41
|
+
defaultValue: props.defaultOpen ?? sidebarCookie.value !== false,
|
|
31
42
|
passive: (props.open === undefined) as false
|
|
32
43
|
}) as Ref<boolean>;
|
|
33
44
|
|
|
34
45
|
function setOpen(value: boolean) {
|
|
35
46
|
open.value = value; // emits('update:open', value)
|
|
36
47
|
|
|
37
|
-
//
|
|
38
|
-
|
|
48
|
+
// Keep the sidebar state for the next visit
|
|
49
|
+
sidebarCookie.value = value;
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
function setOpenMobile(value: boolean) {
|
|
@@ -44,14 +44,14 @@ export type SidebarMenuButtonVariants = {
|
|
|
44
44
|
export const sidebarMenuButtonVariants: (
|
|
45
45
|
props?: SidebarMenuButtonVariants & ClassProp
|
|
46
46
|
) => string = cva(
|
|
47
|
-
'peer/menu-button flex w-full items-center gap-2 rounded
|
|
47
|
+
'peer/menu-button flex w-full items-center gap-2 rounded p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,min-height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-semibold data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! group-data-[compact=true]/sidebar-wrapper:gap-1.5 group-data-[compact=true]/sidebar-wrapper:p-2.5 group-data-[compact=true]/sidebar-wrapper:[&>svg]:size-3.5 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
48
48
|
{
|
|
49
49
|
variants: {
|
|
50
50
|
variant: {
|
|
51
51
|
default:
|
|
52
52
|
'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
|
53
53
|
outline:
|
|
54
|
-
'bg-background shadow-[
|
|
54
|
+
'bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]'
|
|
55
55
|
},
|
|
56
56
|
size: {
|
|
57
57
|
default:
|
|
@@ -12,7 +12,7 @@ export const [useSidebar, provideSidebarContext] = createContext<{
|
|
|
12
12
|
state: ComputedRef<'expanded' | 'collapsed'>;
|
|
13
13
|
open: Ref<boolean>;
|
|
14
14
|
setOpen: (value: boolean) => void;
|
|
15
|
-
isMobile: Ref<boolean
|
|
15
|
+
isMobile: Readonly<Ref<boolean>>;
|
|
16
16
|
openMobile: Ref<boolean>;
|
|
17
17
|
setOpenMobile: (value: boolean) => void;
|
|
18
18
|
toggleSidebar: () => void;
|
|
@@ -7,13 +7,14 @@ import { cn } from '../../../lib/utils';
|
|
|
7
7
|
|
|
8
8
|
// Props
|
|
9
9
|
const props = defineProps<SliderRootProps & {
|
|
10
|
+
thumbLabel?: string;
|
|
10
11
|
class?: HTMLAttributes['class'];
|
|
11
12
|
}>();
|
|
12
13
|
|
|
13
14
|
// Emits
|
|
14
15
|
const emits = defineEmits<SliderRootEmits>();
|
|
15
16
|
|
|
16
|
-
const delegatedProps = reactiveOmit(props, 'class');
|
|
17
|
+
const delegatedProps = reactiveOmit(props, 'class', 'thumbLabel');
|
|
17
18
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
18
19
|
</script>
|
|
19
20
|
|
|
@@ -23,12 +24,12 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
|
23
24
|
props.class
|
|
24
25
|
)" v-bind="forwarded">
|
|
25
26
|
<!-- Track -->
|
|
26
|
-
<SliderTrack data-slot="slider-track" class="relative grow overflow-hidden rounded bg-muted
|
|
27
|
+
<SliderTrack data-slot="slider-track" class="relative grow overflow-hidden rounded bg-muted data-[orientation=horizontal]:h-2 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2">
|
|
27
28
|
<!-- Filled range -->
|
|
28
|
-
<SliderRange data-slot="slider-range" class="absolute bg-primary
|
|
29
|
+
<SliderRange data-slot="slider-range" class="absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full" />
|
|
29
30
|
</SliderTrack>
|
|
30
31
|
|
|
31
32
|
<!-- Thumbs -->
|
|
32
|
-
<SliderThumb v-for="(_, key) in modelValue" :key="key" data-slot="slider-thumb" class="block size-5 shrink-0 cursor-grab rounded border-2 border-primary bg-
|
|
33
|
+
<SliderThumb v-for="(_, key) in modelValue" :key="key" data-slot="slider-thumb" :aria-label="props.thumbLabel" class="block size-5 shrink-0 cursor-grab rounded border-2 border-primary bg-card shadow-elevated-sm outline-none transition-[background-color,box-shadow] duration-150 hover:bg-[color-mix(in_oklab,var(--primary)_10%,var(--card))] focus-visible:ring-[3px] focus-visible:ring-ring/45 active:cursor-grabbing active:bg-[color-mix(in_oklab,var(--primary)_15%,var(--card))] disabled:pointer-events-none disabled:opacity-50" />
|
|
33
34
|
</SliderRoot>
|
|
34
35
|
</template>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { HTMLAttributes } from 'vue';
|
|
3
3
|
import { computed } from 'vue';
|
|
4
|
-
import {
|
|
4
|
+
import { useUiVintageMessage } from '../../../lib/i18n';
|
|
5
5
|
import { cn } from '../../../lib/utils';
|
|
6
6
|
|
|
7
7
|
// Props
|
|
@@ -14,7 +14,8 @@ const props = withDefaults(defineProps<{
|
|
|
14
14
|
label: ''
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const message = useUiVintageMessage();
|
|
18
|
+
const resolvedLabel = computed(() => props.label || message('uiVintage.buttons.loading', 'Loading'));
|
|
18
19
|
|
|
19
20
|
// Size classes
|
|
20
21
|
const sizeClasses: Record<NonNullable<typeof props.size>, string> = {
|
|
@@ -5,10 +5,12 @@ import { reactiveOmit } from '@vueuse/core';
|
|
|
5
5
|
import { StepperDescription } from 'reka-ui';
|
|
6
6
|
import { cn } from '../../../lib/utils';
|
|
7
7
|
|
|
8
|
-
// Props
|
|
9
|
-
const props = defineProps<StepperDescriptionProps & {
|
|
8
|
+
// Props (rendered as inline text by default: the stepper trigger is a button, which can't hold headings or paragraphs)
|
|
9
|
+
const props = withDefaults(defineProps<StepperDescriptionProps & {
|
|
10
10
|
class?: HTMLAttributes['class'];
|
|
11
|
-
}>()
|
|
11
|
+
}>(), {
|
|
12
|
+
as: 'span'
|
|
13
|
+
});
|
|
12
14
|
|
|
13
15
|
const delegatedProps = reactiveOmit(props, 'class');
|
|
14
16
|
</script>
|
|
@@ -22,10 +22,10 @@ const state = computed(() => itemContext.state.value);
|
|
|
22
22
|
|
|
23
23
|
<template>
|
|
24
24
|
<StepperIndicator v-slot="{ step }" data-slot="stepper-indicator" :data-state="state" v-bind="delegatedProps" :class="cn(
|
|
25
|
-
'relative inline-flex size-9 shrink-0 items-center justify-center rounded
|
|
25
|
+
'relative inline-flex size-9 shrink-0 items-center justify-center rounded border border-border bg-card text-xs font-semibold text-muted-foreground tabular-nums',
|
|
26
26
|
'[transition:color_150ms,background-color_220ms,border-color_220ms,box-shadow_380ms_var(--ease-spring),transform_380ms_var(--ease-spring)]',
|
|
27
27
|
'group-hover/stepper-trigger:border-border-strong group-active/stepper-trigger:scale-95 group-active/stepper-trigger:duration-75',
|
|
28
|
-
'data-[state=active]:border-primary data-[state=active]:
|
|
28
|
+
'data-[state=active]:border-primary data-[state=active]:bg-primary/10 data-[state=active]:text-primary data-[state=active]:group-hover/stepper-trigger:border-primary',
|
|
29
29
|
'data-[state=completed]:border-primary data-[state=completed]:bg-primary data-[state=completed]:text-primary-foreground data-[state=completed]:group-hover/stepper-trigger:border-primary',
|
|
30
30
|
'[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
|
|
31
31
|
props.class
|
|
@@ -5,10 +5,12 @@ import { reactiveOmit } from '@vueuse/core';
|
|
|
5
5
|
import { StepperTitle } from 'reka-ui';
|
|
6
6
|
import { cn } from '../../../lib/utils';
|
|
7
7
|
|
|
8
|
-
// Props
|
|
9
|
-
const props = defineProps<StepperTitleProps & {
|
|
8
|
+
// Props (rendered as inline text by default: the stepper trigger is a button, which can't hold headings or paragraphs)
|
|
9
|
+
const props = withDefaults(defineProps<StepperTitleProps & {
|
|
10
10
|
class?: HTMLAttributes['class'];
|
|
11
|
-
}>()
|
|
11
|
+
}>(), {
|
|
12
|
+
as: 'span'
|
|
13
|
+
});
|
|
12
14
|
|
|
13
15
|
const delegatedProps = reactiveOmit(props, 'class');
|
|
14
16
|
</script>
|
|
@@ -4,6 +4,7 @@ import type { HTMLAttributes } from 'vue';
|
|
|
4
4
|
import { reactiveOmit } from '@vueuse/core';
|
|
5
5
|
import { SwitchRoot, SwitchThumb, useForwardPropsEmits } from 'reka-ui';
|
|
6
6
|
import { cn } from '../../../lib/utils';
|
|
7
|
+
import { useFieldControlId } from '../field/field-context';
|
|
7
8
|
|
|
8
9
|
// Props
|
|
9
10
|
const props = defineProps<SwitchRootProps & {
|
|
@@ -15,13 +16,16 @@ const emits = defineEmits<SwitchRootEmits>();
|
|
|
15
16
|
|
|
16
17
|
const delegatedProps = reactiveOmit(props, 'class');
|
|
17
18
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
19
|
+
|
|
20
|
+
// Let a surrounding Field label point to this control
|
|
21
|
+
const fieldControlId = useFieldControlId(() => props.id);
|
|
18
22
|
</script>
|
|
19
23
|
|
|
20
24
|
<template>
|
|
21
|
-
<SwitchRoot v-slot="slotProps" data-slot="switch" v-bind="forwarded" :class="cn(
|
|
25
|
+
<SwitchRoot v-slot="slotProps" data-slot="switch" v-bind="forwarded" :id="fieldControlId" :class="cn(
|
|
22
26
|
'group/switch peer relative inline-flex h-7 w-12 shrink-0 cursor-pointer items-center rounded border border-input bg-secondary shadow-elevated-sm outline-none',
|
|
23
27
|
'[transition:background-color_200ms,border-color_200ms,box-shadow_250ms] hover:border-border-strong focus-visible:ring-[3px] focus-visible:ring-ring/45 disabled:cursor-not-allowed disabled:opacity-60',
|
|
24
|
-
'data-[state=checked]:border-primary data-[state=checked]:bg-accent
|
|
28
|
+
'data-[state=checked]:border-primary data-[state=checked]:bg-accent',
|
|
25
29
|
props.class
|
|
26
30
|
)">
|
|
27
31
|
<SwitchThumb data-slot="switch-thumb" :class="cn(
|
|
@@ -21,7 +21,7 @@ const delegatedProps = reactiveOmit(props, 'class', 'indicatorClass');
|
|
|
21
21
|
)">
|
|
22
22
|
<!-- Sliding active indicator -->
|
|
23
23
|
<TabsIndicator data-slot="tabs-indicator" :class="cn(
|
|
24
|
-
'absolute -z-10 rounded border border-primary bg-
|
|
24
|
+
'absolute -z-10 rounded border border-primary/40 bg-primary/10 transition-[translate,width,height] duration-[380ms] ease-spring',
|
|
25
25
|
'group-aria-[orientation=horizontal]/tabs-list:inset-y-1 group-aria-[orientation=horizontal]/tabs-list:left-0 group-aria-[orientation=horizontal]/tabs-list:w-(--reka-tabs-indicator-size) group-aria-[orientation=horizontal]/tabs-list:translate-x-(--reka-tabs-indicator-position)',
|
|
26
26
|
'group-aria-[orientation=vertical]/tabs-list:inset-x-1 group-aria-[orientation=vertical]/tabs-list:top-0 group-aria-[orientation=vertical]/tabs-list:h-(--reka-tabs-indicator-size) group-aria-[orientation=vertical]/tabs-list:translate-y-(--reka-tabs-indicator-position)',
|
|
27
27
|
props.indicatorClass
|
|
@@ -19,7 +19,7 @@ const forwardedProps = useForwardProps(delegatedProps);
|
|
|
19
19
|
'relative inline-flex min-h-9 flex-1 cursor-pointer items-center justify-center gap-1.5 rounded border border-transparent bg-transparent px-4 py-2 text-sm font-semibold whitespace-nowrap text-muted-foreground outline-none select-none',
|
|
20
20
|
'[transition:color_150ms,background-color_150ms,scale_300ms_var(--ease-spring)] hover:text-foreground active:scale-[0.97] focus-visible:ring-[3px] focus-visible:ring-ring/45 disabled:pointer-events-none disabled:opacity-50',
|
|
21
21
|
'data-[state=active]:text-primary data-[state=inactive]:hover:bg-accent/60',
|
|
22
|
-
'[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4
|
|
22
|
+
'[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
|
|
23
23
|
props.class
|
|
24
24
|
)" v-bind="forwardedProps">
|
|
25
25
|
<slot />
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { HTMLAttributes } from 'vue';
|
|
3
3
|
import { useVModel } from '@vueuse/core';
|
|
4
4
|
import { cn } from '../../../lib/utils';
|
|
5
|
+
import { useFieldControlId } from '../field/field-context';
|
|
5
6
|
|
|
6
7
|
// Props
|
|
7
8
|
const props = defineProps<{
|
|
@@ -19,10 +20,13 @@ const modelValue = useVModel(props, 'modelValue', emits, {
|
|
|
19
20
|
passive: true,
|
|
20
21
|
defaultValue: props.defaultValue
|
|
21
22
|
});
|
|
23
|
+
|
|
24
|
+
// Let a surrounding Field label point to this control
|
|
25
|
+
const fieldControlId = useFieldControlId();
|
|
22
26
|
</script>
|
|
23
27
|
|
|
24
28
|
<template>
|
|
25
|
-
<textarea v-model="modelValue" data-slot="textarea" :class="cn(
|
|
29
|
+
<textarea :id="fieldControlId" v-model="modelValue" data-slot="textarea" :class="cn(
|
|
26
30
|
'uv-field flex field-sizing-content min-h-30 w-full min-w-0 rounded border border-input bg-secondary px-4 py-3 text-xs font-semibold text-foreground shadow-elevated-sm outline-none sm:text-sm',
|
|
27
31
|
'selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground placeholder:opacity-60',
|
|
28
32
|
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60 aria-invalid:animate-uv-shake',
|
|
@@ -16,7 +16,7 @@ const props = withDefaults(defineProps<{
|
|
|
16
16
|
inputClass?: HTMLAttributes['class'];
|
|
17
17
|
}>(), {
|
|
18
18
|
defaultValue: '',
|
|
19
|
-
step:
|
|
19
|
+
step: 60,
|
|
20
20
|
disabled: false
|
|
21
21
|
});
|
|
22
22
|
|
|
@@ -43,7 +43,7 @@ const time = computed({
|
|
|
43
43
|
|
|
44
44
|
<template>
|
|
45
45
|
<Input v-model="time" type="time" :step="props.step" :min="props.min" :max="props.max" :disabled="props.disabled" :class="cn(
|
|
46
|
-
'cursor-pointer font-normal hover:border-
|
|
46
|
+
'cursor-pointer font-normal hover:border-border-strong hover:bg-accent [&::-webkit-calendar-picker-indicator]:cursor-pointer [&::-webkit-calendar-picker-indicator]:opacity-70 hover:[&::-webkit-calendar-picker-indicator]:opacity-100',
|
|
47
47
|
props.inputClass,
|
|
48
48
|
props.class
|
|
49
49
|
)
|
|
@@ -85,7 +85,7 @@ const indicatorStyle = computed<CSSProperties>(() => ({
|
|
|
85
85
|
<span v-if="isSingle" data-slot="toggle-group-indicator" aria-hidden="true" :style="indicatorStyle" :class="cn(
|
|
86
86
|
'pointer-events-none absolute top-0 left-0 z-0 rounded-sm border',
|
|
87
87
|
animated && '[transition:transform_380ms_var(--ease-spring),width_380ms_var(--ease-spring),height_380ms_var(--ease-spring),opacity_180ms_var(--ease-snappy)]',
|
|
88
|
-
props.highlight ? 'border-primary/40 bg-primary/10
|
|
88
|
+
props.highlight ? 'border-primary/40 bg-primary/10' : 'border-border-strong bg-surface shadow-elevated-sm'
|
|
89
89
|
)" />
|
|
90
90
|
|
|
91
91
|
<slot v-bind="slotProps" />
|
|
@@ -26,7 +26,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
|
26
26
|
<template>
|
|
27
27
|
<TooltipPortal>
|
|
28
28
|
<TooltipContent data-slot="tooltip-content" v-bind="{ ...forwarded, ...$attrs }" :class="cn(
|
|
29
|
-
'uv-floating-motion bg-foreground text-background z-50 w-fit max-w-72 rounded
|
|
29
|
+
'uv-floating-motion bg-foreground text-background z-50 w-fit max-w-72 rounded px-3 py-1.5 text-xs font-semibold text-balance shadow-elevated-lg',
|
|
30
30
|
props.class
|
|
31
31
|
)
|
|
32
32
|
">
|
package/src/i18n/de.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"common": {
|
|
4
4
|
"breadcrumb": "Brotkrumennavigation",
|
|
5
5
|
"more": "Mehr",
|
|
6
|
+
"home": "Startseite",
|
|
6
7
|
"empty": {
|
|
7
8
|
"title": "Hier gibt es noch nichts",
|
|
8
9
|
"description": "Zurzeit gibt es keine Inhalte zum Anzeigen."
|
|
@@ -10,7 +11,8 @@
|
|
|
10
11
|
"loading": {
|
|
11
12
|
"title": "Wird geladen...",
|
|
12
13
|
"description": "Bitte warte einen Moment, wahrend wir die Inhalte laden."
|
|
13
|
-
}
|
|
14
|
+
},
|
|
15
|
+
"logo": "{name}-Logo"
|
|
14
16
|
},
|
|
15
17
|
"buttons": {
|
|
16
18
|
"remove": "Entfernen",
|
|
@@ -50,7 +52,10 @@
|
|
|
50
52
|
"description": "Nach einem auszuführenden Befehl suchen..."
|
|
51
53
|
},
|
|
52
54
|
"datePicker": {
|
|
53
|
-
"placeholder": "Datum auswählen"
|
|
55
|
+
"placeholder": "Datum auswählen",
|
|
56
|
+
"month": "Monat",
|
|
57
|
+
"year": "Jahr",
|
|
58
|
+
"time": "Uhrzeit"
|
|
54
59
|
},
|
|
55
60
|
"terminal": {
|
|
56
61
|
"title": "Terminal",
|
|
@@ -60,7 +65,9 @@
|
|
|
60
65
|
"code": {
|
|
61
66
|
"title": "Code",
|
|
62
67
|
"copy": "Code kopieren",
|
|
63
|
-
"copied": "Code kopiert"
|
|
68
|
+
"copied": "Code kopiert",
|
|
69
|
+
"position": "Zeile {line}, Spalte {column}",
|
|
70
|
+
"plainText": "Nur-Text"
|
|
64
71
|
},
|
|
65
72
|
"footer": {
|
|
66
73
|
"madeWith": "Gemacht mit",
|
|
@@ -71,14 +78,20 @@
|
|
|
71
78
|
"readingProgress": "Lesefortschritt",
|
|
72
79
|
"readMore": "Weiterlesen",
|
|
73
80
|
"goToPost": "Zum Beitrag",
|
|
81
|
+
"new": "Neu",
|
|
74
82
|
"tableOfContents": "Inhaltsverzeichnis",
|
|
75
83
|
"tableOfContentsDescription": "Zu einem Abschnitt dieses Artikels springen",
|
|
84
|
+
"tableOfContentsSections": "{count} Abschnitt | {count} Abschnitte",
|
|
76
85
|
"openTableOfContents": "Inhaltsverzeichnis offnen",
|
|
77
86
|
"closeTableOfContents": "Inhaltsverzeichnis schliessen",
|
|
78
87
|
"loadMoreWithNumbers": "Mehr laden ({current}/{total})",
|
|
79
88
|
"author": "Autor",
|
|
80
89
|
"publishedDate": "Veroffentlicht",
|
|
81
90
|
"lastUpdatedDate": "Aktualisiert",
|
|
91
|
+
"readingTime": "Lesezeit",
|
|
92
|
+
"readingTimeValue": "{minutes} Min.",
|
|
93
|
+
"category": "Kategorie",
|
|
94
|
+
"breadcrumbBlog": "Blog",
|
|
82
95
|
"carouselNavigation": "Karussellnavigation",
|
|
83
96
|
"goToSlide": "Zur Folie {index} wechseln",
|
|
84
97
|
"previousSlide": "Vorherige Folie",
|
|
@@ -97,9 +110,6 @@
|
|
|
97
110
|
"copied": "Link kopiert"
|
|
98
111
|
}
|
|
99
112
|
},
|
|
100
|
-
"select": {
|
|
101
|
-
"defaultPlaceholder": "Option auswahlen"
|
|
102
|
-
},
|
|
103
113
|
"errorPage": {
|
|
104
114
|
"notFound": {
|
|
105
115
|
"title": "Seite nicht gefunden",
|
package/src/i18n/en.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"common": {
|
|
4
4
|
"breadcrumb": "Breadcrumb",
|
|
5
5
|
"more": "More",
|
|
6
|
+
"home": "Home",
|
|
6
7
|
"empty": {
|
|
7
8
|
"title": "Nothing here yet",
|
|
8
9
|
"description": "There is no content to show right now."
|
|
@@ -10,7 +11,8 @@
|
|
|
10
11
|
"loading": {
|
|
11
12
|
"title": "Loading...",
|
|
12
13
|
"description": "Please wait a moment while we load the content."
|
|
13
|
-
}
|
|
14
|
+
},
|
|
15
|
+
"logo": "{name} logo"
|
|
14
16
|
},
|
|
15
17
|
"buttons": {
|
|
16
18
|
"remove": "Remove",
|
|
@@ -50,7 +52,10 @@
|
|
|
50
52
|
"description": "Search for a command to run..."
|
|
51
53
|
},
|
|
52
54
|
"datePicker": {
|
|
53
|
-
"placeholder": "Pick a date"
|
|
55
|
+
"placeholder": "Pick a date",
|
|
56
|
+
"month": "Month",
|
|
57
|
+
"year": "Year",
|
|
58
|
+
"time": "Time"
|
|
54
59
|
},
|
|
55
60
|
"terminal": {
|
|
56
61
|
"title": "Terminal",
|
|
@@ -60,7 +65,9 @@
|
|
|
60
65
|
"code": {
|
|
61
66
|
"title": "Code",
|
|
62
67
|
"copy": "Copy code",
|
|
63
|
-
"copied": "Code copied"
|
|
68
|
+
"copied": "Code copied",
|
|
69
|
+
"position": "Ln {line}, Col {column}",
|
|
70
|
+
"plainText": "Plain text"
|
|
64
71
|
},
|
|
65
72
|
"footer": {
|
|
66
73
|
"madeWith": "Made with",
|
|
@@ -71,14 +78,20 @@
|
|
|
71
78
|
"readingProgress": "Reading progress",
|
|
72
79
|
"readMore": "Read more",
|
|
73
80
|
"goToPost": "Go to post",
|
|
81
|
+
"new": "New",
|
|
74
82
|
"tableOfContents": "Table of contents",
|
|
75
83
|
"tableOfContentsDescription": "Jump to a section of this article",
|
|
84
|
+
"tableOfContentsSections": "{count} section | {count} sections",
|
|
76
85
|
"openTableOfContents": "Open table of contents",
|
|
77
86
|
"closeTableOfContents": "Close table of contents",
|
|
78
87
|
"loadMoreWithNumbers": "Load more ({current}/{total})",
|
|
79
88
|
"author": "Author",
|
|
80
89
|
"publishedDate": "Published",
|
|
81
90
|
"lastUpdatedDate": "Updated",
|
|
91
|
+
"readingTime": "Reading time",
|
|
92
|
+
"readingTimeValue": "{minutes} min",
|
|
93
|
+
"category": "Category",
|
|
94
|
+
"breadcrumbBlog": "Blog",
|
|
82
95
|
"carouselNavigation": "Carousel navigation",
|
|
83
96
|
"goToSlide": "Go to slide {index}",
|
|
84
97
|
"previousSlide": "Previous slide",
|
|
@@ -97,9 +110,6 @@
|
|
|
97
110
|
"copied": "Link copied"
|
|
98
111
|
}
|
|
99
112
|
},
|
|
100
|
-
"select": {
|
|
101
|
-
"defaultPlaceholder": "Select an option"
|
|
102
|
-
},
|
|
103
113
|
"errorPage": {
|
|
104
114
|
"notFound": {
|
|
105
115
|
"title": "Page not found",
|