diff --git a/web/src/App.tsx b/web/src/App.tsx index c3741fb..c0290be 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,7 +1,7 @@ import { lazy, Suspense, useEffect, useState } from 'react' import type { ReactNode } from 'react' import { Navigate, Route, Routes } from 'react-router' -import { App as AntdApp, ConfigProvider } from 'antd' +import { App as AntdApp, ConfigProvider, Spin } from 'antd' import zhCN from 'antd/locale/zh_CN' import { useAuth } from './lib/auth' import { useTheme } from './lib/theme' @@ -45,7 +45,7 @@ function AntdProvider({ children }: { children: ReactNode }) { function RequireAuth({ children }: { children: ReactNode }) { const { authenticated, loading } = useAuth() if (loading) { - return
加载中…
+ return
} if (!authenticated) { return @@ -56,7 +56,7 @@ function RequireAuth({ children }: { children: ReactNode }) { export default function App() { return ( - 加载中…}> + }> }> } /> diff --git a/web/src/components/Layout.tsx b/web/src/components/Layout.tsx index 863771d..d61e7fb 100644 --- a/web/src/components/Layout.tsx +++ b/web/src/components/Layout.tsx @@ -2,7 +2,7 @@ import { Link, NavLink, Outlet, useLocation, useNavigate } from 'react-router' import { Moon, Sun, Monitor, ExternalLink, House, PenLine, MoreHorizontal, Tags, Trash2, Settings, LogOut, } from 'lucide-react' -import { Dropdown, Menu, Tooltip } from 'antd' +import { Button, Dropdown, Menu, Tooltip } from 'antd' import type { MenuProps } from 'antd' import { useSiteTitle } from '../features/site' import { useTheme } from '../lib/theme' @@ -20,9 +20,7 @@ function MoreMenu({ triggerClassName, triggerLabel, items }: { // 曾致桌面导航整体横移 4px)
- +
) @@ -49,15 +47,14 @@ function ThemeButton({ className = 'pn-site-navlink' }: { className?: string }) const next = mode === 'light' ? 'dark' : mode === 'dark' ? 'system' : 'light' const title = `主题:${mode === 'light' ? '浅色' : mode === 'dark' ? '深色' : '跟随系统'}(点击切换)` return ( - + /> ) } @@ -132,14 +129,13 @@ function AdminThemeButton() { const label = `主题:${mode === 'light' ? '浅色' : mode === 'dark' ? '深色' : '跟随系统'}(点击切换)` return ( - + /> ) } @@ -269,25 +265,24 @@ function AdminSidebar() { - - - + icon={} + /> - + /> diff --git a/web/src/components/MarkdownViewer.tsx b/web/src/components/MarkdownViewer.tsx index 96edb7e..3285f0c 100644 --- a/web/src/components/MarkdownViewer.tsx +++ b/web/src/components/MarkdownViewer.tsx @@ -1,7 +1,8 @@ -import { memo } from 'react' +import { memo, useState } from 'react' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import rehypeHighlight from 'rehype-highlight' +import { Button } from 'antd' import { sanitizePlugin } from '../lib/sanitize' /** @@ -25,18 +26,29 @@ function CodeBlock(props: React.HTMLAttributes) { } function CopyButton() { - // 复制按钮在点击时读取最近兄弟
 的文本;不注入任何 HTML
+  // 复制按钮在点击时读取最近兄弟 
 的文本;不注入任何 HTML。
+  // MarkdownViewer 会在无 App 上下文的单测中渲染,反馈用本地状态而非 message。
+  const [copied, setCopied] = useState(false)
   return (
-    
+      {copied ? '已复制' : '复制'}
+    
   )
 }
 
diff --git a/web/src/index.css b/web/src/index.css
index 9979016..dbba803 100644
--- a/web/src/index.css
+++ b/web/src/index.css
@@ -213,17 +213,6 @@ input.ant-input::placeholder,
 textarea.ant-input::placeholder {
   color: var(--muted-foreground);
 }
-/* antd 按钮的 danger-outline 形态(默认描边 + 危险色文字) */
-button.ant-btn.pn-btn-danger-outline {
-  color: var(--destructive-text);
-  border-color: var(--destructive-border);
-  background: transparent;
-}
-button.ant-btn.pn-btn-danger-outline:hover:not(:disabled) {
-  color: var(--destructive-text) !important;
-  border-color: var(--destructive-border) !important;
-  background: var(--destructive-subtle) !important;
-}
 /* Dropdown 内路由项:激活态与旧 .pn-moremenu-item.active 一致 */
 .pn-dd-link {
   display: inline-flex;
@@ -358,25 +347,7 @@ button.pn-login-back:hover {
 }
 
 
-/* 表格卡空态(无数据/加载中占位) */
-.pn-empty {
-  display: grid;
-  place-items: center;
-  min-height: 132px;
-  padding: 12px;
-  color: var(--muted-foreground);
-  background: var(--muted);
-  font-size: 13px;
-}
-
-/* ── 状态点 ── */
-.dot {
-  width: 7px;
-  height: 7px;
-  border-radius: 999px;
-  background: currentColor;
-  flex: none;
-}
+/* 加载/空态(Spin/Skeleton/Empty)已由 antd 承接 */
 
 /* ============================================================
    博客端共享 shell —— 居中单栏 720px(设计稿博客系列)
@@ -463,9 +434,25 @@ button.pn-login-back:hover {
   width: 14px;
   height: 14px;
 }
+/* 同类的 antd Button 形态(主题切换按钮/溢出菜单触发器):
+   antd cssinjs 无 layer,需更高特异度对齐导航 pill 规格 */
+button.ant-btn.pn-site-navlink {
+  height: auto;
+  padding: 7px 12px;
+  border: 0;
+  border-radius: var(--radius-sm);
+  background: transparent;
+  font-size: 14px;
+  font-weight: 500;
+  color: var(--muted-foreground);
+}
+button.ant-btn.pn-site-navlink:hover {
+  background: var(--muted);
+  color: var(--foreground);
+}
 /* 博客端溢出菜单触发按钮:<640px 显示(基础规则须在 640px MQ 之前,
    否则同特异性下源码顺序靠后者覆盖 MQ 内的 display:inline-flex) */
-.pn-site-menu-btn {
+button.ant-btn.pn-site-menu-btn {
   display: none;
 }
 .pn-site-main {
@@ -526,7 +513,7 @@ button.pn-login-back:hover {
   .pn-site-navlink.hide-sm {
     display: none;
   }
-  .pn-site-menu-btn {
+  button.ant-btn.pn-site-menu-btn {
     display: inline-flex;
   }
 }
@@ -645,22 +632,28 @@ button.pn-login-back:hover {
   color: var(--muted-foreground);
   font-size: 14px;
 }
-/* 首页分页(对应设计稿 table-foot + pager) */
+/* 首页分页(对应设计稿 table-foot + pager)。
+   总数说明由 Pagination showTotal 承接:total 文本居左、页码居右 */
 .pn-home-pager {
   display: flex;
   align-items: center;
-  justify-content: space-between;
+  justify-content: flex-end;
   gap: 12px;
   margin-top: 40px;
   padding-top: 20px;
   border-top: 1px solid var(--border);
 }
-.pn-home-pager-note {
-  font-size: 12.5px;
+.pn-home-pager ul.ant-pagination {
+  flex: 1;
+  justify-content: space-between;
+}
+.pn-home-pager .ant-pagination-total-text {
+  font-family: var(--font-mono);
+  font-size: 12px;
+  letter-spacing: 0.02em;
   color: var(--muted-foreground);
   white-space: nowrap;
 }
-/* 首页分页器已由 antd Pagination 承接(.pn-home-pager 仅保留布局行) */
 @media (max-width: 640px) {
   .pn-home-content {
     padding-top: 40px;
@@ -957,29 +950,23 @@ button.pn-note-back:hover {
   color: var(--muted-foreground);
   font-style: italic;
 }
-/* 代码块复制按钮 */
-.pn-copy-btn {
+/* 代码块复制按钮(antd Button size=small;悬浮于所属包装 div 时显示) */
+.pn-note-body div:has(> .pn-copy-btn) {
+  position: relative;
+}
+.pn-note-body .pn-copy-btn {
   position: absolute;
   right: 8px;
   top: 8px;
-  padding: 2px 10px;
-  border: 1px solid var(--border);
-  border-radius: var(--radius-sm);
-  background: var(--card);
-  color: var(--muted-foreground);
-  font-size: 12px;
-  line-height: 1.6;
-  cursor: pointer;
+  z-index: 1;
   opacity: 0;
-  transition: opacity 0.15s ease, color 0.15s ease;
+  transition: opacity 0.15s ease;
 }
-.pn-note-body pre:hover .pn-copy-btn,
-.pn-copy-btn:focus-visible {
+.pn-note-body div:has(> .pn-copy-btn):hover .pn-copy-btn,
+.pn-note-body .pn-copy-btn:focus-visible,
+.pn-note-body .pn-copy-btn.is-copied {
   opacity: 1;
 }
-.pn-copy-btn:hover {
-  color: var(--foreground);
-}
 
 /* ============================================================
    标签归档(标签归档.html)
@@ -1009,6 +996,9 @@ button.pn-note-back:hover {
   flex-wrap: wrap;
   gap: 8px;
 }
+.pn-tag-empty {
+  margin-top: 32px;
+}
 .pn-tag-groups {
   margin-top: 48px;
   display: flex;
@@ -1347,32 +1337,23 @@ button.pn-note-back:hover {
   gap: 4px;
   margin-left: auto;
 }
-.pn-admin-iconbtn {
-  position: relative;
-  display: inline-flex;
-  align-items: center;
-  justify-content: center;
+/* 侧栏/topbar 图标按钮(antd Button type=text):28px 方形、muted 前景,
+   hover 沿用 sidebar accent;antd cssinjs 无 layer,需提权 */
+button.ant-btn.pn-admin-iconbtn,
+a.ant-btn.pn-admin-iconbtn {
   width: 28px;
   height: 28px;
   padding: 0;
-  border: 0;
   border-radius: var(--radius-sm);
-  background: transparent;
   color: var(--muted-foreground);
-  text-decoration: none;
-  cursor: pointer;
-  transition: background-color 0.15s ease, color 0.15s ease;
 }
-.pn-admin-iconbtn:hover {
+button.ant-btn.pn-admin-iconbtn:hover:not(:disabled),
+a.ant-btn.pn-admin-iconbtn:hover {
   background: var(--sidebar-accent);
   color: var(--sidebar-accent-foreground);
 }
-.pn-admin-iconbtn svg {
-  width: 15px;
-  height: 15px;
-}
 /* 悬浮提示由 antd Tooltip 承接;侧栏隐藏时的移动端兜底按钮(<768px 显示) */
-.pn-admin-mobile-act {
+button.ant-btn.pn-admin-mobile-act {
   display: none;
 }
 /* 溢出菜单挂载点(面板由 antd Dropdown 渲染,wrapper 仅保留占位语义) */
@@ -1447,39 +1428,15 @@ button.pn-note-back:hover {
   gap: 20px;
   min-width: 0;
 }
-/* 搜索框(topbar 内) */
-.pn-admin-search {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  height: 34px;
+/* 页面级加载占位(antd Spin 居中) */
+.pn-admin-loading {
+  display: grid;
+  place-items: center;
+  min-height: 320px;
+}
+/* 搜索框(topbar 内,antd Input + 前缀图标;<768px 隐藏) */
+.pn-admin-actions .pn-al-search {
   width: 248px;
-  padding: 0 10px;
-  border: 1px solid var(--input);
-  border-radius: var(--radius-sm);
-  background: var(--card);
-  transition: border-color 0.15s ease;
-}
-.pn-admin-search:focus-within {
-  border-color: var(--ring);
-  outline: 2px solid var(--ring);
-  outline-offset: 1px;
-}
-.pn-admin-search svg {
-  width: 14px;
-  height: 14px;
-  flex: none;
-  color: var(--muted-foreground);
-}
-.pn-admin-search input {
-  width: 100%;
-  min-width: 0;
-  padding: 0;
-  border: 0;
-  outline: 0;
-  background: transparent;
-  font-size: 13px;
-  color: var(--foreground);
 }
 /* 移动端 tabbar(<768px) */
 .pn-admin-tabbar {
@@ -1520,13 +1477,13 @@ button.pn-note-back:hover {
     padding-left: 10px;
     padding-right: 10px;
   }
-  .pn-admin-mobile-act {
+  button.ant-btn.pn-admin-mobile-act {
     display: inline-flex;
   }
-  .pn-admin-desktop-act {
+  button.ant-btn.pn-admin-desktop-act {
     display: none;
   }
-  .pn-admin-search {
+  .pn-admin-actions .pn-al-search {
     display: none;
   }
   .pn-admin-content {
@@ -1588,11 +1545,14 @@ button.pn-note-back:hover {
   padding: 12px 16px;
   border-bottom: 1px solid var(--border);
 }
-.pn-al-tab-num {
+/* Segmented 选项内计数徽标(antd Badge count,弱化为 muted 灰) */
+.pn-al-tab-badge {
+  margin-left: 6px;
+}
+.pn-al-tab-badge .ant-badge-count {
+  background: var(--muted-foreground);
+  color: var(--background);
   font-family: var(--font-mono);
-  font-size: 11px;
-  margin-left: 5px;
-  opacity: 0.65;
 }
 .pn-al-table-note {
   font-size: 12px;
@@ -1640,27 +1600,6 @@ button.pn-note-back:hover {
   color: var(--foreground);
   white-space: nowrap;
 }
-.pn-al-status {
-  display: inline-flex;
-  align-items: center;
-  gap: 7px;
-  font-size: 12.5px;
-  font-weight: 500;
-  white-space: nowrap;
-}
-.pn-al-status.pn-al-is-public {
-  color: var(--success-text);
-}
-.pn-al-status.pn-al-is-public .dot {
-  background: var(--success);
-}
-.pn-al-status.pn-al-is-draft {
-  color: var(--muted-foreground);
-}
-.pn-al-status.pn-al-is-draft .dot {
-  background: var(--muted-foreground);
-  opacity: 0.55;
-}
 .pn-al-actions-cell {
   display: flex;
   align-items: center;
@@ -1804,10 +1743,8 @@ button.pn-ae-tool svg {
 .pn-ae-preview .pn-note-body {
   margin-top: 20px;
 }
-.pn-ae-upload-msg {
-  margin: 10px 0 0;
-  font-size: 12px;
-  color: var(--muted-foreground);
+.pn-ae-upload-alert {
+  margin-top: 10px;
 }
 /* 发布设置侧卡 */
 .pn-ae-side {
@@ -1830,20 +1767,6 @@ button.pn-ae-tool svg {
   color: var(--muted-foreground);
   white-space: nowrap;
 }
-.pn-ae-pvalue {
-  display: inline-flex;
-  align-items: center;
-  gap: 7px;
-  color: var(--foreground);
-}
-.pn-ae-pvalue.is-muted {
-  color: var(--muted-foreground);
-}
-.pn-ae-pvalue svg {
-  width: 14px;
-  height: 14px;
-  color: var(--muted-foreground);
-}
 /* 发布日期选择器(size=small) */
 .pn-ae-datepicker {
   flex: none;
@@ -1853,10 +1776,6 @@ button.pn-ae-tool svg {
   font-family: var(--font-mono);
   font-size: 12px;
 }
-.pn-ae-mono {
-  font-family: var(--font-mono);
-  font-size: 12px;
-}
 .pn-ae-pfield {
   display: flex;
   flex-direction: column;
@@ -1924,9 +1843,6 @@ button.pn-ae-tool svg {
   color: var(--foreground);
   white-space: nowrap;
 }
-.pn-at-days-urgent {
-  color: var(--destructive-text);
-}
 .pn-at-actions {
   display: flex;
   align-items: center;
diff --git a/web/src/pages/AdminEdit.tsx b/web/src/pages/AdminEdit.tsx
index 30ae5ae..29b50c6 100644
--- a/web/src/pages/AdminEdit.tsx
+++ b/web/src/pages/AdminEdit.tsx
@@ -6,7 +6,7 @@ import {
   Bold, Code, Eye, EyeOff, Italic, Link2, List, Quote,
   Save, Table, Trash2,
 } from 'lucide-react'
-import { Button, Card, DatePicker, Divider, Input, Select, Switch } from 'antd'
+import { Alert, Badge, Button, Card, DatePicker, Divider, Input, Select, Spin, Switch } from 'antd'
 import { api, ApiError } from '../lib/api'
 import type { NoteItem } from '../lib/api'
 import { invalidatePublic } from '../lib/invalidate'
@@ -72,7 +72,7 @@ export default function AdminEdit() {
   const [errorMsg, setErrorMsg] = useState(null)
   const [slugFieldError, setSlugFieldError] = useState(null)
   const [showPreview, setShowPreview] = useState(false)
-  const [uploadMsg, setUploadMsg] = useState(null)
+  const [uploadMsg, setUploadMsg] = useState<{ kind: 'busy' | 'error'; text: string } | null>(null)
   const dirtyRef = useRef(false)
   const slugTouchedRef = useRef(false)
   const timerRef = useRef | null>(null)
@@ -190,7 +190,7 @@ export default function AdminEdit() {
     return (
       <>
         
-        
加载中…
+
) } @@ -261,16 +261,23 @@ export default function AdminEdit() {
- 编辑器加载中…
}> + }> set('content', v)} - onUploadStart={(name) => setUploadMsg(`上传中:${name}…`)} - onUploadEnd={(err) => setUploadMsg(err ?? null)} + onUploadStart={(name) => setUploadMsg({ kind: 'busy', text: `上传中:${name}…` })} + onUploadEnd={(err) => setUploadMsg(err ? { kind: 'error', text: err } : null)} /> - {uploadMsg &&

{uploadMsg}

} + {uploadMsg && ( + + )} {showPreview && (
@@ -285,12 +292,10 @@ export default function AdminEdit() {
状态 - - {form.status === 'public' ? '公开' : '私有'} - + set('status', checked ? 'public' : 'private')} @@ -355,13 +360,13 @@ export default function AdminEdit() { <> )} diff --git a/web/src/pages/AdminList.tsx b/web/src/pages/AdminList.tsx index 7df27b0..4af7b06 100644 --- a/web/src/pages/AdminList.tsx +++ b/web/src/pages/AdminList.tsx @@ -2,7 +2,7 @@ import { useMemo, useState } from 'react' import { Link, useNavigate } from 'react-router' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { CirclePlus, Eye, EyeOff, Pencil, Pin, Search, Trash2 } from 'lucide-react' -import { Button, Card, Input, Modal, Segmented, Table, Tag } from 'antd' +import { Badge, Button, Card, Empty, Input, Modal, Segmented, Table, Tag } from 'antd' import type { TableProps } from 'antd' import { api } from '../lib/api' import type { NoteItem } from '../lib/api' @@ -122,14 +122,9 @@ export default function AdminList() { { title: '状态', key: 'status', - render: (_, n) => { - const isPublic = n.status === 'public' - return ( - - {isPublic ? '已发布' : '私有'} - - ) - }, + render: (_, n) => ( + + ), }, { title: '操作', @@ -156,7 +151,7 @@ export default function AdminList() { />
- {isLoading ? ( -
加载中…
- ) : visible.length === 0 ? ( -
- {items.length === 0 ? '还没有笔记,点击「新建笔记」开始' : '没有符合筛选条件的笔记'} -
- ) : ( - (n.status === 'public' ? '' : 'pn-al-is-draft')} - /> - )} +
(n.status === 'public' ? '' : 'pn-al-is-draft')} + locale={{ + emptyText: ( + + ), + }} + />
共 {data?.total ?? 0} 篇 · 显示 {visible.length} 篇 diff --git a/web/src/pages/AdminTrash.tsx b/web/src/pages/AdminTrash.tsx index 547993d..7666da0 100644 --- a/web/src/pages/AdminTrash.tsx +++ b/web/src/pages/AdminTrash.tsx @@ -1,6 +1,6 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { RotateCcw, Trash2 } from 'lucide-react' -import { Alert, App, Button, Card, Table } from 'antd' +import { Alert, App, Button, Card, Empty, Table, Tag } from 'antd' import type { TableProps } from 'antd' import { api } from '../lib/api' import type { NoteItem } from '../lib/api' @@ -77,7 +77,7 @@ export default function AdminTrash() { key: 'days', render: (_, n) => { const left = n.deleted_at ? daysRemaining(n.deleted_at) : 0 - return {left} 天 + return left <= 3 ? {left} 天 : {left} 天 }, }, { @@ -122,20 +122,18 @@ export default function AdminTrash() { /> - {isLoading ? ( -
加载中…
- ) : items.length === 0 ? ( -
回收站是空的
- ) : ( -
- )} +
, + }} + />
共 {data?.total ?? 0} 篇已删除笔记 diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx index c21cb09..f4c42bd 100644 --- a/web/src/pages/Home.tsx +++ b/web/src/pages/Home.tsx @@ -2,7 +2,7 @@ import { useState } from 'react' import { Link } from 'react-router' import { useQuery } from '@tanstack/react-query' import { ArrowRight, Pin } from 'lucide-react' -import { Pagination, Tag } from 'antd' +import { Empty, Flex, Pagination, Skeleton, Tag } from 'antd' import { api } from '../lib/api' import type { NoteItem, NoteList } from '../lib/api' import { useDocumentTitle } from '../features/site' @@ -69,9 +69,13 @@ export default function Home() {
{isLoading ? ( -

加载中…

+ + {[0, 1, 2].map((i) => ( + + ))} + ) : !data || data.items.length === 0 ? ( -

还没有公开的笔记

+ ) : ( data.items.map((n) => ) )} @@ -79,15 +83,13 @@ export default function Home() { {totalPages > 1 && ( diff --git a/web/src/pages/Note.tsx b/web/src/pages/Note.tsx index 9980f0c..9569051 100644 --- a/web/src/pages/Note.tsx +++ b/web/src/pages/Note.tsx @@ -1,7 +1,7 @@ import { Link, useNavigate, useParams } from 'react-router' import { useQuery } from '@tanstack/react-query' import { ArrowLeft, ArrowRight, Clock, Eye } from 'lucide-react' -import { Alert, Button, Card, Tag } from 'antd' +import { Alert, Button, Card, Empty, Skeleton, Tag } from 'antd' import { api } from '../lib/api' import type { NoteDetail } from '../lib/api' import { useAuth } from '../lib/auth' @@ -20,17 +20,28 @@ export default function Note() { }) useDocumentTitle(note?.title) - if (isLoading) return

加载中…

+ if (isLoading) { + return ( +
+ +
+ ) + } if (error || !note) { return ( -
-

笔记不存在或未公开

-

- -

-
+
+ ) } diff --git a/web/src/pages/TagPage.tsx b/web/src/pages/TagPage.tsx index c64c3c6..434c13b 100644 --- a/web/src/pages/TagPage.tsx +++ b/web/src/pages/TagPage.tsx @@ -1,7 +1,7 @@ import { Link, useNavigate, useParams } from 'react-router' import { useQuery } from '@tanstack/react-query' import { ArrowRight, Tag } from 'lucide-react' -import { Tag as AntTag } from 'antd' +import { Empty, Skeleton, Spin, Tag as AntTag } from 'antd' import { api } from '../lib/api' import type { NoteList, TagCount } from '../lib/api' import { useDocumentTitle } from '../features/site' @@ -53,10 +53,12 @@ export default function TagPage() { aria-label="全部标签" /> {!tagsData && ( - 加载中… +
)} {tagsData && tagsData.tags.length === 0 && ( - 还没有标签 +
+ +
)} {tag === undefined && tagsData && ( @@ -69,11 +71,11 @@ export default function TagPage() {

{tag}

{isLoading ? ( -

加载中…

+ ) : error ? (

加载失败,请稍后重试

) : !data || data.items.length === 0 ? ( -

该标签下暂无公开笔记

+ ) : ( data.items.map((n) => ( diff --git a/web/src/theme/shadcnTheme.ts b/web/src/theme/shadcnTheme.ts index 6173241..c622c77 100644 --- a/web/src/theme/shadcnTheme.ts +++ b/web/src/theme/shadcnTheme.ts @@ -340,7 +340,8 @@ const useShadcnTheme = (dark: boolean) => { (dark ? styles.buttonPrimaryDark : styles.buttonPrimaryLight), (props as { type?: string }).type === 'default' && (dark ? styles.buttonDefaultDark : styles.buttonDefaultLight), - (props as { danger?: boolean }).danger && + (props as { danger?: boolean; type?: string }).danger && + (props as { type?: string }).type !== 'text' && (dark ? styles.buttonDangerDark : styles.buttonDangerLight), ), }),