Adopt logistics visual system across webapp

This commit is contained in:
Ruslan Bakiev
2026-04-11 08:31:34 +07:00
parent ebe72907a4
commit a74e75049c
28 changed files with 1434 additions and 240 deletions

View File

@@ -17,22 +17,22 @@ const props = defineProps({
})
const variantMap: Record<string, string> = {
default: 'badge-neutral',
success: 'badge-success',
warning: 'badge-warning',
error: 'badge-error',
muted: 'badge-ghost',
primary: 'badge-primary',
default: 'bg-[#f6f1ea] text-[#5f4b33]',
success: 'bg-emerald-100 text-emerald-700',
warning: 'bg-amber-100 text-amber-700',
error: 'bg-rose-100 text-rose-700',
muted: 'bg-[#efe7da] text-[#8a7761]',
primary: 'bg-[#2f2418] text-white',
}
const sizeMap: Record<string, string> = {
xs: 'badge-xs',
sm: 'badge-sm',
md: 'badge-md',
xs: 'px-2 py-1 text-[10px]',
sm: 'px-3 py-1 text-xs',
md: 'px-3.5 py-1.5 text-sm',
}
const badgeClass = computed(() => {
const base = 'badge'
const base = 'inline-flex items-center rounded-full font-semibold'
const variantClass = variantMap[props.variant] || variantMap.default
const sizeClass = sizeMap[props.size] || sizeMap.sm
return [base, variantClass, sizeClass].join(' ')

View File

@@ -2,7 +2,7 @@
<component
:is="componentTag"
:type="componentType"
:class="['btn', variantClass, fullWidth ? 'w-full' : '']"
:class="[baseClass, variantClass, fullWidth ? 'w-full' : '']"
v-bind="$attrs"
>
<slot />
@@ -36,10 +36,11 @@ const componentTag = computed(() => {
return props.as || 'button'
})
const componentType = computed(() => (props.as === 'button' ? props.type : undefined))
const baseClass = 'inline-flex items-center justify-center gap-2 rounded-full border-0 px-5 py-3 text-sm font-bold transition duration-200'
const variantClass = computed(() => {
if (props.variant === 'outline') return 'btn-outline btn-primary'
if (props.variant === 'ghost') return 'btn-ghost'
return 'btn-primary'
if (props.variant === 'outline') return 'bg-transparent text-[#2f2418] ring-1 ring-[#cbbca6] hover:bg-[#f6f1ea]'
if (props.variant === 'ghost') return 'bg-[#f6f1ea] text-[#5f4b33] hover:bg-[#ece2d3]'
return 'bg-[#2f2418] text-white shadow-[0_12px_28px_rgba(47,36,24,0.16)] hover:bg-[#493824]'
})
</script>

View File

@@ -27,18 +27,18 @@ const paddingMap: Record<string, string> = {
}
const toneMap: Record<string, string> = {
default: 'bg-base-100',
muted: 'bg-base-200',
primary: 'bg-primary/10',
default: 'bg-white',
muted: 'bg-[#fbf8f4]',
primary: 'bg-[#f6f1ea]',
}
const cardClass = computed(() => {
const paddingClass = paddingMap[props.padding] || paddingMap.medium
const toneClass = toneMap[props.tone] || toneMap.default
const interactiveClass = props.interactive
? 'cursor-pointer hover:shadow-lg transition-shadow duration-200'
? 'cursor-pointer transition-[transform,box-shadow] duration-200 hover:-translate-y-0.5 hover:shadow-[0_18px_34px_rgba(62,47,26,0.12)]'
: ''
const baseClass = 'card'
const baseClass = 'rounded-[28px] border border-[#eadfce] text-[#2f2418] shadow-none'
return [baseClass, paddingClass, toneClass, interactiveClass].filter(Boolean).join(' ')
})
</script>

View File

@@ -1,9 +1,9 @@
<template>
<label v-if="label" class="w-full space-y-1">
<span class="text-base font-semibold text-base-content">{{ label }}</span>
<label v-if="label" class="w-full space-y-2">
<span class="text-sm font-bold uppercase tracking-[0.12em] text-[#8a7761]">{{ label }}</span>
<input
v-bind="$attrs"
class="input input-bordered w-full bg-base-100 text-base-content placeholder-base-content/60"
class="h-12 w-full rounded-full border-0 bg-[#f6f1ea] px-5 text-[#2f2418] shadow-none outline-none placeholder:text-[#9b8d79]"
:value="modelValue"
@input="onInput"
/>
@@ -11,7 +11,7 @@
<input
v-else
v-bind="$attrs"
class="input input-bordered w-full bg-base-100 text-base-content placeholder-base-content/60"
class="h-12 w-full rounded-full border-0 bg-[#f6f1ea] px-5 text-[#2f2418] shadow-none outline-none placeholder:text-[#9b8d79]"
:value="modelValue"
@input="onInput"
/>

View File

@@ -1,8 +1,9 @@
<template>
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div class="space-y-1">
<h1 class="text-2xl lg:text-3xl font-bold text-base-content">{{ title }}</h1>
<p v-if="description" class="text-base-content/70">{{ description }}</p>
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div class="space-y-2">
<p class="text-xs font-bold uppercase tracking-[0.16em] text-[#8c7b67]">Workspace</p>
<h1 class="text-2xl font-black text-[#2f2418] lg:text-3xl">{{ title }}</h1>
<p v-if="description" class="max-w-[720px] text-sm leading-6 text-[#6f6353]">{{ description }}</p>
</div>
<div v-if="$slots.actions || actions?.length" class="flex items-center gap-2 flex-shrink-0">
<slot name="actions">

View File

@@ -2,7 +2,7 @@
<component
:is="to ? NuxtLink : 'button'"
:to="to"
class="btn btn-sm btn-ghost gap-2"
class="inline-flex items-center gap-2 rounded-full bg-[#f6f1ea] px-4 py-2 text-sm font-bold text-[#5f4b33] transition hover:bg-[#ece2d3]"
@click="!to && $emit('click')"
>
<Icon v-if="icon" :name="icon" size="16" />

View File

@@ -21,20 +21,20 @@ const props = defineProps({
})
const variantMap: Record<string, string> = {
neutral: 'badge-neutral',
primary: 'badge-primary',
outline: 'badge-outline',
inverse: 'badge-ghost bg-white/10 text-white border border-white/40',
neutral: 'bg-[#f6f1ea] text-[#5f4b33]',
primary: 'bg-[#2f2418] text-white',
outline: 'bg-transparent text-[#2f2418] ring-1 ring-[#cbbca6]',
inverse: 'bg-white/10 text-white border border-white/40',
}
const toneMap: Record<string, string> = {
default: '',
success: 'badge-success',
warning: 'badge-warning',
success: 'bg-emerald-100 text-emerald-700',
warning: 'bg-amber-100 text-amber-700',
}
const pillClass = computed(() => {
const base = ['badge', props.size === 'sm' ? 'badge-sm' : 'badge-md']
const base = ['inline-flex items-center rounded-full font-semibold', props.size === 'sm' ? 'px-3 py-1 text-xs' : 'px-3.5 py-1.5 text-sm']
const variantClass = variantMap[props.variant] || variantMap.neutral
const toneClass = toneMap[props.tone] || ''
return [base, variantClass, toneClass].flat().filter(Boolean).join(' ')

View File

@@ -17,8 +17,8 @@ const props = defineProps({
})
const variantMap: Record<string, string> = {
default: 'bg-base-200 text-base-content',
hero: 'bg-primary text-primary-content rounded-box overflow-hidden px-6',
default: 'rounded-[28px] bg-white px-6 text-[#2f2418] shadow-none',
hero: 'overflow-hidden rounded-[34px] bg-[#10223b] px-6 text-white shadow-[0_22px_54px_rgba(16,34,59,0.24)]',
plain: '',
}

View File

@@ -1,5 +1,5 @@
<template>
<select v-bind="$attrs" class="select select-bordered w-full">
<select v-bind="$attrs" class="h-12 w-full rounded-full border-0 bg-[#f6f1ea] px-5 text-[#2f2418] shadow-none outline-none">
<slot />
</select>
</template>

View File

@@ -1,6 +1,6 @@
<template>
<label v-if="label" class="w-full space-y-1">
<span class="text-base font-semibold text-base-content">{{ label }}</span>
<label v-if="label" class="w-full space-y-2">
<span class="text-sm font-bold uppercase tracking-[0.12em] text-[#8a7761]">{{ label }}</span>
<textarea
v-bind="$attrs"
:class="fieldClass"
@@ -39,6 +39,6 @@ const onInput = (event: Event) => {
}
const fieldClass = computed(() =>
['textarea textarea-bordered w-full min-h-[120px]', props.mono ? 'font-mono' : ''].join(' ')
['w-full min-h-[120px] rounded-[24px] border-0 bg-[#f6f1ea] px-5 py-4 text-[#2f2418] shadow-none outline-none placeholder:text-[#9b8d79]', props.mono ? 'font-mono' : ''].join(' ')
)
</script>