Files
Arcrun/landing/app/mira/mira.css
T
Leo 8d4c3a3464 feat(mira): P0 河道完善 3 task — Mira 頭像 / @mira 選擇性回覆 / 編輯器 popup
對應 tasks.md backlog #5a / #5b / #5c(leo 2026-05-16 P0),design.md §3.6.5。

#5a Mira 發文獨立頭像
- 新 MiraAvatar 元件(紫色漸層圓 + 🤖 emoji)
- isMiraSource() 判斷 post 來源是 leo(km-writer-direct/logseq/mobile/web/tg/rss)
  還是 mira(ai-* / mira-* / 其他 test sources)
- PostCard header:showMira ? Mira 頭像 + 名「Mira」 : leo 頭像 + leo 名

#5b @mira 選擇性回覆(撤回每篇 auto-reply)
- 新 hasMiraMention() regex:偵測文字含 @mira(前後可有標點)
- PostComposer / BlockEditor / ReplyLine 三處 submit:只有 @mira 時 triggerAiReply
- triggerAiReply prompt 加 topic 抽取(@mira 後第一段到標點)+ scope hint
- wiki_synthesis trigger 跟 @mira 無關,每篇都跑(KB 副本同步)
- 不擋手動筆記(leo 隨手寫不需要 mira 每篇都回)

#5c 編輯器 popup 放大
- composer 加 ⇱ 放大按鈕 → 切到 fullscreen overlay popup
- popup 含大 textarea + 同 markdown toolbar + 同 submit 邏輯
- ⌘+Enter 發布、Esc 收起、外點 backdrop 收起
- 對應 leo「寫長文 textarea 太小」需求

CSS 加 .mira-avatar-mira / .mira-composer-popup-* 系列。
TS check pass。
2026-05-16 10:35:32 +08:00

