feat(ui): standardize design system, modals, sidebar, and form inputs
- Implement unified design system tokens, 10px radius, and IRANSans typography - Modernize sidebar with Gemini-style collapsed expander, square 1:1 items, and elevated profile flyout - Standardize all modal dialogs with 16px padding, fixed header/footer, 16px medium title, and sticky bottom actions - Refactor DealFormView and CustomFieldsSection with standard UiField, UiInput, and UiSelect components - Add draggable bottom-left QuickCreate floating action button
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
label?: string;
|
||||
forId?: string;
|
||||
required?: boolean;
|
||||
hint?: string;
|
||||
error?: string | boolean;
|
||||
horizontal?: boolean;
|
||||
}>(),
|
||||
{
|
||||
required: false,
|
||||
horizontal: false,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="ui-field" :class="{ horizontal, hasError: !!error }">
|
||||
<div v-if="label || $slots.label" class="label-row">
|
||||
<label v-if="label" :for="forId" class="field-label">
|
||||
{{ label }}
|
||||
<span v-if="required" class="required-mark" aria-hidden="true">*</span>
|
||||
</label>
|
||||
<slot v-else name="label" />
|
||||
<slot name="label-extra" />
|
||||
</div>
|
||||
|
||||
<div class="control-wrap">
|
||||
<slot />
|
||||
<p v-if="typeof error === 'string' && error" class="field-error" role="alert">
|
||||
{{ error }}
|
||||
</p>
|
||||
<p v-else-if="hint || $slots.hint" class="field-hint">
|
||||
<slot name="hint">{{ hint }}</slot>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.ui-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-1);
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ui-field.horizontal {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--sp-3);
|
||||
}
|
||||
|
||||
.ui-field.horizontal .label-row {
|
||||
flex: 0 0 140px;
|
||||
}
|
||||
|
||||
.ui-field.horizontal .control-wrap {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.label-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--sp-2);
|
||||
}
|
||||
|
||||
.field-label {
|
||||
font-size: var(--fs-sm);
|
||||
font-weight: var(--fw-semibold);
|
||||
color: var(--ink-secondary);
|
||||
line-height: var(--lh-tight);
|
||||
}
|
||||
|
||||
.required-mark {
|
||||
color: var(--danger);
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.control-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.field-error {
|
||||
margin: 2px 0 0;
|
||||
font-size: var(--fs-xs);
|
||||
color: var(--danger);
|
||||
font-weight: var(--fw-medium);
|
||||
}
|
||||
|
||||
.field-hint {
|
||||
margin: 2px 0 0;
|
||||
font-size: var(--fs-xs);
|
||||
color: var(--muted);
|
||||
line-height: var(--lh-normal);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user