feat(ui): Midnight Glass v2 마감 — lucide 아이콘 통일 + 몰입 패널 웨이브 + 팝업 정합
- @mui/icons-material → lucide-react 전환 (23파일, 잔여 0) - VoiceRecordingPanel: 9바 DOM 웨이브 → GradientWave (canvas) - Vanilla 팝업 5종 style.css v2 정합 (글래스 네이비/헤어라인/블루, CSS 변수 주입 구조 유지 — 테마 반응형 보존)
This commit is contained in:
parent
a8a1d6e546
commit
082ed2ef02
30 changed files with 212 additions and 289 deletions
|
|
@ -4,12 +4,7 @@
|
|||
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { Box, Button, IconButton, Dialog, DialogTitle, DialogContent, DialogActions, TextField, Chip, Select, MenuItem, FormControl, InputLabel } from '@mui/material'
|
||||
import AddIcon from '@mui/icons-material/Add'
|
||||
import DeleteIcon from '@mui/icons-material/Delete'
|
||||
import EditIcon from '@mui/icons-material/Edit'
|
||||
import CheckCircleIcon from '@mui/icons-material/CheckCircle'
|
||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow'
|
||||
import LinkIcon from '@mui/icons-material/Link'
|
||||
import { Plus, Trash2, Pencil, CircleCheck, Play, Link } from 'lucide-react'
|
||||
import { MetalCard, PhosphorText, Led, ScreenPanel } from '@d3ro/ui/components/ds'
|
||||
import { PageHeader, EmptyStateCard } from '../components/shared'
|
||||
import { isImeComposingEvent } from '../utils/keyboard'
|
||||
|
|
@ -131,7 +126,7 @@ export function CommandsPage(): React.ReactElement {
|
|||
title={t('commands.title').toUpperCase()}
|
||||
count={t('commands.count', { count: instructions.length }).toUpperCase()}
|
||||
action={
|
||||
<Button variant="contained" startIcon={<AddIcon />} onClick={openAdd} size="small">
|
||||
<Button variant="contained" startIcon={<Plus size={16} />} onClick={openAdd} size="small">
|
||||
{t('commands.add').toUpperCase()}
|
||||
</Button>
|
||||
}
|
||||
|
|
@ -183,7 +178,7 @@ export function CommandsPage(): React.ReactElement {
|
|||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, flex: 1 }}>
|
||||
{isActive ? (
|
||||
<CheckCircleIcon sx={{ fontSize: 16, color: d3roPalette.accent.amber }} />
|
||||
<CircleCheck size={16} style={{ color: d3roPalette.accent.amber }} />
|
||||
) : (
|
||||
<Led color={inst.isBuiltin ? 'amber' : 'green'} size={6} />
|
||||
)}
|
||||
|
|
@ -210,7 +205,7 @@ export function CommandsPage(): React.ReactElement {
|
|||
onClick={() => openEdit(inst)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.accent.amber } }}
|
||||
>
|
||||
<EditIcon sx={{ fontSize: 16 }} />
|
||||
<Pencil size={16} />
|
||||
</IconButton>
|
||||
{!inst.isBuiltin && (
|
||||
<IconButton
|
||||
|
|
@ -218,7 +213,7 @@ export function CommandsPage(): React.ReactElement {
|
|||
onClick={() => handleDelete(inst.id)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.tag.red } }}
|
||||
>
|
||||
<DeleteIcon sx={{ fontSize: 16 }} />
|
||||
<Trash2 size={16} />
|
||||
</IconButton>
|
||||
)}
|
||||
</Box>
|
||||
|
|
@ -360,7 +355,7 @@ function VoiceKeywordsSection({ instructions }: { instructions: CustomInstructio
|
|||
onClick={() => { setEditingRule(rule.instructionId); setKeywordInput('') }}
|
||||
sx={{ p: 0.25, color: d3roPalette.text.muted, '&:hover': { color: d3roPalette.accent.amber } }}
|
||||
>
|
||||
<AddIcon sx={{ fontSize: 14 }} />
|
||||
<Plus size={14} />
|
||||
</IconButton>
|
||||
)}
|
||||
</Box>
|
||||
|
|
@ -456,7 +451,7 @@ function ChainSection({ instructions }: { instructions: CustomInstruction[] }):
|
|||
{t('chain.title').toUpperCase()}
|
||||
</PhosphorText>
|
||||
<Box sx={{ flex: 1, height: '1px', bgcolor: d3roPalette.border.subtle }} />
|
||||
<Button variant="outlined" startIcon={<LinkIcon />} onClick={openAdd} size="small" sx={{ fontSize: d3roTypo.micro.size }}>
|
||||
<Button variant="outlined" startIcon={<Link size={16} />} onClick={openAdd} size="small" sx={{ fontSize: d3roTypo.micro.size }}>
|
||||
{t('chain.add').toUpperCase()}
|
||||
</Button>
|
||||
</Box>
|
||||
|
|
@ -497,15 +492,15 @@ function ChainSection({ instructions }: { instructions: CustomInstruction[] }):
|
|||
<Box sx={{ display: 'flex', gap: 0.5 }}>
|
||||
<IconButton size="small" onClick={() => handleExecute(chain.id)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.tag.green } }}>
|
||||
<PlayArrowIcon sx={{ fontSize: 16 }} />
|
||||
<Play size={16} />
|
||||
</IconButton>
|
||||
<IconButton size="small" onClick={() => openEdit(chain)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.accent.amber } }}>
|
||||
<EditIcon sx={{ fontSize: 16 }} />
|
||||
<Pencil size={16} />
|
||||
</IconButton>
|
||||
<IconButton size="small" onClick={() => handleDelete(chain.id)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.tag.red } }}>
|
||||
<DeleteIcon sx={{ fontSize: 16 }} />
|
||||
<Trash2 size={16} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
@ -563,12 +558,12 @@ function ChainSection({ instructions }: { instructions: CustomInstruction[] }):
|
|||
)}
|
||||
<IconButton size="small" onClick={() => removeStep(idx)} disabled={formSteps.length <= 1}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.tag.red } }}>
|
||||
<DeleteIcon sx={{ fontSize: 16 }} />
|
||||
<Trash2 size={16} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
))}
|
||||
|
||||
<Button onClick={addStep} startIcon={<AddIcon />} size="small" sx={{ mt: 1 }}>
|
||||
<Button onClick={addStep} startIcon={<Plus size={16} />} size="small" sx={{ mt: 1 }}>
|
||||
{t('chain.addStep')}
|
||||
</Button>
|
||||
</DialogContent>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { Box, TextField, Button, IconButton, Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'
|
||||
import AddIcon from '@mui/icons-material/Add'
|
||||
import DeleteIcon from '@mui/icons-material/Delete'
|
||||
import EditIcon from '@mui/icons-material/Edit'
|
||||
import { Plus, Trash2, Pencil } from 'lucide-react'
|
||||
import { MetalCard, PhosphorText } from '@d3ro/ui/components/ds'
|
||||
import { PageHeader, SearchInput, EmptyStateCard } from '../components/shared'
|
||||
import { d3roPalette, d3roFontMono, d3roTypo } from '@d3ro/ui/theme'
|
||||
|
|
@ -73,7 +71,7 @@ export function DictionaryPage(): React.ReactElement {
|
|||
title={t('dictionary.title').toUpperCase()}
|
||||
count={t('dictionary.words', { count: data?.total ?? 0 }).toUpperCase()}
|
||||
action={
|
||||
<Button variant="contained" startIcon={<AddIcon />} onClick={openAdd} size="small">
|
||||
<Button variant="contained" startIcon={<Plus size={16} />} onClick={openAdd} size="small">
|
||||
{t('dictionary.add').toUpperCase()}
|
||||
</Button>
|
||||
}
|
||||
|
|
@ -114,11 +112,11 @@ export function DictionaryPage(): React.ReactElement {
|
|||
<Box sx={{ display: 'flex', gap: 0.5 }}>
|
||||
<IconButton size="small" onClick={() => openEdit(entry)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.accent.amber } }}>
|
||||
<EditIcon sx={{ fontSize: 16 }} />
|
||||
<Pencil size={16} />
|
||||
</IconButton>
|
||||
<IconButton size="small" onClick={() => { window.electronAPI.dictionary.delete({ id: entry.id }); loadData() }}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.tag.red } }}>
|
||||
<DeleteIcon sx={{ fontSize: 16 }} />
|
||||
<Trash2 size={16} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import { useState, useEffect, useCallback, useMemo } from 'react'
|
||||
import { Box, Chip, IconButton, Tooltip } from '@mui/material'
|
||||
import FileDownloadIcon from '@mui/icons-material/FileDownload'
|
||||
import { Download } from 'lucide-react'
|
||||
import { PhosphorText } from '@d3ro/ui/components/ds'
|
||||
import { d3roPalette, d3roTypo, d3roFontMono, d3roRadius } from '@d3ro/ui/theme'
|
||||
import { useI18n } from '@d3ro/i18n'
|
||||
|
|
@ -96,7 +96,7 @@ export function HistoryPage(): React.ReactElement {
|
|||
onClick={handleExport}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.accent.amber } }}
|
||||
>
|
||||
<FileDownloadIcon sx={{ fontSize: 18 }} />
|
||||
<Download size={18} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<PhosphorText variant="meta" sx={{ color: d3roPalette.text.dimLabel }}>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,7 @@
|
|||
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { Box, TextField, IconButton, Tooltip, LinearProgress } from '@mui/material'
|
||||
import AddIcon from '@mui/icons-material/Add'
|
||||
import DeleteIcon from '@mui/icons-material/Delete'
|
||||
import RefreshIcon from '@mui/icons-material/Refresh'
|
||||
import SearchIcon from '@mui/icons-material/Search'
|
||||
import SendIcon from '@mui/icons-material/Send'
|
||||
import DescriptionIcon from '@mui/icons-material/Description'
|
||||
import { Plus, Trash2, RefreshCw, Search, Send, FileText } from 'lucide-react'
|
||||
import { MetalCard, PhosphorText, Led, PhysicalButton, ScreenPanel } from '@d3ro/ui/components/ds'
|
||||
import { PageHeader, EmptyStateCard } from '../components/shared'
|
||||
import { isImeComposingEvent } from '../utils/keyboard'
|
||||
|
|
@ -96,7 +91,7 @@ export function KnowledgeBasePage(): React.ReactElement {
|
|||
title={t('rag.title').toUpperCase()}
|
||||
action={
|
||||
<PhysicalButton size="small" onClick={handleAddDocument} disabled={adding}>
|
||||
<AddIcon sx={{ fontSize: 14, mr: 0.5 }} /> {adding ? t('rag.adding') : t('rag.addDocument')}
|
||||
<Plus size={14} style={{ marginRight: 4 }} /> {adding ? t('rag.adding') : t('rag.addDocument')}
|
||||
</PhysicalButton>
|
||||
}
|
||||
/>
|
||||
|
|
@ -160,7 +155,7 @@ export function KnowledgeBasePage(): React.ReactElement {
|
|||
{documents.map((doc) => (
|
||||
<MetalCard key={doc.id}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
<DescriptionIcon sx={{ fontSize: 20, color: d3roPalette.text.inactive }} />
|
||||
<FileText size={20} style={{ color: d3roPalette.text.inactive }} />
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<PhosphorText variant="body">{doc.fileName}</PhosphorText>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mt: 0.25 }}>
|
||||
|
|
@ -176,13 +171,13 @@ export function KnowledgeBasePage(): React.ReactElement {
|
|||
<Tooltip title={t('rag.reindex')}>
|
||||
<IconButton size="small" onClick={() => handleReindex(doc.id)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.accent.amber } }}>
|
||||
<RefreshIcon sx={{ fontSize: 16 }} />
|
||||
<RefreshCw size={16} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={t('common.delete')}>
|
||||
<IconButton size="small" onClick={() => handleRemoveDocument(doc.id)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.tag.red } }}>
|
||||
<DeleteIcon sx={{ fontSize: 16 }} />
|
||||
<Trash2 size={16} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
|
@ -198,7 +193,7 @@ export function KnowledgeBasePage(): React.ReactElement {
|
|||
|
||||
<MetalCard>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<SearchIcon sx={{ fontSize: 20, color: d3roPalette.text.inactive }} />
|
||||
<Search size={20} style={{ color: d3roPalette.text.inactive }} />
|
||||
<TextField
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
|
|
@ -219,7 +214,7 @@ export function KnowledgeBasePage(): React.ReactElement {
|
|||
/>
|
||||
<IconButton onClick={handleQuery} disabled={!query.trim() || querying}
|
||||
sx={{ color: query.trim() ? d3roPalette.accent.amber : d3roPalette.text.inactive }}>
|
||||
<SendIcon sx={{ fontSize: 20 }} />
|
||||
<Send size={20} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</MetalCard>
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ import {
|
|||
Snackbar,
|
||||
Alert,
|
||||
} from '@mui/material'
|
||||
import AddIcon from '@mui/icons-material/Add'
|
||||
import StopIcon from '@mui/icons-material/Stop'
|
||||
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord'
|
||||
import { Plus, Square, Circle } from 'lucide-react'
|
||||
import { MetalCard, PhosphorText, Led, PhysicalButton, ScreenPanel } from '@d3ro/ui/components/ds'
|
||||
import { MeetingDetailTabs } from '../components/meeting/MeetingDetailTabs'
|
||||
import { EditableSegment } from '../components/meeting/EditableSegment'
|
||||
|
|
@ -229,7 +227,7 @@ export function MeetingModePage(): React.ReactElement {
|
|||
count={totalSessions > 0 ? t('meeting.sessions', { count: totalSessions }) : undefined}
|
||||
action={
|
||||
<PhysicalButton size="small" onClick={handleStartRecording}>
|
||||
<AddIcon sx={{ fontSize: 16, mr: 0.5 }} />
|
||||
<Plus size={16} style={{ marginRight: 4 }} />
|
||||
{t('meeting.newMeeting')}
|
||||
</PhysicalButton>
|
||||
}
|
||||
|
|
@ -344,7 +342,7 @@ export function MeetingModePage(): React.ReactElement {
|
|||
{/* 상단 바 */}
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
<FiberManualRecordIcon sx={{ color: d3roPalette.tag.red, fontSize: 16, animation: 'pulse 1s infinite' }} />
|
||||
<Circle size={16} fill="currentColor" style={{ color: d3roPalette.tag.red, animation: 'pulse 1s infinite' }} />
|
||||
<PhosphorText variant="label" sx={{ fontFamily: d3roFontMono }}>
|
||||
{formatTime(elapsedMs)}
|
||||
</PhosphorText>
|
||||
|
|
@ -354,7 +352,7 @@ export function MeetingModePage(): React.ReactElement {
|
|||
</Box>
|
||||
{!isProcessing && (
|
||||
<PhysicalButton size="small" color="error" onClick={handleStopRecording}>
|
||||
<StopIcon sx={{ fontSize: 16, mr: 0.5 }} />
|
||||
<Square size={16} style={{ marginRight: 4 }} />
|
||||
{t('meeting.stopRecording')}
|
||||
</PhysicalButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,7 @@
|
|||
|
||||
import { useState, useEffect, useCallback, useRef } from 'react'
|
||||
import { Alert, Box, IconButton, Snackbar, TextField, Tooltip } from '@mui/material'
|
||||
import MicIcon from '@mui/icons-material/Mic'
|
||||
import StopIcon from '@mui/icons-material/Stop'
|
||||
import SendIcon from '@mui/icons-material/Send'
|
||||
import DeleteSweepIcon from '@mui/icons-material/DeleteSweep'
|
||||
import CancelIcon from '@mui/icons-material/Cancel'
|
||||
import { Mic, Square, Send, Trash2, XCircle } from 'lucide-react'
|
||||
import { MetalCard, PhosphorText, Led, PhysicalButton, ScreenPanel, InstrumentPanel } from '@d3ro/ui/components/ds'
|
||||
import { PageHeader } from '../components/shared'
|
||||
import { VoiceRecordingPanel } from '../components/voice-conversation/VoiceRecordingPanel'
|
||||
|
|
@ -248,7 +244,7 @@ export function VoiceConversationPage(): React.ReactElement {
|
|||
{messages.length > 0 && (
|
||||
<Tooltip title={t('conversation.clearHistory')}>
|
||||
<IconButton size="small" onClick={handleClearHistory} sx={{ color: d3roPalette.text.inactive }}>
|
||||
<DeleteSweepIcon sx={{ fontSize: 18 }} />
|
||||
<Trash2 size={18} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
|
@ -378,7 +374,7 @@ export function VoiceConversationPage(): React.ReactElement {
|
|||
{/* 녹음 버튼 */}
|
||||
{!isActive ? (
|
||||
<PhysicalButton onClick={handleStartSession} sx={{ minWidth: 48, px: 2 }}>
|
||||
<MicIcon sx={{ fontSize: 20 }} />
|
||||
<Mic size={20} />
|
||||
</PhysicalButton>
|
||||
) : state === 'listening' ? (
|
||||
<PhysicalButton
|
||||
|
|
@ -386,15 +382,15 @@ export function VoiceConversationPage(): React.ReactElement {
|
|||
onClick={isRealtime ? handleStopSession : handleFinishListening}
|
||||
sx={{ minWidth: 48, px: 2 }}
|
||||
>
|
||||
<StopIcon sx={{ fontSize: 20 }} />
|
||||
<Square size={20} />
|
||||
</PhysicalButton>
|
||||
) : state === 'thinking' || state === 'speaking' ? (
|
||||
<PhysicalButton onClick={handleCancelResponse} sx={{ minWidth: 48, px: 2 }}>
|
||||
<CancelIcon sx={{ fontSize: 20 }} />
|
||||
<XCircle size={20} />
|
||||
</PhysicalButton>
|
||||
) : (
|
||||
<PhysicalButton onClick={handleFinishListening} sx={{ minWidth: 48, px: 2 }}>
|
||||
<MicIcon sx={{ fontSize: 20 }} />
|
||||
<Mic size={20} />
|
||||
</PhysicalButton>
|
||||
)}
|
||||
|
||||
|
|
@ -439,7 +435,7 @@ export function VoiceConversationPage(): React.ReactElement {
|
|||
: d3roPalette.text.inactive,
|
||||
}}
|
||||
>
|
||||
<SendIcon sx={{ fontSize: 20 }} />
|
||||
<Send size={20} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue