style(ui): unify sky-atlas visual system

Centralize interactive component styles, adopt the fresh eucalyptus palette, and keep map controls square with hard shadows. Update project guidance and the OpenCloud style skill to match the implementation.
This commit is contained in:
2026-07-25 02:41:27 +08:00
parent 2b82ec7d9c
commit 55c90e8c60
26 changed files with 710 additions and 453 deletions
+20 -5
View File
@@ -7,30 +7,43 @@ const sourceRoot = new URL('../src', import.meta.url)
const deprecatedPatterns = [
{
pattern: /\b(?:bg|border|ring|text)-(?:gray|indigo|purple|violet)-\d+\b/g,
message: '使用项目约定的 slate/sky/teal 语义色,不要重新引入灰色或紫色系。',
message: '使用项目约定的 slate/sky/自然绿色语义色,不要重新引入灰色或紫色系。',
},
{
pattern: /\b(?:bg|border|ring|text)-(?:green|lime)-\d+\b/g,
message: '绿色必须使用项目重映射后的 teal 品牌色或 emerald 成功色,不要引入默认 green/lime 荧光色。',
},
{
pattern: /#(?:f0fdfa|ccfbf1|99f6e4|5eead4|2dd4bf|14b8a6|0d9488|0f766e|115e59|134e4a)\b/gi,
message: '检测到旧版高饱和 teal 色值,请改用自然绿色设计令牌。',
},
{
pattern: /text-xs uppercase tracking-\[0\.18em\] text-slate-500/g,
message: '重复的小节标签应使用 oc-section-label。',
vueOnly: true,
},
{
pattern: /border border-slate-200 bg-slate-50 p-4/g,
message: '标准内嵌信息面板应使用 oc-inset-panel。',
vueOnly: true,
},
{
pattern: /border-b border-sky-100 bg-\[linear-gradient\(180deg,#e0f2fe_0%,#f8fafc_100%\)\]/g,
message: '标准页面头部应使用 oc-page-hero。',
vueOnly: true,
},
]
async function collectVueFiles(directory) {
const styleSourceExtensions = new Set(['.vue', '.css', '.ts'])
async function collectStyleSourceFiles(directory) {
const entries = await readdir(directory, { withFileTypes: true })
const files = await Promise.all(entries.map(async (entry) => {
const path = join(directory, entry.name)
return entry.isDirectory() ? collectVueFiles(path) : [path]
return entry.isDirectory() ? collectStyleSourceFiles(path) : [path]
}))
return files.flat().filter((path) => extname(path) === '.vue')
return files.flat().filter((path) => styleSourceExtensions.has(extname(path)))
}
function lineNumberAt(source, index) {
@@ -39,10 +52,12 @@ function lineNumberAt(source, index) {
const violations = []
for (const file of await collectVueFiles(sourceRoot.pathname)) {
for (const file of await collectStyleSourceFiles(sourceRoot.pathname)) {
const source = await readFile(file, 'utf8')
for (const rule of deprecatedPatterns) {
if (rule.vueOnly && extname(file) !== '.vue') continue
for (const match of source.matchAll(rule.pattern)) {
violations.push({
file: relative(projectRoot.pathname, file),