Public Access
feat: implement overflow menu for exam actions in MyExams component
This commit is contained in:
1 parent
26041cba1e
commit
a40bfa7838
2 files changed
+273
-154
No files matched your search
+175
-154
@@ -33,7 +33,6 @@ export default function MyExams({ onLoadExam }: Readonly<Props>) {
|
|||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
const [deleteConfirm, setDeleteConfirm] = useState<number | null>(null)
|
const [deleteConfirm, setDeleteConfirm] = useState<number | null>(null)
|
||||||
const [startingId, setStartingId] = useState<number | null>(null)
|
const [startingId, setStartingId] = useState<number | null>(null)
|
||||||
const [shareOpenId, setShareOpenId] = useState<number | null>(null)
|
|
||||||
const [sharingId, setSharingId] = useState<number | null>(null)
|
const [sharingId, setSharingId] = useState<number | null>(null)
|
||||||
const [duplicatingId, setDuplicatingId] = useState<number | null>(null)
|
const [duplicatingId, setDuplicatingId] = useState<number | null>(null)
|
||||||
const [exportingId, setExportingId] = useState<number | null>(null)
|
const [exportingId, setExportingId] = useState<number | null>(null)
|
||||||
@@ -42,8 +41,12 @@ export default function MyExams({ onLoadExam }: Readonly<Props>) {
|
|||||||
const [showNewCollection, setShowNewCollection] = useState(false)
|
const [showNewCollection, setShowNewCollection] = useState(false)
|
||||||
const [newCollectionName, setNewCollectionName] = useState('')
|
const [newCollectionName, setNewCollectionName] = useState('')
|
||||||
const [creatingCollection, setCreatingCollection] = useState(false)
|
const [creatingCollection, setCreatingCollection] = useState(false)
|
||||||
const [moveMenuExamId, setMoveMenuExamId] = useState<number | null>(null)
|
|
||||||
const [movingExamId, setMovingExamId] = useState<number | null>(null)
|
const [movingExamId, setMovingExamId] = useState<number | null>(null)
|
||||||
|
const [menuOpenId, setMenuOpenId] = useState<number | null>(null)
|
||||||
|
const [menuSection, setMenuSection] = useState<'main' | 'move' | 'share'>('main')
|
||||||
|
|
||||||
|
const closeMenu = () => { setMenuOpenId(null); setMenuSection('main') }
|
||||||
|
const openMenu = (id: number) => { setMenuOpenId(id); setMenuSection('main') }
|
||||||
const [editingCollectionId, setEditingCollectionId] = useState<number | null>(null)
|
const [editingCollectionId, setEditingCollectionId] = useState<number | null>(null)
|
||||||
const [editingCollectionName, setEditingCollectionName] = useState('')
|
const [editingCollectionName, setEditingCollectionName] = useState('')
|
||||||
const [deleteCollectionId, setDeleteCollectionId] = useState<number | null>(null)
|
const [deleteCollectionId, setDeleteCollectionId] = useState<number | null>(null)
|
||||||
@@ -105,7 +108,7 @@ export default function MyExams({ onLoadExam }: Readonly<Props>) {
|
|||||||
const res = await examApi.shareExam(id)
|
const res = await examApi.shareExam(id)
|
||||||
const url = `${window.location.origin}/share/${res.shareToken}`
|
const url = `${window.location.origin}/share/${res.shareToken}`
|
||||||
await navigator.clipboard.writeText(url)
|
await navigator.clipboard.writeText(url)
|
||||||
setShareOpenId(null)
|
closeMenu()
|
||||||
setExams((prev) => prev.map((e) => (e.id === id ? { ...e, share_token: res.shareToken } : e)))
|
setExams((prev) => prev.map((e) => (e.id === id ? { ...e, share_token: res.shareToken } : e)))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError((e as Error).message)
|
setError((e as Error).message)
|
||||||
@@ -117,7 +120,7 @@ export default function MyExams({ onLoadExam }: Readonly<Props>) {
|
|||||||
const handleUnshare = async (id: number) => {
|
const handleUnshare = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
await examApi.unshareExam(id)
|
await examApi.unshareExam(id)
|
||||||
setShareOpenId(null)
|
closeMenu()
|
||||||
setExams((prev) => prev.map((e) => (e.id === id ? { ...e, share_token: null } : e)))
|
setExams((prev) => prev.map((e) => (e.id === id ? { ...e, share_token: null } : e)))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError((e as Error).message)
|
setError((e as Error).message)
|
||||||
@@ -186,7 +189,7 @@ export default function MyExams({ onLoadExam }: Readonly<Props>) {
|
|||||||
setMovingExamId(examId)
|
setMovingExamId(examId)
|
||||||
try {
|
try {
|
||||||
await collectionApi.moveExamToCollection(examId, collectionId)
|
await collectionApi.moveExamToCollection(examId, collectionId)
|
||||||
setMoveMenuExamId(null)
|
closeMenu()
|
||||||
setExams((prev) => prev.map((e) => e.id === examId ? { ...e, collection_id: collectionId } : e))
|
setExams((prev) => prev.map((e) => e.id === examId ? { ...e, collection_id: collectionId } : e))
|
||||||
setCollections((prev) => prev.map((c) => {
|
setCollections((prev) => prev.map((c) => {
|
||||||
if (collectionId !== null && c.id === collectionId) return { ...c, exam_count: c.exam_count + 1 }
|
if (collectionId !== null && c.id === collectionId) return { ...c, exam_count: c.exam_count + 1 }
|
||||||
@@ -633,149 +636,11 @@ export default function MyExams({ onLoadExam }: Readonly<Props>) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="workspace-card-actions">
|
<div className="workspace-card-actions">
|
||||||
<button
|
|
||||||
className="btn btn-primary btn-sm"
|
|
||||||
onClick={() => void startExam(exam.id)}
|
|
||||||
disabled={startingId === exam.id}
|
|
||||||
>
|
|
||||||
{startingId === exam.id ? t('common.loading') : t('workspace.takeExam')}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="btn btn-sm"
|
|
||||||
onClick={() => navigate(`/exam-editor/${exam.id}`)}
|
|
||||||
disabled={startingId === exam.id}
|
|
||||||
>
|
|
||||||
{t('common.edit')}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="btn btn-sm"
|
|
||||||
onClick={() => void handleDuplicate(exam.id)}
|
|
||||||
disabled={duplicatingId === exam.id}
|
|
||||||
title={t('workspace.duplicate')}
|
|
||||||
>
|
|
||||||
{duplicatingId === exam.id ? t('common.loading') : t('workspace.duplicate')}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="btn btn-sm"
|
|
||||||
onClick={() => void handleExport(exam.id, exam.title)}
|
|
||||||
disabled={exportingId === exam.id}
|
|
||||||
title={t('workspace.export')}
|
|
||||||
>
|
|
||||||
{exportingId === exam.id ? t('common.loading') : '↓'}
|
|
||||||
</button>
|
|
||||||
{/* Move to collection dropdown */}
|
|
||||||
<div style={{ position: 'relative' }}>
|
|
||||||
<button
|
|
||||||
className="btn btn-sm"
|
|
||||||
onClick={() => setMoveMenuExamId((id) => (id === exam.id ? null : exam.id))}
|
|
||||||
disabled={movingExamId === exam.id}
|
|
||||||
title={t('workspace.moveTo')}
|
|
||||||
>
|
|
||||||
{movingExamId === exam.id ? t('common.loading') : '▤'}
|
|
||||||
</button>
|
|
||||||
{moveMenuExamId === exam.id && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
right: 0,
|
|
||||||
top: 'calc(100% + 4px)',
|
|
||||||
zIndex: 10,
|
|
||||||
minWidth: 180,
|
|
||||||
background: 'var(--paper)',
|
|
||||||
border: '1px solid var(--line-2)',
|
|
||||||
borderRadius: 8,
|
|
||||||
boxShadow: 'var(--shadow-md)',
|
|
||||||
padding: '6px 0',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{exam.collection_id !== null && (
|
|
||||||
<button
|
|
||||||
className="user-menu-item"
|
|
||||||
style={{ fontSize: 13 }}
|
|
||||||
onClick={() => void handleMoveExam(exam.id, null)}
|
|
||||||
>
|
|
||||||
{t('workspace.removeFromCollection')}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{collections.map((col) => (
|
|
||||||
col.id !== exam.collection_id && (
|
|
||||||
<button
|
|
||||||
key={col.id}
|
|
||||||
className="user-menu-item"
|
|
||||||
style={{ fontSize: 13 }}
|
|
||||||
onClick={() => void handleMoveExam(exam.id, col.id)}
|
|
||||||
>
|
|
||||||
{col.name}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
))}
|
|
||||||
{collections.length === 0 && exam.collection_id === null && (
|
|
||||||
<div className="user-menu-item" style={{ fontSize: 13, color: 'var(--ink-3)', cursor: 'default' }}>
|
|
||||||
{t('workspace.noSavedExams')}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div style={{ position: 'relative' }}>
|
|
||||||
<button
|
|
||||||
className="btn btn-sm"
|
|
||||||
onClick={() => setShareOpenId((id) => (id === exam.id ? null : exam.id))}
|
|
||||||
disabled={startingId === exam.id || sharingId === exam.id}
|
|
||||||
title={exam.share_token ? t('share.shared') : t('share.share')}
|
|
||||||
>
|
|
||||||
{sharingId === exam.id ? t('common.loading') : (exam.share_token ? t('share.shared') : t('share.share'))}
|
|
||||||
</button>
|
|
||||||
{shareOpenId === exam.id && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
right: 0,
|
|
||||||
top: 'calc(100% + 4px)',
|
|
||||||
zIndex: 10,
|
|
||||||
minWidth: 180,
|
|
||||||
background: 'var(--paper)',
|
|
||||||
border: '1px solid var(--line-2)',
|
|
||||||
borderRadius: 8,
|
|
||||||
boxShadow: 'var(--shadow-md)',
|
|
||||||
padding: '6px 0',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{exam.share_token ? (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
className="user-menu-item"
|
|
||||||
style={{ fontSize: 13 }}
|
|
||||||
onClick={() => {
|
|
||||||
const url = `${window.location.origin}/share/${exam.share_token}`
|
|
||||||
void navigator.clipboard.writeText(url)
|
|
||||||
setShareOpenId(null)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('share.copyLink')}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="user-menu-item"
|
|
||||||
style={{ fontSize: 13, color: 'var(--wrong)' }}
|
|
||||||
onClick={() => void handleUnshare(exam.id)}
|
|
||||||
>
|
|
||||||
{t('share.revokeLink')}
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<button
|
|
||||||
className="user-menu-item"
|
|
||||||
style={{ fontSize: 13 }}
|
|
||||||
onClick={() => void handleShare(exam.id)}
|
|
||||||
>
|
|
||||||
{t('share.generateLink')}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{deleteConfirm === exam.id ? (
|
{deleteConfirm === exam.id ? (
|
||||||
<div className="workspace-delete-confirm">
|
<div className="workspace-delete-confirm">
|
||||||
|
<span style={{ fontSize: 13, color: 'var(--ink-3)', marginRight: 4 }}>
|
||||||
|
{t('workspace.batchDeleteConfirm')}
|
||||||
|
</span>
|
||||||
<button className="btn btn-sm admin-btn-danger" onClick={() => void deleteExam(exam.id)}>
|
<button className="btn btn-sm admin-btn-danger" onClick={() => void deleteExam(exam.id)}>
|
||||||
{t('common.confirm')}
|
{t('common.confirm')}
|
||||||
</button>
|
</button>
|
||||||
@@ -784,14 +649,170 @@ export default function MyExams({ onLoadExam }: Readonly<Props>) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<>
|
||||||
className="btn btn-ghost btn-sm admin-btn-danger-ghost"
|
<button
|
||||||
onClick={() => setDeleteConfirm(exam.id)}
|
className="btn btn-primary btn-sm"
|
||||||
title={t('common.delete')}
|
onClick={() => void startExam(exam.id)}
|
||||||
disabled={startingId === exam.id}
|
disabled={startingId === exam.id}
|
||||||
>
|
>
|
||||||
✕
|
{startingId === exam.id ? t('common.loading') : t('workspace.takeExam')}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-sm"
|
||||||
|
onClick={() => navigate(`/exam-editor/${exam.id}`)}
|
||||||
|
disabled={startingId === exam.id}
|
||||||
|
>
|
||||||
|
{t('common.edit')}
|
||||||
|
</button>
|
||||||
|
<div style={{ position: 'relative' }}>
|
||||||
|
<button
|
||||||
|
className="btn btn-ghost btn-sm workspace-menu-trigger"
|
||||||
|
onClick={() => menuOpenId === exam.id ? closeMenu() : openMenu(exam.id)}
|
||||||
|
disabled={startingId === exam.id}
|
||||||
|
title="More actions"
|
||||||
|
aria-label="More actions"
|
||||||
|
aria-haspopup="menu"
|
||||||
|
aria-expanded={menuOpenId === exam.id}
|
||||||
|
>
|
||||||
|
⋯
|
||||||
|
</button>
|
||||||
|
{menuOpenId === exam.id && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="workspace-menu-backdrop"
|
||||||
|
onClick={closeMenu}
|
||||||
|
aria-label="Close menu"
|
||||||
|
tabIndex={-1}
|
||||||
|
/>
|
||||||
|
<div className="workspace-menu" role="menu">
|
||||||
|
{menuSection === 'main' && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item"
|
||||||
|
onClick={() => { closeMenu(); void handleDuplicate(exam.id) }}
|
||||||
|
disabled={duplicatingId === exam.id}
|
||||||
|
>
|
||||||
|
<span className="workspace-menu-icon">⧉</span>
|
||||||
|
<span>{duplicatingId === exam.id ? t('common.loading') : t('workspace.duplicate')}</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item"
|
||||||
|
onClick={() => { closeMenu(); void handleExport(exam.id, exam.title) }}
|
||||||
|
disabled={exportingId === exam.id}
|
||||||
|
>
|
||||||
|
<span className="workspace-menu-icon">↓</span>
|
||||||
|
<span>{exportingId === exam.id ? t('common.loading') : t('workspace.export')}</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item"
|
||||||
|
onClick={() => setMenuSection('move')}
|
||||||
|
disabled={movingExamId === exam.id}
|
||||||
|
>
|
||||||
|
<span className="workspace-menu-icon">▤</span>
|
||||||
|
<span>{t('workspace.moveTo')}</span>
|
||||||
|
<span className="workspace-menu-chevron">›</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item"
|
||||||
|
onClick={() => setMenuSection('share')}
|
||||||
|
disabled={sharingId === exam.id}
|
||||||
|
>
|
||||||
|
<span className="workspace-menu-icon">↗</span>
|
||||||
|
<span>
|
||||||
|
{sharingId === exam.id
|
||||||
|
? t('common.loading')
|
||||||
|
: (exam.share_token ? t('share.shared') : t('share.share'))}
|
||||||
|
</span>
|
||||||
|
<span className="workspace-menu-chevron">›</span>
|
||||||
|
</button>
|
||||||
|
<div className="workspace-menu-divider" />
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item workspace-menu-item-danger"
|
||||||
|
onClick={() => { closeMenu(); setDeleteConfirm(exam.id) }}
|
||||||
|
>
|
||||||
|
<span className="workspace-menu-icon">✕</span>
|
||||||
|
<span>{t('common.delete')}</span>
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{menuSection === 'move' && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-back"
|
||||||
|
onClick={() => setMenuSection('main')}
|
||||||
|
>
|
||||||
|
‹ {t('common.back')}
|
||||||
|
</button>
|
||||||
|
<div className="workspace-menu-divider" />
|
||||||
|
{exam.collection_id !== null && (
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item"
|
||||||
|
onClick={() => void handleMoveExam(exam.id, null)}
|
||||||
|
>
|
||||||
|
{t('workspace.removeFromCollection')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{collections.map((col) => (
|
||||||
|
col.id !== exam.collection_id && (
|
||||||
|
<button
|
||||||
|
key={col.id}
|
||||||
|
className="user-menu-item workspace-menu-item"
|
||||||
|
onClick={() => void handleMoveExam(exam.id, col.id)}
|
||||||
|
>
|
||||||
|
{col.name}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
))}
|
||||||
|
{collections.length === 0 && exam.collection_id === null && (
|
||||||
|
<div className="user-menu-item workspace-menu-item" style={{ color: 'var(--ink-3)', cursor: 'default' }}>
|
||||||
|
{t('workspace.collections')}: 0
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{menuSection === 'share' && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-back"
|
||||||
|
onClick={() => setMenuSection('main')}
|
||||||
|
>
|
||||||
|
‹ {t('common.back')}
|
||||||
|
</button>
|
||||||
|
<div className="workspace-menu-divider" />
|
||||||
|
{exam.share_token ? (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item"
|
||||||
|
onClick={() => {
|
||||||
|
const url = `${window.location.origin}/share/${exam.share_token}`
|
||||||
|
void navigator.clipboard.writeText(url)
|
||||||
|
closeMenu()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('share.copyLink')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item workspace-menu-item-danger"
|
||||||
|
onClick={() => void handleUnshare(exam.id)}
|
||||||
|
>
|
||||||
|
{t('share.revokeLink')}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
className="user-menu-item workspace-menu-item"
|
||||||
|
onClick={() => void handleShare(exam.id)}
|
||||||
|
>
|
||||||
|
{sharingId === exam.id ? t('common.loading') : t('share.generateLink')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2532,9 +2532,107 @@ select {
|
|||||||
|
|
||||||
.workspace-delete-confirm {
|
.workspace-delete-confirm {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Overflow (⋯) menu trigger */
|
||||||
|
.workspace-menu-trigger {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 4px 10px;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
color: var(--ink-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Click-away backdrop for the overflow menu */
|
||||||
|
.workspace-menu-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 9;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: default;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overflow menu panel */
|
||||||
|
.workspace-menu {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: calc(100% + 6px);
|
||||||
|
z-index: 10;
|
||||||
|
min-width: 220px;
|
||||||
|
background: var(--paper);
|
||||||
|
border: 1px solid var(--line-2);
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
padding: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
animation: workspace-menu-in 120ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes workspace-menu-in {
|
||||||
|
from { opacity: 0; transform: translateY(-2px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-menu-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 80ms ease, color 80ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-menu-item:disabled {
|
||||||
|
opacity: 0.55;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-menu-icon {
|
||||||
|
width: 16px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--ink-3);
|
||||||
|
font-size: 13px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-menu-chevron {
|
||||||
|
margin-left: auto;
|
||||||
|
color: var(--ink-4);
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-menu-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: var(--line);
|
||||||
|
margin: 4px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-menu-item-danger {
|
||||||
|
color: var(--wrong);
|
||||||
|
}
|
||||||
|
.workspace-menu-item-danger .workspace-menu-icon {
|
||||||
|
color: var(--wrong);
|
||||||
|
}
|
||||||
|
.workspace-menu-item-danger:hover {
|
||||||
|
background: var(--wrong-weak);
|
||||||
|
color: var(--wrong);
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-menu-back {
|
||||||
|
color: var(--ink-3);
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Empty state */
|
/* Empty state */
|
||||||
.workspace-empty {
|
.workspace-empty {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
Reference in new issue
Block a user