862 lines
19 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Mira — 社群貼文式 KM 河道
* 視覺參考:Facebook / X / LinkedIn
* Scope 在 .mira-app 容器內,避免汙染 landing 的 Tailwind 樣式
*/
.mira-app {
/* Surfaces */
--mira-bg-0: #0e0e0d;
--mira-bg-1: #1a1a18;
--mira-bg-2: #252320;
--mira-bg-3: #302d28;
--mira-line: #2e2c27;
--mira-line-soft: #1f1d1a;
/* Text — 高對比 */
--mira-text-1: #f0eee8;
--mira-text-2: #c9c4b8;
--mira-text-3: #9c968a;
--mira-text-4: #6c685e;
--mira-accent: oklch(0.78 0.13 75);
--mira-accent-soft: oklch(0.78 0.13 75 / 0.16);
--mira-accent-line: oklch(0.78 0.13 75 / 0.4);
--mira-conflict: oklch(0.72 0.14 30);
--mira-conflict-soft: oklch(0.72 0.14 30 / 0.13);
--mira-src-logseq: oklch(0.75 0.08 250);
--mira-src-mobile: oklch(0.78 0.07 160);
--mira-src-tg: oklch(0.78 0.08 220);
--mira-src-rss: oklch(0.78 0.08 30);
--mira-src-ai: oklch(0.82 0.10 95);
--mira-radius-sm: 6px;
--mira-radius: 10px;
--mira-radius-lg: 14px;
--mira-font-zh: "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, sans-serif;
--mira-font-en: "Inter Tight", "Helvetica Neue", Helvetica, Arial, sans-serif;
--mira-font-mono: "JetBrains Mono", "SF Mono", Menlo, monospace;
background: var(--mira-bg-0);
color: var(--mira-text-1);
font-family: var(--mira-font-zh);
/* 不啟用 palt:保留中文標點全寬,避免標點看起來只有半寬 */
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
letter-spacing: 0.01em;
line-height: 1.65;
min-height: calc(100vh - 73px);
}
.mira-app .mira-num,
.mira-app .mira-en {
font-family: var(--mira-font-en);
letter-spacing: 0;
}
.mira-app .mira-content {
max-width: 920px;
margin: 0 auto;
padding: 24px 16px 80px;
}
@media (max-width: 640px) {
.mira-app .mira-content {
padding: 12px 0 60px;
}
}
/* ── card 卡片 ── */
.mira-app .mira-card {
background: var(--mira-bg-1);
border: 1px solid var(--mira-line);
border-radius: var(--mira-radius);
margin-bottom: 12px;
/* 不要 overflow: hidden — 會 clip ⋮ menu dropdown */
position: relative;
}
@media (max-width: 640px) {
.mira-app .mira-card {
border-radius: 0;
border-left: none;
border-right: none;
margin-bottom: 8px;
}
}
/* ── composer 寫貼文 ── */
.mira-app .mira-composer-card {
padding: 14px 16px;
}
.mira-app .mira-composer-row {
display: flex;
gap: 12px;
align-items: flex-start;
}
.mira-app .mira-composer-textarea {
flex: 1;
min-width: 0;
background: transparent;
border: none;
outline: none;
resize: none;
font-family: inherit;
font-size: 16px;
line-height: 1.65;
color: var(--mira-text-1);
padding: 8px 0;
}
.mira-app .mira-composer-textarea::placeholder {
color: var(--mira-text-3);
}
.mira-app .mira-composer-actions {
display: flex;
align-items: center;
gap: 10px;
padding-top: 10px;
margin-top: 8px;
border-top: 1px solid var(--mira-line-soft);
margin-left: 52px;
flex-wrap: wrap;
}
/* ── avatar ── */
.mira-app .mira-avatar {
border-radius: 50%;
flex-shrink: 0;
background: var(--mira-bg-2);
object-fit: cover;
}
.mira-app .mira-avatar-fallback {
display: grid;
place-items: center;
background: linear-gradient(135deg, var(--mira-bg-2), var(--mira-bg-3));
color: var(--mira-text-1);
font-weight: 600;
font-family: var(--mira-font-en);
}
/* Mira 自有頭像 — 跟 leo 區分(紫色漸層 + 機器人 emoji) */
.mira-app .mira-avatar-mira {
display: grid;
place-items: center;
background: linear-gradient(135deg, oklch(0.45 0.15 280), oklch(0.55 0.18 300));
color: #fff;
border-radius: 50%;
flex-shrink: 0;
/* emoji 本身有色彩,背景僅當邊框襯托 */
line-height: 1;
}
/* ── post 貼文 ── */
.mira-app .mira-post {
display: flex;
flex-direction: column;
}
.mira-app .mira-post-header {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px 10px;
}
.mira-app .mira-post-author {
flex: 1;
min-width: 0;
}
.mira-app .mira-post-name {
font-size: 14.5px;
font-weight: 600;
color: var(--mira-text-1);
line-height: 1.3;
}
.mira-app .mira-post-time {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--mira-text-3);
font-family: var(--mira-font-en);
margin-top: 2px;
}
/* ── post body 內文 ── */
.mira-app .mira-post-body {
padding: 0 16px 12px;
}
.mira-app .mira-post-content {
font-size: 15px;
line-height: 1.7;
color: var(--mira-text-1);
word-break: break-word;
white-space: normal;
}
.mira-app .mira-post-content-full {
/* 展開模式:顯示每個 sub-block 為獨立行,可編輯 */
font-size: 14.5px;
}
/* react-markdown render 樣式 */
.mira-app .mira-md > *:first-child { margin-top: 0; }
.mira-app .mira-md > *:last-child { margin-bottom: 0; }
.mira-app .mira-md p {
margin: 0 0 8px;
line-height: 1.7;
}
.mira-app .mira-md h1,
.mira-app .mira-md h2,
.mira-app .mira-md h3,
.mira-app .mira-md h4,
.mira-app .mira-md h5,
.mira-app .mira-md h6 {
margin: 14px 0 6px;
font-weight: 700;
color: var(--mira-text-1);
line-height: 1.3;
}
.mira-app .mira-md h1 { font-size: 1.5em; }
.mira-app .mira-md h2 { font-size: 1.3em; }
.mira-app .mira-md h3 { font-size: 1.15em; font-weight: 600; }
.mira-app .mira-md h4,
.mira-app .mira-md h5,
.mira-app .mira-md h6 { font-size: 1em; font-weight: 600; }
.mira-app .mira-md ul,
.mira-app .mira-md ol {
margin: 4px 0 8px;
padding-left: 22px;
}
.mira-app .mira-md ul {
list-style: disc;
}
.mira-app .mira-md ul ul {
list-style: circle;
}
.mira-app .mira-md ul ul ul {
list-style: square;
}
.mira-app .mira-md ol {
list-style: decimal;
}
.mira-app .mira-md ul ul,
.mira-app .mira-md ul ol,
.mira-app .mira-md ol ul,
.mira-app .mira-md ol ol {
margin: 4px 0;
}
.mira-app .mira-md li {
margin: 2px 0;
line-height: 1.7;
}
/* GFM task list 的 li 不顯示 bulletcheckbox 取代)*/
.mira-app .mira-md li:has(> input[type="checkbox"]) {
list-style: none;
margin-left: -22px;
}
.mira-app .mira-md li > p {
margin: 0;
}
.mira-app .mira-md blockquote {
margin: 8px 0;
padding: 4px 12px;
border-left: 3px solid var(--mira-line);
color: var(--mira-text-2);
background: var(--mira-bg-2);
border-radius: 0 4px 4px 0;
}
.mira-app .mira-md blockquote p:last-child { margin-bottom: 0; }
.mira-app .mira-md hr {
border: none;
border-top: 1px solid var(--mira-line);
margin: 16px 0;
}
.mira-app .mira-md code {
font-family: var(--mira-font-mono);
font-size: 0.9em;
background: var(--mira-bg-2);
padding: 1px 5px;
border-radius: 4px;
border: 1px solid var(--mira-line-soft);
}
.mira-app .mira-md pre {
margin: 8px 0;
padding: 12px;
background: var(--mira-bg-2);
border: 1px solid var(--mira-line-soft);
border-radius: 6px;
overflow-x: auto;
}
.mira-app .mira-md pre code {
background: transparent;
border: none;
padding: 0;
font-size: 0.85em;
line-height: 1.6;
}
.mira-app .mira-md table {
border-collapse: collapse;
margin: 8px 0;
width: 100%;
font-size: 0.95em;
}
.mira-app .mira-md th,
.mira-app .mira-md td {
border: 1px solid var(--mira-line);
padding: 6px 10px;
text-align: left;
}
.mira-app .mira-md th {
background: var(--mira-bg-2);
color: var(--mira-text-1);
font-weight: 600;
}
.mira-app .mira-md tr:nth-child(even) {
background: rgba(255, 255, 255, 0.02);
}
.mira-app .mira-md strong { color: var(--mira-text-1); font-weight: 700; }
.mira-app .mira-md em { font-style: italic; }
.mira-app .mira-md del { color: var(--mira-text-3); }
/* GFM task list */
.mira-app .mira-md input[type="checkbox"] {
margin-right: 6px;
vertical-align: middle;
}
/* ── show more ── */
.mira-app .mira-show-more {
background: transparent;
border: none;
color: var(--mira-accent);
font-size: 14px;
cursor: pointer;
padding: 4px 0;
margin-top: 4px;
font-family: inherit;
}
.mira-app .mira-show-more:hover {
text-decoration: underline;
}
/* ── footer 互動列 ── */
.mira-app .mira-post-footer {
display: flex;
align-items: center;
border-top: 1px solid var(--mira-line-soft);
padding: 4px 8px;
margin: 0 8px;
}
.mira-app .mira-action-btn {
background: transparent;
border: none;
color: var(--mira-text-2);
font-size: 13.5px;
font-family: inherit;
padding: 8px 14px;
cursor: pointer;
border-radius: 6px;
display: flex;
align-items: center;
gap: 6px;
transition: background 0.12s, color 0.12s;
}
.mira-app .mira-action-btn:hover,
.mira-app .mira-action-btn:active {
background: var(--mira-bg-2);
color: var(--mira-text-1);
}
.mira-app .mira-action-count {
font-size: 12px;
color: var(--mira-text-3);
font-family: var(--mira-font-en);
}
/* ── replies 對整篇的留言 ── */
.mira-app .mira-post-replies {
background: var(--mira-bg-0);
padding: 8px 16px;
border-top: 1px solid var(--mira-line-soft);
display: flex;
flex-direction: column;
gap: 6px;
}
.mira-app .mira-show-replies {
background: transparent;
border: none;
color: var(--mira-text-2);
font-size: 13px;
cursor: pointer;
padding: 6px 4px;
text-align: left;
font-family: inherit;
font-weight: 500;
}
.mira-app .mira-show-replies:hover {
text-decoration: underline;
}
.mira-app .mira-reply-composer {
display: flex;
gap: 10px;
padding: 10px 16px;
border-top: 1px solid var(--mira-line-soft);
background: var(--mira-bg-0);
align-items: flex-start;
}
/* ── reply line ── */
.mira-app .mira-reply-line {
margin-bottom: 6px;
padding: 8px 10px;
background: var(--mira-bg-1);
border-radius: 16px;
display: flex;
align-items: flex-start;
gap: 8px;
position: relative;
}
.mira-app .mira-reply-line.is-ai {
background: var(--mira-accent-soft);
}
/* reply line 內的 ⋮ 永遠顯示(取代 hover only*/
.mira-app .mira-reply-line .mira-menu-wrap {
opacity: 1;
}
.mira-app .mira-reply-icon {
font-size: 13px;
color: var(--mira-text-2);
flex-shrink: 0;
margin-top: 2px;
}
.mira-app .mira-reply-line.is-ai .mira-reply-icon {
color: var(--mira-accent);
}
.mira-app .mira-reply-content {
font-size: 13.5px;
line-height: 1.6;
color: var(--mira-text-1);
word-break: break-word;
white-space: normal;
}
.mira-app .mira-reply-nested {
margin-left: 20px;
margin-top: 4px;
padding-left: 8px;
border-left: 2px solid var(--mira-line-soft);
}
/* ── source tag ── */
.mira-app .src-tag {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 1px 7px;
border-radius: 999px;
font-size: 11px;
font-family: var(--mira-font-en);
letter-spacing: 0.04em;
background: var(--mira-bg-2);
color: var(--mira-text-2);
border: 1px solid var(--mira-line);
}
.mira-app .src-dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: var(--mira-text-3);
}
.mira-app .src-tag.logseq .src-dot { background: var(--mira-src-logseq); }
.mira-app .src-tag.mobile .src-dot { background: var(--mira-src-mobile); }
.mira-app .src-tag.tg .src-dot { background: var(--mira-src-tg); }
.mira-app .src-tag.rss .src-dot { background: var(--mira-src-rss); }
.mira-app .src-tag.ai .src-dot { background: var(--mira-src-ai); }
/* ── wiki link ── */
.mira-app .wiki-link {
color: var(--mira-accent);
cursor: pointer;
text-decoration: none;
border-bottom: 1px dashed var(--mira-accent-line);
padding-bottom: 1px;
}
.mira-app .wiki-link:hover {
background: var(--mira-accent-soft);
}
/* ── empty state ── */
.mira-app .empty-state {
text-align: center;
padding: 80px 20px;
color: var(--mira-text-2);
font-size: 13px;
}
/* ── icon button ── */
.mira-app .mira-icon-btn {
width: 32px;
height: 32px;
display: grid;
place-items: center;
border-radius: 50%;
cursor: pointer;
color: var(--mira-text-2);
background: transparent;
border: none;
font-size: 14px;
line-height: 1;
padding: 0;
transition: background 0.12s, color 0.12s;
flex-shrink: 0;
}
.mira-app .mira-icon-btn:hover,
.mira-app .mira-icon-btn:active {
background: var(--mira-bg-2);
color: var(--mira-text-1);
}
.mira-app .mira-icon-btn-vertical {
font-size: 20px;
font-weight: 700;
letter-spacing: 0;
}
/* ── ⋮ menu (dropdown) ── */
.mira-app .mira-menu-wrap {
position: relative;
}
.mira-app .mira-menu {
position: absolute;
right: 0;
top: calc(100% + 4px);
min-width: 160px;
background: var(--mira-bg-1);
border: 1px solid var(--mira-line);
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
padding: 4px;
z-index: 10;
display: flex;
flex-direction: column;
gap: 1px;
}
.mira-app .mira-menu-item {
background: transparent;
border: none;
text-align: left;
padding: 10px 14px;
border-radius: 5px;
color: var(--mira-text-1);
font-size: 14px;
cursor: pointer;
font-family: inherit;
transition: background 0.12s;
}
.mira-app .mira-menu-item:hover,
.mira-app .mira-menu-item:active {
background: var(--mira-bg-2);
}
.mira-app .mira-menu-item.danger {
color: var(--mira-conflict);
}
.mira-app .mira-menu-item.danger:hover {
background: var(--mira-conflict-soft);
}
/* ── block-lineFullContent 模式)── */
.mira-app .mira-block-line {
position: relative;
}
.mira-app .mira-block-line .mira-menu-wrap {
opacity: 0;
transition: opacity 0.12s;
}
.mira-app .mira-block-line:hover .mira-menu-wrap {
opacity: 1;
}
@media (hover: none) {
/* 觸控裝置一律顯示 ⋮ */
.mira-app .mira-block-line .mira-menu-wrap {
opacity: 1;
}
}
.mira-app .mira-menu-wrap:has(.mira-menu) { opacity: 1 !important; }
/* ── edit textarea ── */
.mira-app .mira-edit-textarea {
width: 100%;
background: var(--mira-bg-0);
border: 1px solid var(--mira-accent-line);
border-radius: 8px;
padding: 10px 12px;
font-family: inherit;
font-size: 14px;
line-height: 1.7;
color: var(--mira-text-1);
resize: vertical;
outline: none;
}
.mira-app .mira-edit-textarea:focus {
border-color: var(--mira-accent);
}
.mira-app .mira-edit-textarea::placeholder {
color: var(--mira-text-3);
}
.mira-app .mira-edit-actions {
display: flex;
align-items: center;
gap: 8px;
margin-top: 6px;
flex-wrap: wrap;
}
/* ── markdown toolbar ── */
.mira-app .mira-md-toolbar {
display: flex;
align-items: center;
gap: 4px;
padding: 6px 8px;
background: var(--mira-bg-2);
border: 1px solid var(--mira-line);
border-bottom: none;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
flex-wrap: wrap;
}
/* compact 模式:給 PostComposer 的 actions 列 inline 用 */
.mira-app .mira-md-toolbar.compact {
padding: 0;
background: transparent;
border: none;
gap: 2px;
}
.mira-app .mira-md-btn {
background: transparent;
border: none;
width: 28px;
height: 28px;
display: grid;
place-items: center;
border-radius: 5px;
color: var(--mira-text-2);
cursor: pointer;
font-size: 13px;
font-family: inherit;
transition: background 0.12s, color 0.12s;
padding: 0;
line-height: 1;
}
.mira-app .mira-md-btn:hover,
.mira-app .mira-md-btn:active {
background: var(--mira-bg-3);
color: var(--mira-text-1);
}
.mira-app .mira-md-btn em {
font-style: italic;
font-family: serif;
}
.mira-app .mira-md-hint {
margin-left: auto;
font-size: 11px;
color: var(--mira-text-3);
font-family: var(--mira-font-en);
}
/* toolbar 之後的 textarea 接續成一塊 */
.mira-app .mira-md-toolbar + .mira-edit-textarea {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-top: none;
}
/* ── kbd 提示 ── */
.mira-app .mira-kbd {
font-size: 11px;
color: var(--mira-text-3);
font-family: var(--mira-font-en);
}
/* ── messages ── */
.mira-app .mira-msg-error {
font-size: 12px;
color: var(--mira-conflict);
}
.mira-app .mira-error {
padding: 16px;
color: var(--mira-conflict);
font-size: 14px;
}
/* ── buttons ── */
.mira-app .mira-btn-primary {
background: var(--mira-accent);
border: none;
color: var(--mira-bg-0);
font-size: 13px;
padding: 8px 18px;
border-radius: 999px;
cursor: pointer;
font-weight: 600;
font-family: inherit;
transition: opacity 0.12s, background 0.12s;
}
.mira-app .mira-btn-primary:hover {
opacity: 0.9;
}
.mira-app .mira-btn-primary:disabled,
.mira-app .mira-btn-primary.disabled {
background: var(--mira-bg-3);
color: var(--mira-text-3);
cursor: not-allowed;
opacity: 1;
}
.mira-app .mira-btn-ghost {
background: transparent;
border: 1px solid var(--mira-line);
color: var(--mira-text-2);
font-size: 12px;
padding: 6px 14px;
border-radius: 999px;
cursor: pointer;
font-family: inherit;
}
.mira-app .mira-btn-ghost:hover {
background: var(--mira-bg-2);
color: var(--mira-text-1);
}
/* ── Mira 思考中(AI reply pending)── */
.mira-app .mira-thinking {
opacity: 0.7;
}
.mira-app .mira-thinking-dots::after {
content: '⋯';
display: inline-block;
animation: mira-think-dots 1.4s infinite;
}
@keyframes mira-think-dots {
0%, 100% { opacity: 0.3; }
50% { opacity: 1; }
}
/* ── skeleton loader ── */
.mira-app .mira-skel {
height: 60px;
background: linear-gradient(
90deg,
var(--mira-bg-1) 0%,
var(--mira-bg-2) 50%,
var(--mira-bg-1) 100%
);
background-size: 200% 100%;
animation: mira-skel-shimmer 1.4s ease-in-out infinite;
border-radius: 6px;
}
@keyframes mira-skel-shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* ── rel time ── */
.mira-app .mira-rel-time {
cursor: default;
}
/* ── Wiki detail (7B.3g 樹狀渲染) ── */
/* .mira-md 已在 §190+ 定義整套 markdown 樣式(河道+wiki 共用),這裡只加 wiki 細節頁的「不破版」保護 */
.mira-app .mira-wiki-detail {
overflow-wrap: break-word;
word-break: break-word;
}
/* 防止長 cypher binding 字串 / URL 撐爆右邊界 */
.mira-app .mira-wiki-detail .mira-md li,
.mira-app .mira-wiki-detail .mira-md p {
overflow-wrap: break-word;
word-break: break-word;
}
/* wiki h2/h3 加底線分隔,更像文章 */
.mira-app .mira-wiki-detail .mira-md h2 {
border-bottom: 1px solid var(--mira-line-soft);
padding-bottom: 4px;
}
/* ── Composer popup (P0 #5c 編輯器放大) ── */
.mira-app .mira-composer-expand {
font-size: 18px;
padding: 0 8px;
cursor: pointer;
color: var(--mira-text-3);
}
.mira-app .mira-composer-expand:hover {
color: var(--mira-text-1);
}
/* backdrop 蓋全頁 + 居中 */
.mira-composer-popup-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 1000;
display: grid;
place-items: center;
padding: 16px;
}
/* popup card 大編輯區 */
.mira-composer-popup {
background: var(--mira-bg-1);
border: 1px solid var(--mira-line);
border-radius: var(--mira-radius-lg);
width: min(800px, 100%);
max-height: 90vh;
display: flex;
flex-direction: column;
overflow: hidden;
font-family: var(--mira-font-zh);
color: var(--mira-text-1);
}
.mira-composer-popup-header {
display: flex;
align-items: center;
gap: 10px;
padding: 14px 16px;
border-bottom: 1px solid var(--mira-line);
}
.mira-composer-popup-title {
font-weight: 600;
font-size: 15px;
}
.mira-composer-popup-textarea {
flex: 1;
min-height: 320px;
padding: 16px;
background: transparent;
color: var(--mira-text-1);
border: none;
outline: none;
resize: none;
font-family: inherit;
font-size: 15px;
line-height: 1.7;
}
.mira-composer-popup-actions {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
border-top: 1px solid var(--mira-line);
background: var(--mira-bg-0);
}