refactor(styles): 建立统一的生产级样式体系 (#4)
## 变更内容 - 将全局样式拆分为设计令牌、基础规则和语义组件层 - 集中管理 Naive UI 主题配置 - 迁移页面容器、表单、信息面板和按钮等重复样式 - 增加样式体系文档与自动契约检查 ## 验证 - `npm run check:styles` - `npm run build`Reviewed-on: #4
This commit was merged in pull request #4.
This commit is contained in:
@@ -119,7 +119,7 @@ watch(() => props.initialValue, value => {
|
||||
<div class="flex items-start justify-between border-b border-slate-200 px-6 py-5">
|
||||
<div>
|
||||
<h3 class="text-xl font-semibold text-slate-900">编辑图片信息</h3>
|
||||
<p class="mt-1 text-sm text-slate-500">修改后会同步影响个人主页、画廊和地图中的展示。</p>
|
||||
<p class="oc-field-help">修改后会同步影响个人主页、画廊和地图中的展示。</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@@ -143,10 +143,10 @@ watch(() => props.initialValue, value => {
|
||||
|
||||
<div class="grid gap-5">
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">类别</label>
|
||||
<label class="oc-field-label">类别</label>
|
||||
<select
|
||||
:value="form.cloudCategoryId ?? ''"
|
||||
class="w-full border border-slate-300 bg-white px-3 py-2.5 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500"
|
||||
class="oc-field-control"
|
||||
@change="onCategoryChange"
|
||||
>
|
||||
<option value="" disabled>请选择</option>
|
||||
@@ -158,36 +158,36 @@ watch(() => props.initialValue, value => {
|
||||
</div>
|
||||
|
||||
<div v-if="form.cloudCategoryId === 'other'">
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">自定义云型</label>
|
||||
<label class="oc-field-label">自定义云型</label>
|
||||
<input
|
||||
v-model="form.customCloudType"
|
||||
type="text"
|
||||
class="w-full border border-slate-300 px-3 py-2.5 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500"
|
||||
class="oc-field-control"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">拍摄时间</label>
|
||||
<label class="oc-field-label">拍摄时间</label>
|
||||
<input
|
||||
v-model="form.capturedAt"
|
||||
type="datetime-local"
|
||||
class="w-full border border-slate-300 px-3 py-2.5 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500"
|
||||
class="oc-field-control"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">位置名称</label>
|
||||
<label class="oc-field-label">位置名称</label>
|
||||
<input
|
||||
v-model="form.locationName"
|
||||
type="text"
|
||||
class="w-full border border-slate-300 px-3 py-2.5 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500"
|
||||
class="oc-field-control"
|
||||
placeholder="如:北京、成都"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="mb-1 flex items-center justify-between gap-3">
|
||||
<label class="block text-sm font-medium text-slate-700">经纬度</label>
|
||||
<label class="oc-field-label mb-0">经纬度</label>
|
||||
<button
|
||||
v-if="hasCoordinates"
|
||||
type="button"
|
||||
@@ -203,7 +203,7 @@ watch(() => props.initialValue, value => {
|
||||
type="number"
|
||||
step="any"
|
||||
placeholder="纬度"
|
||||
class="w-full border border-slate-300 px-3 py-2.5 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500"
|
||||
class="oc-field-control"
|
||||
@input="onLatInput"
|
||||
/>
|
||||
<input
|
||||
@@ -211,7 +211,7 @@ watch(() => props.initialValue, value => {
|
||||
type="number"
|
||||
step="any"
|
||||
placeholder="经度"
|
||||
class="w-full border border-slate-300 px-3 py-2.5 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500"
|
||||
class="oc-field-control"
|
||||
@input="onLngInput"
|
||||
/>
|
||||
<button
|
||||
@@ -227,7 +227,7 @@ watch(() => props.initialValue, value => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">图片描述</label>
|
||||
<label class="oc-field-label">图片描述</label>
|
||||
<textarea
|
||||
v-model="form.description"
|
||||
rows="4"
|
||||
|
||||
@@ -154,7 +154,7 @@ onBeforeUnmount(() => {
|
||||
<div class="flex items-start justify-between border-b border-slate-200 px-6 py-5">
|
||||
<div>
|
||||
<h3 class="text-xl font-semibold text-slate-900">{{ title }}</h3>
|
||||
<p class="mt-1 text-sm text-slate-500">{{ description }}</p>
|
||||
<p class="oc-field-help">{{ description }}</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -101,7 +101,7 @@ onBeforeUnmount(() => {
|
||||
<div v-if="hasCoordinates" class="mt-5 overflow-hidden border border-slate-200 bg-white">
|
||||
<div class="flex items-center justify-between border-b border-slate-200 px-4 py-3">
|
||||
<div>
|
||||
<p class="text-xs uppercase tracking-[0.18em] text-slate-500">位置地图</p>
|
||||
<p class="oc-section-label">位置地图</p>
|
||||
<p class="mt-1 text-sm font-medium text-slate-900">{{ locationName || '拍摄位置' }}</p>
|
||||
</div>
|
||||
<p class="text-right text-[11px] leading-5 text-slate-500">
|
||||
|
||||
@@ -203,7 +203,7 @@ onBeforeUnmount(() => {
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.22em] text-sky-700">Quick Upload</p>
|
||||
<h2 class="mt-2 text-xl font-bold text-slate-950">快速上传云图</h2>
|
||||
<p class="mt-1 text-sm text-slate-500">从地图当前位置带入经纬度,提交后进入审核队列。</p>
|
||||
<p class="oc-field-help">从地图当前位置带入经纬度,提交后进入审核队列。</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@@ -242,7 +242,7 @@ onBeforeUnmount(() => {
|
||||
>
|
||||
<NIcon size="42" class="text-sky-600"><CloudUpload /></NIcon>
|
||||
<p class="mt-3 text-base font-semibold text-slate-800">选择一张云图</p>
|
||||
<p class="mt-1 text-sm text-slate-500">支持 JPG、PNG,可点击或拖拽上传。</p>
|
||||
<p class="oc-field-help">支持 JPG、PNG,可点击或拖拽上传。</p>
|
||||
</div>
|
||||
|
||||
<template v-else-if="activeItem">
|
||||
@@ -259,10 +259,10 @@ onBeforeUnmount(() => {
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">类别 <span class="text-rose-500">*</span></label>
|
||||
<label class="oc-field-label">类别 <span class="oc-field-required">*</span></label>
|
||||
<select
|
||||
:value="activeItem.cloudCategoryId ?? ''"
|
||||
class="w-full border border-slate-300 bg-white px-3 py-2.5 text-sm text-slate-800 outline-none transition-colors focus:border-sky-500 focus:ring-2 focus:ring-sky-100"
|
||||
class="oc-field-control"
|
||||
@change="onCategoryChange"
|
||||
>
|
||||
<option value="" disabled>请选择</option>
|
||||
@@ -276,25 +276,25 @@ onBeforeUnmount(() => {
|
||||
v-model="activeItem.customCloudType"
|
||||
type="text"
|
||||
placeholder="输入云的类型"
|
||||
class="mt-2 w-full border border-slate-300 px-3 py-2 text-sm outline-none transition-colors focus:border-sky-500 focus:ring-2 focus:ring-sky-100"
|
||||
class="oc-field-control mt-2"
|
||||
@input="activeItem.errors = {}"
|
||||
/>
|
||||
<p v-if="activeItem.errors.cloudCategory" class="mt-1 text-sm text-rose-600">{{ activeItem.errors.cloudCategory }}</p>
|
||||
<p v-if="activeItem.errors.cloudCategory" class="oc-field-error">{{ activeItem.errors.cloudCategory }}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">拍摄时间 <span class="text-rose-500">*</span></label>
|
||||
<label class="oc-field-label">拍摄时间 <span class="oc-field-required">*</span></label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
:value="formatDatetimeLocal(activeItem.capturedAt)"
|
||||
class="w-full border border-slate-300 px-3 py-2 text-sm outline-none transition-colors focus:border-sky-500 focus:ring-2 focus:ring-sky-100"
|
||||
class="oc-field-control"
|
||||
@change="onCapturedAtChange"
|
||||
/>
|
||||
<p v-if="activeItem.errors.capturedAt" class="mt-1 text-sm text-rose-600">{{ activeItem.errors.capturedAt }}</p>
|
||||
<p v-if="activeItem.errors.capturedAt" class="oc-field-error">{{ activeItem.errors.capturedAt }}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">经纬度</label>
|
||||
<label class="oc-field-label">经纬度</label>
|
||||
<div class="grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_40px] gap-2">
|
||||
<div>
|
||||
<input
|
||||
@@ -302,10 +302,10 @@ onBeforeUnmount(() => {
|
||||
type="number"
|
||||
step="any"
|
||||
placeholder="纬度"
|
||||
class="w-full border border-slate-300 px-3 py-2 text-sm outline-none transition-colors focus:border-sky-500 focus:ring-2 focus:ring-sky-100"
|
||||
class="oc-field-control"
|
||||
@input="onLatInput"
|
||||
/>
|
||||
<p v-if="activeItem.errors.latitude" class="mt-1 text-sm text-rose-600">{{ activeItem.errors.latitude }}</p>
|
||||
<p v-if="activeItem.errors.latitude" class="oc-field-error">{{ activeItem.errors.latitude }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
@@ -313,10 +313,10 @@ onBeforeUnmount(() => {
|
||||
type="number"
|
||||
step="any"
|
||||
placeholder="经度"
|
||||
class="w-full border border-slate-300 px-3 py-2 text-sm outline-none transition-colors focus:border-sky-500 focus:ring-2 focus:ring-sky-100"
|
||||
class="oc-field-control"
|
||||
@input="onLngInput"
|
||||
/>
|
||||
<p v-if="activeItem.errors.longitude" class="mt-1 text-sm text-rose-600">{{ activeItem.errors.longitude }}</p>
|
||||
<p v-if="activeItem.errors.longitude" class="oc-field-error">{{ activeItem.errors.longitude }}</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@@ -334,22 +334,22 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">位置名称</label>
|
||||
<label class="oc-field-label">位置名称</label>
|
||||
<input
|
||||
v-model="activeItem.locationName"
|
||||
type="text"
|
||||
placeholder="如:北京、成都"
|
||||
class="w-full border border-slate-300 px-3 py-2 text-sm outline-none transition-colors focus:border-sky-500 focus:ring-2 focus:ring-sky-100"
|
||||
class="oc-field-control"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-slate-700">图片说明</label>
|
||||
<label class="oc-field-label">图片说明</label>
|
||||
<textarea
|
||||
v-model="activeItem.description"
|
||||
rows="3"
|
||||
placeholder="描述一下这张图片..."
|
||||
class="w-full resize-none border border-slate-300 px-3 py-2 text-sm outline-none transition-colors focus:border-sky-500 focus:ring-2 focus:ring-sky-100"
|
||||
class="oc-field-control resize-none"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user