Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f6f01942e | |||
| 7e80320e9f | |||
| fb00ddb1d8 | |||
| 6bbbbc1633 |
@@ -649,6 +649,11 @@ async function listGameItems(gameId) {
|
||||
return rows.map(mapGameItemRow)
|
||||
}
|
||||
|
||||
async function findGameItemById(itemId) {
|
||||
const rows = await query('SELECT id, game_id, src, label, created_at FROM game_items WHERE id = ? LIMIT 1', [itemId])
|
||||
return mapGameItemRow(rows[0])
|
||||
}
|
||||
|
||||
async function getGameDetail(gameId) {
|
||||
const game = await findGameById(gameId)
|
||||
if (!game) return null
|
||||
@@ -931,6 +936,14 @@ async function listImageAssets() {
|
||||
return rows.map(mapImageAssetRow)
|
||||
}
|
||||
|
||||
async function findImageAssetById(id) {
|
||||
const rows = await query(
|
||||
'SELECT id, content_hash, src, mime_type, byte_size, original_byte_size, width, height, created_at FROM image_assets WHERE id = ? LIMIT 1',
|
||||
[id]
|
||||
)
|
||||
return mapImageAssetRow(rows[0])
|
||||
}
|
||||
|
||||
async function getReferencedUploadFootprint() {
|
||||
const [referencedSrcs, assets] = await Promise.all([listReferencedUploadSources(), listImageAssets()])
|
||||
const assetMap = new Map(assets.map((asset) => [asset.src, asset]))
|
||||
@@ -1208,32 +1221,70 @@ async function getCustomItemUsageMeta() {
|
||||
async function listCustomItems({ queryText = '', page = 1, limit = 50, orphanOnly = false } = {}) {
|
||||
const normalizedLimit = Math.min(Math.max(Number(limit) || 50, 1), 200)
|
||||
const normalizedPage = Math.max(Number(page) || 1, 1)
|
||||
const hasQuery = !!(queryText || '').trim()
|
||||
const search = `%${(queryText || '').trim()}%`
|
||||
const whereClause = hasQuery ? 'WHERE c.label LIKE ? OR c.src LIKE ? OR u.email LIKE ? OR u.nickname LIKE ?' : ''
|
||||
const params = hasQuery ? [search, search, search, search] : []
|
||||
const searchText = (queryText || '').trim()
|
||||
const hasQuery = !!searchText
|
||||
const search = `%${searchText}%`
|
||||
|
||||
const rows = await query(
|
||||
`
|
||||
SELECT
|
||||
c.id,
|
||||
c.owner_id,
|
||||
c.src,
|
||||
c.label,
|
||||
c.created_at,
|
||||
u.nickname,
|
||||
u.email
|
||||
FROM custom_items c
|
||||
INNER JOIN users u ON u.id = c.owner_id
|
||||
${whereClause}
|
||||
ORDER BY c.created_at DESC
|
||||
`,
|
||||
params
|
||||
)
|
||||
const [customRows, gameItemRows, assetRows, usageMeta] = await Promise.all([
|
||||
query(
|
||||
`
|
||||
SELECT
|
||||
c.id,
|
||||
c.owner_id,
|
||||
c.src,
|
||||
c.label,
|
||||
c.created_at,
|
||||
u.nickname,
|
||||
u.email
|
||||
FROM custom_items c
|
||||
INNER JOIN users u ON u.id = c.owner_id
|
||||
${hasQuery ? 'WHERE c.label LIKE ? OR c.src LIKE ? OR u.email LIKE ? OR u.nickname LIKE ?' : ''}
|
||||
ORDER BY c.created_at DESC
|
||||
`,
|
||||
hasQuery ? [search, search, search, search] : []
|
||||
),
|
||||
query(
|
||||
`
|
||||
SELECT
|
||||
gi.id,
|
||||
gi.game_id,
|
||||
gi.src,
|
||||
gi.label,
|
||||
gi.created_at,
|
||||
g.name AS game_name
|
||||
FROM game_items gi
|
||||
INNER JOIN games g ON g.id = gi.game_id
|
||||
${hasQuery ? 'WHERE gi.label LIKE ? OR gi.src LIKE ? OR gi.game_id LIKE ? OR g.name LIKE ?' : ''}
|
||||
ORDER BY gi.created_at DESC
|
||||
`,
|
||||
hasQuery ? [search, search, search, search] : []
|
||||
),
|
||||
query(
|
||||
`
|
||||
SELECT ia.id, ia.src, ia.created_at
|
||||
FROM image_assets ia
|
||||
WHERE ia.src LIKE '/uploads/assets/%'
|
||||
${hasQuery ? 'AND ia.src LIKE ?' : ''}
|
||||
ORDER BY ia.created_at DESC
|
||||
`,
|
||||
hasQuery ? [search] : []
|
||||
),
|
||||
getCustomItemUsageMeta(),
|
||||
])
|
||||
|
||||
const { usageMap, linkedGamesMap } = await getCustomItemUsageMeta()
|
||||
const allItems = rows
|
||||
.map((row) => ({
|
||||
const templateLinkedBySrc = new Map()
|
||||
gameItemRows.forEach((row) => {
|
||||
if (!row?.src) return
|
||||
if (!templateLinkedBySrc.has(row.src)) templateLinkedBySrc.set(row.src, new Map())
|
||||
templateLinkedBySrc.get(row.src).set(row.game_id, {
|
||||
id: row.game_id,
|
||||
name: row.game_name || row.game_id,
|
||||
})
|
||||
})
|
||||
|
||||
const customItems = customRows.map((row) => {
|
||||
const linkedGames = Array.from((templateLinkedBySrc.get(row.src) || new Map()).values())
|
||||
return {
|
||||
id: row.id,
|
||||
ownerId: row.owner_id,
|
||||
src: row.src,
|
||||
@@ -1241,10 +1292,60 @@ async function listCustomItems({ queryText = '', page = 1, limit = 50, orphanOnl
|
||||
createdAt: Number(row.created_at),
|
||||
ownerName: row.nickname || row.email,
|
||||
ownerEmail: row.email,
|
||||
usageCount: usageMap.get(row.id) || 0,
|
||||
linkedGames: linkedGamesMap.get(row.id) || [],
|
||||
usageCount: usageMeta.usageMap.get(row.id) || 0,
|
||||
linkedGames,
|
||||
sourceType: 'user',
|
||||
sourceLabel: '사용자 업로드',
|
||||
canDelete: true,
|
||||
}
|
||||
})
|
||||
|
||||
const templateSrcSet = new Set(gameItemRows.map((row) => row.src).filter(Boolean))
|
||||
const customSrcSet = new Set(customRows.map((row) => row.src).filter(Boolean))
|
||||
const assetLibraryItems = assetRows
|
||||
.filter((row) => row?.src && !templateSrcSet.has(row.src) && !customSrcSet.has(row.src))
|
||||
.map((row) => ({
|
||||
id: `asset:${row.id}`,
|
||||
assetId: row.id,
|
||||
ownerId: '',
|
||||
src: row.src,
|
||||
label: (row.src.split('/').pop() || '').replace(/\.[^.]+$/, '') || '이름 없음',
|
||||
createdAt: Number(row.created_at || 0),
|
||||
ownerName: '관리자 보관 자산',
|
||||
ownerEmail: '',
|
||||
usageCount: 0,
|
||||
linkedGames: [],
|
||||
sourceType: 'template',
|
||||
sourceLabel: '관리자 템플릿',
|
||||
canDelete: true,
|
||||
sourceGameId: '',
|
||||
sourceGameName: '',
|
||||
isAssetLibraryItem: true,
|
||||
}))
|
||||
.filter((item) => (orphanOnly ? item.usageCount === 0 : true))
|
||||
|
||||
const templateItems = gameItemRows.map((row) => ({
|
||||
id: row.id,
|
||||
ownerId: '',
|
||||
src: row.src,
|
||||
label: row.label,
|
||||
createdAt: Number(row.created_at),
|
||||
ownerName: row.game_name || row.game_id,
|
||||
ownerEmail: '',
|
||||
usageCount: (templateLinkedBySrc.get(row.src) || new Map()).size,
|
||||
linkedGames: Array.from((templateLinkedBySrc.get(row.src) || new Map()).values()),
|
||||
sourceType: 'template',
|
||||
sourceLabel: '관리자 템플릿',
|
||||
canDelete: true,
|
||||
sourceGameId: row.game_id,
|
||||
sourceGameName: row.game_name || row.game_id,
|
||||
}))
|
||||
|
||||
const allItems = [...customItems, ...templateItems, ...assetLibraryItems]
|
||||
.filter((item) => {
|
||||
if (!orphanOnly) return true
|
||||
return item.sourceType === 'user' && item.usageCount === 0 && item.linkedGames.length === 0
|
||||
})
|
||||
.sort((a, b) => Number(b.createdAt || 0) - Number(a.createdAt || 0))
|
||||
|
||||
const total = allItems.length
|
||||
const offset = (normalizedPage - 1) * normalizedLimit
|
||||
@@ -1935,11 +2036,13 @@ module.exports = {
|
||||
listGames,
|
||||
findGameById,
|
||||
listGameItems,
|
||||
findGameItemById,
|
||||
getGameDetail,
|
||||
createGame,
|
||||
updateGameThumbnail,
|
||||
findImageAssetByHash,
|
||||
findImageAssetBySrc,
|
||||
findImageAssetById,
|
||||
createImageAsset,
|
||||
createImageOptimizationJob,
|
||||
findImageOptimizationJobById,
|
||||
|
||||
@@ -75,7 +75,7 @@ async function optimizeAndPersist({ file, width, height, fit, quality }) {
|
||||
}
|
||||
}
|
||||
|
||||
const filename = String(Date.now()) + '-' + nanoid() + '.webp'
|
||||
const filename = nanoid() + '.webp'
|
||||
const absoluteDir = path.join(UPLOAD_ROOT, OPTIMIZED_DIR)
|
||||
const absolutePath = path.join(absoluteDir, filename)
|
||||
const src = '/uploads/' + OPTIMIZED_DIR + '/' + filename
|
||||
|
||||
@@ -8,6 +8,8 @@ const { nanoid } = require('nanoid')
|
||||
const {
|
||||
findUserById,
|
||||
findGameById,
|
||||
findGameItemById,
|
||||
findImageAssetById,
|
||||
createGame,
|
||||
listGames,
|
||||
updateGameThumbnail,
|
||||
@@ -308,6 +310,20 @@ router.post('/image-assets/stats/reset', requireAdmin, async (req, res) => {
|
||||
res.json({ deletedCount })
|
||||
})
|
||||
|
||||
async function removeUploadFiles(srcs) {
|
||||
await Promise.all(
|
||||
(srcs || []).map(async (src) => {
|
||||
if (!src || !src.startsWith('/uploads/')) return
|
||||
const absolutePath = path.join(__dirname, '..', '..', src.replace(/^\//, ''))
|
||||
try {
|
||||
await fs.unlink(absolutePath)
|
||||
} catch (e) {
|
||||
if (e?.code !== 'ENOENT') throw e
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
async function removeCustomItemFiles(items) {
|
||||
await Promise.all(
|
||||
items.map(async (item) => {
|
||||
@@ -322,12 +338,12 @@ async function removeCustomItemFiles(items) {
|
||||
)
|
||||
}
|
||||
|
||||
async function promoteCustomItemToGameItem({ customItem, gameId }) {
|
||||
async function promoteLibraryItemToGameItem({ item, gameId }) {
|
||||
return createGameItem({
|
||||
id: nanoid(),
|
||||
gameId,
|
||||
src: customItem.src || '',
|
||||
label: customItem.label,
|
||||
src: item.src || '',
|
||||
label: item.label,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -425,15 +441,31 @@ async function createGameTemplateFromRequest({ templateRequest, gameId, gameName
|
||||
}
|
||||
|
||||
router.delete('/custom-items/:itemId', requireAdmin, async (req, res) => {
|
||||
const result = await listCustomItems({ page: 1, limit: 200, orphanOnly: false })
|
||||
const result = await listCustomItems({ page: 1, limit: 10000, orphanOnly: false })
|
||||
const target = result.items.find((item) => item.id === req.params.itemId)
|
||||
if (!target) return res.status(404).json({ error: 'not_found' })
|
||||
if (target.sourceType === 'template') {
|
||||
if (String(target.id || '').startsWith('asset:')) {
|
||||
const assetId = String(target.id).slice('asset:'.length)
|
||||
const asset = await findImageAssetById(assetId)
|
||||
if (!asset) return res.status(404).json({ error: 'not_found' })
|
||||
await deleteImageAssets([assetId])
|
||||
await removeUploadFiles([asset.src])
|
||||
return res.json({ ok: true, sourceType: 'template-asset' })
|
||||
}
|
||||
|
||||
await deleteGameItem(target.id)
|
||||
return res.json({ ok: true, sourceType: 'template' })
|
||||
}
|
||||
|
||||
if (!target.canDelete) return res.status(409).json({ error: 'item_locked' })
|
||||
if (target.linkedGames.length > 0) return res.status(409).json({ error: 'item_linked' })
|
||||
if (target.usageCount > 0) return res.status(409).json({ error: 'item_in_use' })
|
||||
|
||||
const items = await findCustomItemsByIds([target.id])
|
||||
await deleteCustomItems([target.id])
|
||||
await removeCustomItemFiles(items)
|
||||
res.json({ ok: true })
|
||||
res.json({ ok: true, sourceType: 'user' })
|
||||
})
|
||||
|
||||
router.post('/custom-items/:itemId/promote', requireAdmin, async (req, res) => {
|
||||
@@ -447,9 +479,11 @@ router.post('/custom-items/:itemId/promote', requireAdmin, async (req, res) => {
|
||||
if (!game) return res.status(404).json({ error: 'game_not_found' })
|
||||
|
||||
const customItem = await findCustomItemById(req.params.itemId)
|
||||
if (!customItem) return res.status(404).json({ error: 'not_found' })
|
||||
const gameItem = customItem ? null : await findGameItemById(req.params.itemId)
|
||||
const sourceItem = customItem || gameItem
|
||||
if (!sourceItem) return res.status(404).json({ error: 'not_found' })
|
||||
|
||||
const item = await promoteCustomItemToGameItem({ customItem, gameId: game.id })
|
||||
const item = await promoteLibraryItemToGameItem({ item: sourceItem, gameId: game.id })
|
||||
res.json({ item })
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 할 일 및 이슈
|
||||
|
||||
## 중기 개선
|
||||
- 라이트모드/다크모드 1차 전환은 붙였으므로, 관리자 화면과 티어 에디터까지 세부 색상 균형을 더 정교하게 맞추는 후속 테마 보정 작업을 이어간다.
|
||||
- 라이트모드/다크모드 2차 보정까지 반영했으므로, 남은 작업은 전체 화면을 실제 사용 흐름으로 돌려 보며 대비·명도·아이콘 가독성을 미세하게 QA하는 최종 테마 점검 단계로 가져간다.
|
||||
- 관리자용 티어표 승인/숨김 처리, 아이템 정렬 UI를 추가한다.
|
||||
- 회원 일괄 작업(다중 선택, 일괄 비밀번호 초기화, 활동 저조 계정 정리) 같은 관리 보조 기능을 추가한다.
|
||||
- 티어 행 프리셋 저장, 색상 관리, 행 복제 같은 고급 편집 기능을 추가한다.
|
||||
@@ -10,3 +10,9 @@
|
||||
- production에서 SESSION_SECRET 누락 시 서버가 부팅되지 않도록 강제한다.
|
||||
- helmet 기반 보안 헤더와 업로드 정적 응답 헤더를 정리한다.
|
||||
- 책 아이콘 기반 사용법 모달은 제작 흐름뿐 아니라 복사, 템플릿 업데이트 요청, 새 템플릿 요청까지 확장했으므로, 실제 16:9 스크린샷 자산과 단계별 문구를 운영 톤에 맞게 채운다.
|
||||
|
||||
- 관리자 아이템 라이브러리에서 동일 이미지(src)를 여러 템플릿이 공유하는 경우, 필요하면 묶어서 보거나 대표 카드로 합쳐 보는 후속 정리 옵션을 검토한다.
|
||||
|
||||
- 라이트모드 최종 QA 시 홈/설정/관리자/에디터를 실제 사용 흐름으로 돌리며, 남아 있는 하드코딩 텍스트 색과 플레이스홀더 배경을 한 번 더 점검한다.
|
||||
|
||||
- 관리자 아이템 라이브러리는 보관 자산까지 노출되므로, 이후에는 `활성 템플릿 / 보관 자산` 분리 필터나 그룹 보기까지 검토한다.
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# 업데이트 로그
|
||||
|
||||
## 2026-04-01 v1.3.36
|
||||
- `내 티어표` 화면 헤더를 공통 `pageHead` 문법으로 통일하고, 라이트모드에서는 공통 `railHeader` 배경을 사이드 레일과 같은 톤으로 맞춰 화면 간 상단 밀도 차를 줄임.
|
||||
- 관리자 아이템 상세 모달은 더 넓은 비율로 키우고, 템플릿에 연결된 게임 이름은 hover 가능한 버튼으로 바꿔 클릭 시 해당 게임이 선택된 `게임 관리` 탭으로 바로 이동할 수 있게 함.
|
||||
- 관리자 아이템 라이브러리는 이제 게임에 연결된 템플릿 이미지뿐 아니라 연결이 해제된 `/uploads/assets/` 보관 자산도 함께 보여줘, 게임 목록에서 아이템을 제거해도 아이템 관리에서는 계속 검수·재연결할 수 있게 정리함.
|
||||
- 아이템 관리 탭은 다른 탭으로 이동했다가 돌아오면 검색어와 필터를 초기화해, 결과가 남아 있어 목록이 비어 보이는 오해를 줄이도록 조정함.
|
||||
|
||||
## 2026-04-01 v1.3.35
|
||||
- 라이트모드에서 홈 게임 카드의 메타 텍스트와 대표 썸네일 플레이스홀더, 브랜드 타이틀 색을 다시 정리하고, 전체 밝기도 약간 눌러 눈부심이 덜한 회백색 톤으로 보정함.
|
||||
- 관리자 아이템 상세 모달은 더 넓은 2단 레이아웃으로 키우고, 브라우저 뒤로가기 시 페이지 이탈 대신 모달이 먼저 닫히도록 히스토리 동작을 보강함.
|
||||
- 아이템 라이브러리의 삭제 기준을 다시 정리해, 사용자 업로드는 어디에도 연결되지 않았을 때만 삭제하고 관리자 템플릿 이미지는 라이브러리에서도 해당 템플릿 항목을 제거할 수 있게 확장함.
|
||||
|
||||
## 2026-04-01 v1.3.34
|
||||
- 관리자 아이템 관리 오른쪽 사이드에서는 `가져올 게임` 셀렉트를 제거하고, 사용자 업로드와 관리자 템플릿 이미지를 함께 검수하는 라이브러리 흐름으로 단순화함.
|
||||
- 아이템 상세 모달은 좌측에 검색/정렬 가능한 게임 리스트를 두고 우측에 이미지·메타·액션을 배치하는 2단 레이아웃으로 재구성해, 많은 게임 속에서도 직접 검수 후 템플릿에 연결하기 쉽게 정리함.
|
||||
- 아이템 라이브러리에는 이제 관리자 템플릿 이미지도 함께 표시하고, 배지로 `사용자 업로드 / 관리자 템플릿`을 구분하며 새 업로드 WebP 파일명에서는 시간 정보처럼 보이는 접두 숫자를 제거함.
|
||||
- 템플릿 아이템까지 함께 보이는 구조에 맞춰 삭제 API도 사용자 업로드이면서 템플릿에 연결되지 않은 항목만 지울 수 있도록 안전 장치를 보강함.
|
||||
|
||||
## 2026-04-01 v1.3.33
|
||||
- 라이트모드/다크모드 2차 보정으로 관리자 화면과 티어 에디터의 카드, 패널, 입력창, 모달, 썸네일 프레임을 전역 테마 변수 기준으로 다시 맞춰, 후속 화면에서도 명도 차가 더 자연스럽게 이어지도록 정리함.
|
||||
- 공통 셸도 함께 손봐서 좌측 사이드 아이콘 필터와 텍스트 대비를 테마 변수 기반으로 전환하고, 가이드 모달·축소 검색 모달·내비 활성 상태까지 라이트모드에서 읽기 쉬운 톤으로 보정함.
|
||||
- 전역 스타일 변수의 다크 기본값과 아이콘 필터 값을 바로잡아, 카드 배경과 텍스트 변수의 자기참조/오동작 가능성을 줄이고 이후 테마 QA 기준을 더 안정적으로 맞춤.
|
||||
|
||||
## 2026-04-01 v1.3.32
|
||||
- 전역 테마 변수와 로컬 저장 기반 테마 토글을 추가해, Settings 화면 오른쪽 사이드에서 라이트모드/다크모드를 전환하고 재방문 시 같은 테마를 유지할 수 있게 함.
|
||||
- 앱 셸, 홈, 게임 허브, 내 티어표, 즐겨찾기, 검색, 로그인, 설정 화면의 공통 카드·입력·텍스트 색을 테마 변수 기준으로 바꿔, 주요 사용자 화면은 라이트/다크 전환이 자연스럽게 이어지도록 1차 정리함.
|
||||
|
||||
@@ -684,6 +684,7 @@ function submitGlobalSearch() {
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
border-bottom: 1px solid var(--theme-border);
|
||||
background: var(--theme-rail-bg);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -744,7 +745,7 @@ function submitGlobalSearch() {
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--theme-border);
|
||||
background: var(--theme-pill-bg);
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
color: var(--theme-text-soft);
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -771,7 +772,7 @@ function submitGlobalSearch() {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: block;
|
||||
filter: brightness(0) saturate(100%) invert(94%) sepia(6%) saturate(207%) hue-rotate(186deg) brightness(96%) contrast(92%);
|
||||
filter: var(--theme-icon-filter);
|
||||
}
|
||||
|
||||
.ghostIcon--iconOnly {
|
||||
@@ -818,7 +819,7 @@ function submitGlobalSearch() {
|
||||
.appUserCard__avatar--fallback {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
background: var(--theme-surface-soft-3);
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
@@ -853,7 +854,7 @@ function submitGlobalSearch() {
|
||||
border-radius: 14px;
|
||||
border: 1px solid var(--theme-border);
|
||||
background: var(--theme-pill-bg);
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
color: var(--theme-text-soft);
|
||||
margin-bottom: 14px;
|
||||
box-sizing: border-box;
|
||||
transition: padding 220ms ease, justify-content 220ms ease;
|
||||
@@ -906,7 +907,7 @@ function submitGlobalSearch() {
|
||||
gap: 12px;
|
||||
padding: 11px 12px;
|
||||
border-radius: 14px;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
color: var(--theme-text-muted);
|
||||
text-decoration: none;
|
||||
transition: background 180ms ease, color 180ms ease, transform 180ms ease;
|
||||
}
|
||||
@@ -921,8 +922,8 @@ function submitGlobalSearch() {
|
||||
|
||||
.leftNav__item--active,
|
||||
.leftNav__item.router-link-active {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: rgba(255, 255, 255, 0.96);
|
||||
background: var(--theme-surface-soft-3);
|
||||
color: var(--theme-text-strong);
|
||||
}
|
||||
|
||||
.leftNav__glyph {
|
||||
@@ -1065,10 +1066,7 @@ function submitGlobalSearch() {
|
||||
font-size: 28px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.05em;
|
||||
background-image: linear-gradient(90deg, #ff75c3 0%, #ffa647 20%, #ffe83f 40%, #9fff5b 60%, #70e2ff 80%, #cd93ff 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
color: var(--theme-text-strong);
|
||||
}
|
||||
|
||||
.workspaceHead__brandSub {
|
||||
@@ -1273,7 +1271,7 @@ function submitGlobalSearch() {
|
||||
grid-template-columns: 260px minmax(0, 1fr);
|
||||
border-radius: 28px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: linear-gradient(180deg, rgba(34, 34, 34, 0.98), rgba(18, 18, 18, 0.98));
|
||||
box-shadow: 0 28px 90px rgba(0, 0, 0, 0.42);
|
||||
}
|
||||
@@ -1291,7 +1289,7 @@ function submitGlobalSearch() {
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
color: var(--theme-text-faint);
|
||||
}
|
||||
|
||||
.guideModal__title {
|
||||
@@ -1314,8 +1312,8 @@ function submitGlobalSearch() {
|
||||
padding: 12px 14px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid var(--theme-border);
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background: var(--theme-pill-bg);
|
||||
color: var(--theme-text-muted);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
@@ -1323,13 +1321,13 @@ function submitGlobalSearch() {
|
||||
.guideModal__listItem--active {
|
||||
border-color: rgba(77, 127, 233, 0.5);
|
||||
background: rgba(77, 127, 233, 0.14);
|
||||
color: rgba(255, 255, 255, 0.96);
|
||||
color: var(--theme-text-strong);
|
||||
}
|
||||
|
||||
.guideModal__listIndex {
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
color: var(--theme-text-faint);
|
||||
}
|
||||
|
||||
.guideModal__listLabel {
|
||||
@@ -1400,7 +1398,7 @@ function submitGlobalSearch() {
|
||||
|
||||
.guideModal__mediaHint {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.48);
|
||||
color: var(--theme-text-faint);
|
||||
}
|
||||
|
||||
.guideModal__text {
|
||||
@@ -1424,14 +1422,14 @@ function submitGlobalSearch() {
|
||||
.guideModal__stepSummary {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.86);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
.guideModal__stepDescription {
|
||||
margin: 0;
|
||||
max-width: 720px;
|
||||
line-height: 1.7;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
color: var(--theme-text-soft);
|
||||
}
|
||||
|
||||
.guideModal__footer {
|
||||
@@ -1452,7 +1450,7 @@ function submitGlobalSearch() {
|
||||
height: 10px;
|
||||
border-radius: 999px;
|
||||
border: 0;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
background: var(--theme-surface-soft-3);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -1496,7 +1494,7 @@ function submitGlobalSearch() {
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
padding: 88px 20px 20px;
|
||||
background: rgba(0, 0, 0, 0.44);
|
||||
background: color-mix(in srgb, var(--theme-body-bg) 72%, transparent);
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
@@ -1507,8 +1505,8 @@ function submitGlobalSearch() {
|
||||
gap: 14px;
|
||||
padding: 18px 22px;
|
||||
border-radius: 24px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: rgba(26, 26, 26, 0.96);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: var(--theme-main-bg);
|
||||
box-shadow: 0 28px 60px rgba(0, 0, 0, 0.34);
|
||||
}
|
||||
|
||||
@@ -1525,7 +1523,7 @@ function submitGlobalSearch() {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: block;
|
||||
filter: brightness(0) saturate(100%) invert(94%) sepia(6%) saturate(207%) hue-rotate(186deg) brightness(96%) contrast(92%);
|
||||
filter: var(--theme-icon-filter);
|
||||
}
|
||||
|
||||
.collapsedSearchBar__input {
|
||||
@@ -1540,7 +1538,7 @@ function submitGlobalSearch() {
|
||||
}
|
||||
|
||||
.collapsedSearchBar__input::placeholder {
|
||||
color: rgba(255, 255, 255, 0.46);
|
||||
color: var(--theme-text-faint);
|
||||
}
|
||||
|
||||
.localRightRailRoot {
|
||||
@@ -1572,7 +1570,7 @@ function submitGlobalSearch() {
|
||||
padding: 12px 14px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: rgba(11, 18, 32, 0.94);
|
||||
background: color-mix(in srgb, var(--theme-main-bg) 94%, transparent);
|
||||
backdrop-filter: blur(12px);
|
||||
box-shadow: 0 14px 30px rgba(0, 0, 0, 0.28);
|
||||
opacity: 1;
|
||||
@@ -1611,7 +1609,7 @@ function submitGlobalSearch() {
|
||||
.toast__close {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.68);
|
||||
color: var(--theme-text-muted);
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -24,45 +24,47 @@
|
||||
--theme-border: rgba(255, 255, 255, 0.08);
|
||||
--theme-border-strong: rgba(255, 255, 255, 0.12);
|
||||
--theme-text: rgba(255, 255, 255, 0.92);
|
||||
--theme-text-strong: var(--theme-text-strong);
|
||||
--theme-text-muted: var(--theme-text-muted);
|
||||
--theme-text-soft: var(--theme-text-soft);
|
||||
--theme-text-strong: rgba(255, 255, 255, 0.98);
|
||||
--theme-text-muted: rgba(255, 255, 255, 0.74);
|
||||
--theme-text-soft: rgba(255, 255, 255, 0.62);
|
||||
--theme-text-faint: rgba(255, 255, 255, 0.4);
|
||||
--theme-thumb-fallback-bg: #555;
|
||||
--theme-select-arrow: var(--theme-select-arrow);
|
||||
--theme-select-arrow: rgba(255, 255, 255, 0.68);
|
||||
--theme-danger-bg: rgba(239, 68, 68, 0.1);
|
||||
--theme-danger-border: rgba(239, 68, 68, 0.18);
|
||||
--theme-accent-bg: rgba(76, 133, 245, 0.92);
|
||||
--theme-accent-text: #fff;
|
||||
--theme-icon-filter: brightness(0) saturate(100%) invert(94%) sepia(6%) saturate(207%) hue-rotate(186deg) brightness(96%) contrast(92%);
|
||||
}
|
||||
|
||||
:root[data-theme='light'] {
|
||||
--theme-body-bg: #edf1f7;
|
||||
--theme-shell-bg: rgba(244, 247, 252, 0.98);
|
||||
--theme-rail-bg: rgba(248, 250, 253, 0.96);
|
||||
--theme-main-bg: rgba(241, 244, 249, 0.98);
|
||||
--theme-workspace-bg: rgba(250, 252, 255, 0.95);
|
||||
--theme-card-bg: var(--theme-text-strong);
|
||||
--theme-card-bg-hover: rgba(245, 248, 255, 0.98);
|
||||
--theme-card-border: rgba(26, 32, 44, 0.1);
|
||||
--theme-card-shadow: 0 18px 34px rgba(31, 41, 55, 0.08);
|
||||
--theme-surface-soft: rgba(15, 23, 42, 0.05);
|
||||
--theme-surface-soft-2: rgba(15, 23, 42, 0.07);
|
||||
--theme-surface-soft-3: rgba(15, 23, 42, 0.1);
|
||||
--theme-pill-bg: rgba(15, 23, 42, 0.04);
|
||||
--theme-border: rgba(15, 23, 42, 0.1);
|
||||
--theme-border-strong: rgba(15, 23, 42, 0.14);
|
||||
--theme-text: rgba(20, 27, 40, 0.9);
|
||||
--theme-body-bg: #e7ebf2;
|
||||
--theme-shell-bg: rgba(237, 241, 247, 0.98);
|
||||
--theme-rail-bg: rgba(243, 246, 251, 0.97);
|
||||
--theme-main-bg: rgba(232, 236, 243, 0.98);
|
||||
--theme-workspace-bg: rgba(247, 249, 252, 0.96);
|
||||
--theme-card-bg: rgba(252, 253, 255, 0.98);
|
||||
--theme-card-bg-hover: rgba(244, 247, 251, 0.98);
|
||||
--theme-card-border: rgba(31, 41, 55, 0.11);
|
||||
--theme-card-shadow: 0 18px 34px rgba(31, 41, 55, 0.07);
|
||||
--theme-surface-soft: rgba(30, 41, 59, 0.055);
|
||||
--theme-surface-soft-2: rgba(30, 41, 59, 0.075);
|
||||
--theme-surface-soft-3: rgba(30, 41, 59, 0.105);
|
||||
--theme-pill-bg: rgba(30, 41, 59, 0.045);
|
||||
--theme-border: rgba(30, 41, 59, 0.11);
|
||||
--theme-border-strong: rgba(30, 41, 59, 0.16);
|
||||
--theme-text: rgba(20, 27, 40, 0.92);
|
||||
--theme-text-strong: rgba(10, 15, 28, 0.98);
|
||||
--theme-text-muted: rgba(55, 65, 81, 0.74);
|
||||
--theme-text-soft: rgba(75, 85, 99, 0.64);
|
||||
--theme-text-faint: rgba(100, 116, 139, 0.82);
|
||||
--theme-thumb-fallback-bg: #d8dde8;
|
||||
--theme-select-arrow: rgba(55, 65, 81, 0.72);
|
||||
--theme-text-muted: rgba(55, 65, 81, 0.76);
|
||||
--theme-text-soft: rgba(75, 85, 99, 0.72);
|
||||
--theme-text-faint: rgba(100, 116, 139, 0.88);
|
||||
--theme-thumb-fallback-bg: #f6f8fb;
|
||||
--theme-select-arrow: rgba(55, 65, 81, 0.74);
|
||||
--theme-danger-bg: rgba(239, 68, 68, 0.1);
|
||||
--theme-danger-border: rgba(239, 68, 68, 0.22);
|
||||
--theme-accent-bg: rgba(64, 110, 226, 0.94);
|
||||
--theme-accent-text: #fff;
|
||||
--theme-icon-filter: brightness(0) saturate(100%) invert(14%) sepia(14%) saturate(652%) hue-rotate(182deg) brightness(95%) contrast(91%);
|
||||
}
|
||||
|
||||
* {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -215,7 +215,7 @@ function thumbUrl(g) {
|
||||
font-size: 18px;
|
||||
}
|
||||
.libraryCard__meta {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
color: var(--theme-text-soft);
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -66,11 +66,11 @@ function openList(t) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="dashboardHero">
|
||||
<div class="dashboardHero__left">
|
||||
<div class="dashboardHero__eyebrow">Library</div>
|
||||
<h2 class="dashboardHero__title">내 티어표</h2>
|
||||
<p class="dashboardHero__desc">직접 저장한 티어표를 같은 카드 레이아웃으로 다시 열고 정리할 수 있어요.</p>
|
||||
<section class="pageHead">
|
||||
<div class="pageHead__main">
|
||||
<div class="pageHead__eyebrow">Library</div>
|
||||
<h2 class="pageHead__title">내 티어표</h2>
|
||||
<div class="pageHead__desc">직접 저장한 티어표를 같은 카드 레이아웃으로 다시 열고 정리할 수 있어요.</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -110,35 +110,6 @@ function openList(t) {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dashboardHero {
|
||||
display: flex;
|
||||
gap: 18px;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
padding: 6px 2px 18px;
|
||||
}
|
||||
.dashboardHero__left {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
.dashboardHero__eyebrow {
|
||||
font-size: 12px;
|
||||
color: var(--theme-text-soft);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
.dashboardHero__title {
|
||||
margin: 4px 0 6px;
|
||||
font-size: 32px;
|
||||
letter-spacing: -0.04em;
|
||||
color: var(--theme-text-strong);
|
||||
}
|
||||
.dashboardHero__desc {
|
||||
margin: 0;
|
||||
color: var(--theme-text-muted);
|
||||
max-width: 720px;
|
||||
}
|
||||
.panel {
|
||||
background: transparent;
|
||||
border-radius: 0;
|
||||
|
||||
@@ -1361,7 +1361,7 @@ onUnmounted(() => {
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.editorMain__subtitle {
|
||||
color: rgba(255, 255, 255, 0.58);
|
||||
color: var(--theme-text-soft);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
@@ -1372,13 +1372,13 @@ onUnmounted(() => {
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
color: var(--theme-text-soft);
|
||||
}
|
||||
.editorMain__sourceLink {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: rgba(191, 219, 254, 0.94);
|
||||
color: color-mix(in srgb, var(--theme-accent-bg) 78%, white);
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1388,7 +1388,7 @@ onUnmounted(() => {
|
||||
box-sizing: border-box;
|
||||
background:
|
||||
radial-gradient(circle at top, rgba(96, 165, 250, 0.14), transparent 38%),
|
||||
rgba(11, 18, 32, 0.98);
|
||||
var(--theme-shell-bg);
|
||||
}
|
||||
.previewOnly__sheet {
|
||||
display: grid;
|
||||
@@ -1451,13 +1451,13 @@ onUnmounted(() => {
|
||||
text-align: center;
|
||||
font-weight: 900;
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: var(--theme-surface-soft-2);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
}
|
||||
.previewOnly__drop {
|
||||
border-radius: 14px;
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: var(--theme-pill-bg);
|
||||
border: 1px solid var(--theme-border);
|
||||
min-height: calc(var(--thumb-size, 80px) + 24px);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
@@ -1498,8 +1498,8 @@ onUnmounted(() => {
|
||||
gap: 12px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid var(--theme-border);
|
||||
background: var(--theme-pill-bg);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
@@ -1513,8 +1513,8 @@ onUnmounted(() => {
|
||||
width: 42px;
|
||||
height: 24px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.16);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: var(--theme-surface-soft-3);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
transition: background 180ms ease, border-color 180ms ease;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
@@ -1525,13 +1525,13 @@ onUnmounted(() => {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
background: var(--theme-text-strong);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.24);
|
||||
transition: transform 180ms ease;
|
||||
}
|
||||
.toggleSwitch__label {
|
||||
font-weight: 800;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
.toggleSwitch input:checked ~ .toggleSwitch__track {
|
||||
background: rgba(96, 165, 250, 0.34);
|
||||
@@ -1547,14 +1547,14 @@ onUnmounted(() => {
|
||||
.btn {
|
||||
padding: 10px 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: var(--theme-surface-soft-2);
|
||||
color: var(--theme-text);
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
}
|
||||
.btn:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
background: var(--theme-surface-soft-3);
|
||||
}
|
||||
.btn--primary {
|
||||
background: rgba(110, 231, 183, 0.18);
|
||||
@@ -1600,8 +1600,8 @@ onUnmounted(() => {
|
||||
}
|
||||
.board {
|
||||
width: min(100%, 960px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: linear-gradient(180deg, rgba(55, 55, 55, 0.86), rgba(42, 42, 42, 0.82));
|
||||
border: 1px solid var(--theme-border);
|
||||
background: linear-gradient(180deg, color-mix(in srgb, var(--theme-card-bg) 94%, transparent), color-mix(in srgb, var(--theme-card-bg-hover) 88%, transparent));
|
||||
border-radius: 22px;
|
||||
padding: 20px;
|
||||
align-self: start;
|
||||
@@ -1614,15 +1614,15 @@ onUnmounted(() => {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 20px;
|
||||
background: rgba(4, 8, 16, 0.68);
|
||||
background: color-mix(in srgb, var(--theme-body-bg) 76%, transparent);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
.modalCard {
|
||||
width: min(100%, 420px);
|
||||
border-radius: 20px;
|
||||
padding: 24px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
background: linear-gradient(180deg, rgba(17, 24, 39, 0.96), rgba(11, 18, 32, 0.96));
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: linear-gradient(180deg, color-mix(in srgb, var(--theme-main-bg) 98%, transparent), color-mix(in srgb, var(--theme-shell-bg) 98%, transparent));
|
||||
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.38);
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
@@ -1695,24 +1695,24 @@ onUnmounted(() => {
|
||||
}
|
||||
.templateRequestDraft__label {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.64);
|
||||
color: var(--theme-text-soft);
|
||||
}
|
||||
.templateRequestDraft__hint {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.46);
|
||||
color: var(--theme-text-faint);
|
||||
}
|
||||
.templateRequestDraft__note {
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
color: var(--theme-text-soft);
|
||||
}
|
||||
.templateRequestDraft__input {
|
||||
width: 100%;
|
||||
padding: 14px 0;
|
||||
border: 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-bottom: 1px solid var(--theme-border-strong);
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.94);
|
||||
color: var(--theme-text-strong);
|
||||
outline: none;
|
||||
font-size: 18px;
|
||||
line-height: 1.5;
|
||||
@@ -1723,7 +1723,7 @@ onUnmounted(() => {
|
||||
border-bottom-color: rgba(96, 165, 250, 0.9);
|
||||
}
|
||||
.templateRequestDraft__input::placeholder {
|
||||
color: rgba(255, 255, 255, 0.34);
|
||||
color: var(--theme-text-faint);
|
||||
}
|
||||
.templateRequestDraft__textarea {
|
||||
min-height: 92px;
|
||||
@@ -1738,8 +1738,8 @@ onUnmounted(() => {
|
||||
flex-wrap: wrap;
|
||||
padding: 10px 12px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid var(--theme-border);
|
||||
background: var(--theme-pill-bg);
|
||||
}
|
||||
.boardTools__left,
|
||||
.boardTools__right {
|
||||
@@ -1758,9 +1758,9 @@ onUnmounted(() => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: var(--theme-surface-soft);
|
||||
color: var(--theme-text);
|
||||
cursor: pointer;
|
||||
transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
|
||||
}
|
||||
@@ -1811,9 +1811,9 @@ onUnmounted(() => {
|
||||
min-width: 48px;
|
||||
padding: 9px 10px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: var(--theme-surface-soft);
|
||||
color: var(--theme-text);
|
||||
cursor: pointer;
|
||||
font-weight: 800;
|
||||
}
|
||||
@@ -1831,7 +1831,7 @@ onUnmounted(() => {
|
||||
border-radius: 28px;
|
||||
background:
|
||||
radial-gradient(circle at top, rgba(96, 165, 250, 0.14), transparent 38%),
|
||||
rgba(11, 18, 32, 0.98);
|
||||
var(--theme-shell-bg);
|
||||
}
|
||||
.exportBoard__title {
|
||||
font-size: 28px;
|
||||
@@ -1869,8 +1869,8 @@ onUnmounted(() => {
|
||||
.row__label {
|
||||
position: relative;
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: var(--theme-surface-soft-3);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -1898,9 +1898,9 @@ onUnmounted(() => {
|
||||
.columnName {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-bottom: 1px solid var(--theme-border-strong);
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.88);
|
||||
color: var(--theme-text);
|
||||
padding: 4px 0;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
@@ -1909,7 +1909,7 @@ onUnmounted(() => {
|
||||
outline: none;
|
||||
}
|
||||
.columnName::placeholder {
|
||||
color: rgba(255, 255, 255, 0.34);
|
||||
color: var(--theme-text-faint);
|
||||
}
|
||||
.columnRemoveText {
|
||||
position: absolute;
|
||||
@@ -1924,15 +1924,15 @@ onUnmounted(() => {
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.56);
|
||||
color: var(--theme-text-soft);
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
}
|
||||
.columnRemoveText:hover {
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface-soft-2);
|
||||
}
|
||||
.columnRemoveText:disabled {
|
||||
opacity: 0.32;
|
||||
@@ -1949,15 +1949,15 @@ onUnmounted(() => {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid var(--theme-border);
|
||||
background: rgba(0, 0, 0, 0.16);
|
||||
font-size: 12px;
|
||||
}
|
||||
.groupName {
|
||||
width: 100%;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: var(--theme-pill-bg);
|
||||
color: var(--theme-text);
|
||||
border-radius: 10px;
|
||||
padding: 8px 10px;
|
||||
font-weight: 900;
|
||||
@@ -1977,15 +1977,15 @@ onUnmounted(() => {
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
color: var(--theme-text-soft);
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
font-weight: 800;
|
||||
}
|
||||
.rowRemoveText:hover {
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface-soft-2);
|
||||
}
|
||||
.rowRemoveText:disabled {
|
||||
opacity: 0.32;
|
||||
@@ -1999,7 +1999,7 @@ onUnmounted(() => {
|
||||
}
|
||||
.row__drop {
|
||||
border-radius: 16px;
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
background: var(--theme-pill-bg);
|
||||
border: 1px solid rgba(255, 255, 255, 0.10);
|
||||
min-height: calc(var(--thumb-size, 80px) + 24px);
|
||||
padding: 10px;
|
||||
@@ -2055,7 +2055,7 @@ onUnmounted(() => {
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(239, 68, 68, 0.32);
|
||||
background: rgba(11, 18, 32, 0.92);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
color: var(--theme-text);
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
font-weight: 900;
|
||||
@@ -2070,14 +2070,14 @@ onUnmounted(() => {
|
||||
width: var(--thumb-size, 80px);
|
||||
height: var(--thumb-size, 80px);
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: var(--theme-surface-soft-2);
|
||||
object-fit: cover;
|
||||
}
|
||||
.sidebar {
|
||||
min-width: 0;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: linear-gradient(180deg, rgba(52, 52, 52, 0.84), rgba(36, 36, 36, 0.8));
|
||||
border: 1px solid var(--theme-border);
|
||||
background: linear-gradient(180deg, color-mix(in srgb, var(--theme-card-bg) 94%, transparent), color-mix(in srgb, var(--theme-card-bg-hover) 88%, transparent));
|
||||
border-radius: 22px;
|
||||
padding: 14px;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||
@@ -2114,7 +2114,7 @@ onUnmounted(() => {
|
||||
.editorSidebar__label {
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
color: rgba(255, 255, 255, 0.52);
|
||||
color: var(--theme-text-faint);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
}
|
||||
@@ -2122,9 +2122,9 @@ onUnmounted(() => {
|
||||
.editorSidebar__textarea {
|
||||
width: 100%;
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid var(--theme-border);
|
||||
background: var(--theme-surface-soft);
|
||||
color: var(--theme-text);
|
||||
padding: 11px 12px;
|
||||
outline: none;
|
||||
resize: vertical;
|
||||
@@ -2135,7 +2135,7 @@ onUnmounted(() => {
|
||||
.editorSidebar__hint {
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: rgba(255, 255, 255, 0.56);
|
||||
color: var(--theme-text-soft);
|
||||
word-break: keep-all;
|
||||
}
|
||||
.editorSidebar__hint--warn {
|
||||
@@ -2147,8 +2147,8 @@ onUnmounted(() => {
|
||||
aspect-ratio: 16 / 9;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: #4c4c4c;
|
||||
border: 1px solid var(--theme-border);
|
||||
background: var(--theme-thumb-fallback-bg);
|
||||
}
|
||||
|
||||
.editorSidebar__thumbFrame--active {
|
||||
@@ -2165,7 +2165,7 @@ onUnmounted(() => {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: rgba(255, 255, 255, 0.36);
|
||||
color: var(--theme-text-faint);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@@ -2184,7 +2184,7 @@ onUnmounted(() => {
|
||||
}
|
||||
.editorSidebar__fileName {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.56);
|
||||
color: var(--theme-text-soft);
|
||||
word-break: break-word;
|
||||
}
|
||||
.editorSidebar__favorite {
|
||||
@@ -2195,9 +2195,9 @@ onUnmounted(() => {
|
||||
width: 100%;
|
||||
padding: 11px 12px;
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
border: 1px solid var(--theme-border);
|
||||
background: var(--theme-pill-bg);
|
||||
color: var(--theme-text);
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -2223,7 +2223,7 @@ onUnmounted(() => {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.74);
|
||||
color: var(--theme-text-muted);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -2285,16 +2285,16 @@ onUnmounted(() => {
|
||||
height: 44px;
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
}
|
||||
.customItemEditor__input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 9px 10px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid var(--theme-border-strong);
|
||||
background: var(--theme-pill-bg);
|
||||
color: var(--theme-text);
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -2303,7 +2303,7 @@ onUnmounted(() => {
|
||||
padding: 14px;
|
||||
border-radius: 16px;
|
||||
border: 1px dashed rgba(255, 255, 255, 0.18);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
background: var(--theme-surface-soft);
|
||||
}
|
||||
.dropzone--active {
|
||||
border-color: rgba(110, 231, 183, 0.6);
|
||||
@@ -2334,7 +2334,7 @@ onUnmounted(() => {
|
||||
padding: 10px 8px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.10);
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
background: var(--theme-pill-bg);
|
||||
}
|
||||
.poolItem--readonly {
|
||||
opacity: 0.58;
|
||||
@@ -2363,7 +2363,7 @@ onUnmounted(() => {
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(255, 255, 255, 0.58);
|
||||
color: var(--theme-text-soft);
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
|
||||
Reference in New Issue
Block a user