refactor: remove animations and emoji, fix layout spacing
- Remove all button shine/hover animations from CSS - Replace all emoji with text labels - Fix header padding to prevent overlap with drawer - Added left padding (80px) to header content - Session name is now fully visible - Simplified empty states without icons - Updated delete button text from icon to 'Del' - Menu button now shows 'Menu' text instead of hamburger icon - All 52 tests passing
This commit is contained in:
+3
-10
@@ -44,15 +44,8 @@ export default function App() {
|
|||||||
height: '40px',
|
height: '40px',
|
||||||
border: '3px solid var(--border)',
|
border: '3px solid var(--border)',
|
||||||
borderTopColor: 'var(--accent)',
|
borderTopColor: 'var(--accent)',
|
||||||
borderRadius: '50%',
|
borderRadius: '50%'
|
||||||
animation: 'spin 1s linear infinite'
|
|
||||||
}} />
|
}} />
|
||||||
<style>{`
|
|
||||||
@keyframes spin {
|
|
||||||
to { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
|
|
||||||
Loading...
|
Loading...
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,11 +65,11 @@ export default function App() {
|
|||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
background: 'var(--bg-secondary)',
|
background: 'var(--bg-secondary)',
|
||||||
border: '1px solid var(--border)',
|
border: '1px solid var(--border)',
|
||||||
fontSize: '20px'
|
fontSize: '18px'
|
||||||
}}
|
}}
|
||||||
title="Open Menu"
|
title="Open Menu"
|
||||||
>
|
>
|
||||||
☰
|
Menu
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ChatWindow
|
<ChatWindow
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
if (!input.trim() || isLoading) return
|
if (!input.trim() || isLoading) return
|
||||||
|
|
||||||
if (!config.endpoint) {
|
if (!config.endpoint) {
|
||||||
setError('Please configure API endpoint in the drawer (☰)')
|
setError('Please configure API endpoint in the drawer')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,18 +123,18 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
|
|
||||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
||||||
let content = `# Conversation Export\n\n`
|
let content = `# Conversation Export\n\n`
|
||||||
content += `**Date:** ${new Date().toLocaleString()}\n`
|
content += `Date: ${new Date().toLocaleString()}\n`
|
||||||
content += `**Endpoint:** ${config.endpoint}\n`
|
content += `Endpoint: ${config.endpoint}\n`
|
||||||
content += `**Model:** ${config.model || 'local-swarm'}\n`
|
content += `Model: ${config.model || 'local-swarm'}\n`
|
||||||
if (config.systemPrompt) {
|
if (config.systemPrompt) {
|
||||||
content += `**System Prompt:** ${config.systemPrompt}\n`
|
content += `System Prompt: ${config.systemPrompt}\n`
|
||||||
}
|
}
|
||||||
content += `**Streaming:** ${config.streaming ? 'Enabled' : 'Disabled'}\n\n`
|
content += `Streaming: ${config.streaming ? 'Enabled' : 'Disabled'}\n\n`
|
||||||
content += `---\n\n`
|
content += `---\n\n`
|
||||||
|
|
||||||
session.messages.forEach(msg => {
|
session.messages.forEach(msg => {
|
||||||
const role = msg.role === 'user' ? '👤 User' : '🤖 Assistant'
|
const role = msg.role === 'user' ? 'User' : 'Assistant'
|
||||||
content += `### ${role}\n\n${msg.content}\n\n`
|
content += `## ${role}\n\n${msg.content}\n\n`
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create and download file
|
// Create and download file
|
||||||
@@ -161,14 +161,15 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
height: '100vh',
|
height: '100vh',
|
||||||
backgroundColor: 'var(--bg-primary)'
|
backgroundColor: 'var(--bg-primary)'
|
||||||
}}>
|
}}>
|
||||||
{/* Header */}
|
{/* Header - Added padding-left to avoid overlap with menu button */}
|
||||||
<header style={{
|
<header style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '16px 20px',
|
padding: '16px 20px 16px 80px',
|
||||||
borderBottom: '1px solid var(--border)',
|
borderBottom: '1px solid var(--border)',
|
||||||
backgroundColor: 'var(--bg-secondary)',
|
backgroundColor: 'var(--bg-secondary)',
|
||||||
boxShadow: '0 1px 3px rgba(0,0,0,0.2)'
|
boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
|
||||||
|
minHeight: '64px'
|
||||||
}}>
|
}}>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<h1 style={{
|
<h1 style={{
|
||||||
@@ -210,7 +211,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
className="secondary small"
|
className="secondary small"
|
||||||
title="Export conversation"
|
title="Export conversation"
|
||||||
>
|
>
|
||||||
📥 Export
|
Export
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -235,11 +236,10 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
padding: '40px'
|
padding: '40px'
|
||||||
}}>
|
}}>
|
||||||
<div style={{ fontSize: '48px', marginBottom: '16px' }}>💬</div>
|
|
||||||
<h2 style={{ fontSize: '20px', marginBottom: '8px', color: 'var(--text-primary)' }}>
|
<h2 style={{ fontSize: '20px', marginBottom: '8px', color: 'var(--text-primary)' }}>
|
||||||
Welcome to Light Chat
|
Welcome to Light Chat
|
||||||
</h2>
|
</h2>
|
||||||
<p>Open the menu (☰) to create a session</p>
|
<p>Open the menu to create a session</p>
|
||||||
</div>
|
</div>
|
||||||
) : session.messages.length === 0 ? (
|
) : session.messages.length === 0 ? (
|
||||||
<div style={{
|
<div style={{
|
||||||
@@ -252,7 +252,6 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
padding: '40px'
|
padding: '40px'
|
||||||
}}>
|
}}>
|
||||||
<div style={{ fontSize: '48px', marginBottom: '16px' }}>👋</div>
|
|
||||||
<h2 style={{ fontSize: '20px', marginBottom: '8px', color: 'var(--text-primary)' }}>
|
<h2 style={{ fontSize: '20px', marginBottom: '8px', color: 'var(--text-primary)' }}>
|
||||||
Start the conversation
|
Start the conversation
|
||||||
</h2>
|
</h2>
|
||||||
@@ -264,8 +263,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
key={index}
|
key={index}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: msg.role === 'user' ? 'flex-end' : 'flex-start',
|
justifyContent: msg.role === 'user' ? 'flex-end' : 'flex-start'
|
||||||
animation: 'fadeIn 0.3s ease-out'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -280,20 +278,16 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
: 'var(--bg-secondary)',
|
: 'var(--bg-secondary)',
|
||||||
color: msg.role === 'user' ? 'white' : 'var(--text-primary)',
|
color: msg.role === 'user' ? 'white' : 'var(--text-primary)',
|
||||||
boxShadow: 'var(--shadow)',
|
boxShadow: 'var(--shadow)',
|
||||||
border: `1px solid ${msg.role === 'user' ? 'var(--accent)' : 'var(--border)'}`,
|
border: `1px solid ${msg.role === 'user' ? 'var(--accent)' : 'var(--border)'}`
|
||||||
position: 'relative'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{
|
<div style={{
|
||||||
fontSize: '12px',
|
fontSize: '12px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
marginBottom: '6px',
|
marginBottom: '6px',
|
||||||
color: msg.role === 'user' ? 'rgba(255,255,255,0.8)' : 'var(--accent)',
|
color: msg.role === 'user' ? 'rgba(255,255,255,0.8)' : 'var(--accent)'
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '6px'
|
|
||||||
}}>
|
}}>
|
||||||
{msg.role === 'user' ? '👤 You' : '🤖 Assistant'}
|
{msg.role === 'user' ? 'You' : 'Assistant'}
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
<div style={{
|
||||||
whiteSpace: 'pre-wrap',
|
whiteSpace: 'pre-wrap',
|
||||||
@@ -313,8 +307,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start'
|
||||||
animation: 'fadeIn 0.3s ease-out'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -325,8 +318,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
backgroundColor: 'var(--bg-secondary)',
|
backgroundColor: 'var(--bg-secondary)',
|
||||||
color: 'var(--text-primary)',
|
color: 'var(--text-primary)',
|
||||||
boxShadow: 'var(--shadow)',
|
boxShadow: 'var(--shadow)',
|
||||||
border: '1px solid var(--accent)',
|
border: '1px solid var(--accent)'
|
||||||
position: 'relative'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{
|
<div style={{
|
||||||
@@ -338,14 +330,13 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: '6px'
|
gap: '6px'
|
||||||
}}>
|
}}>
|
||||||
🤖 Assistant
|
Assistant
|
||||||
<span style={{
|
<span style={{
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
width: '6px',
|
width: '6px',
|
||||||
height: '6px',
|
height: '6px',
|
||||||
backgroundColor: 'var(--accent)',
|
backgroundColor: 'var(--accent)',
|
||||||
borderRadius: '50%',
|
borderRadius: '50%'
|
||||||
animation: 'pulse 1s infinite'
|
|
||||||
}} />
|
}} />
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
<div style={{
|
||||||
@@ -370,14 +361,6 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
gap: '8px',
|
gap: '8px',
|
||||||
padding: '10px 0'
|
padding: '10px 0'
|
||||||
}}>
|
}}>
|
||||||
<span style={{
|
|
||||||
display: 'inline-block',
|
|
||||||
width: '8px',
|
|
||||||
height: '8px',
|
|
||||||
backgroundColor: 'var(--accent)',
|
|
||||||
borderRadius: '50%',
|
|
||||||
animation: 'pulse 1.5s infinite'
|
|
||||||
}} />
|
|
||||||
Thinking...
|
Thinking...
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -392,7 +375,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
borderRadius: 'var(--radius-md)',
|
borderRadius: 'var(--radius-md)',
|
||||||
border: '1px solid var(--error)'
|
border: '1px solid var(--error)'
|
||||||
}}>
|
}}>
|
||||||
⚠️ {error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div ref={messagesEndRef} />
|
<div ref={messagesEndRef} />
|
||||||
@@ -414,7 +397,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
type="text"
|
type="text"
|
||||||
value={input}
|
value={input}
|
||||||
onChange={(e) => setInput(e.target.value)}
|
onChange={(e) => setInput(e.target.value)}
|
||||||
placeholder={config.endpoint ? "Type your message..." : "Configure API endpoint in menu (☰) first"}
|
placeholder={config.endpoint ? "Type your message..." : "Configure API endpoint in menu first"}
|
||||||
disabled={isLoading || !session}
|
disabled={isLoading || !session}
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -430,7 +413,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
className="danger"
|
className="danger"
|
||||||
style={{ padding: '14px 20px' }}
|
style={{ padding: '14px 20px' }}
|
||||||
>
|
>
|
||||||
⏹️ Stop
|
Stop
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
@@ -438,7 +421,7 @@ export function ChatWindow({ session, config, onAddMessage }: ChatWindowProps) {
|
|||||||
disabled={!input.trim() || !session}
|
disabled={!input.trim() || !session}
|
||||||
style={{ padding: '14px 24px' }}
|
style={{ padding: '14px 24px' }}
|
||||||
>
|
>
|
||||||
Send 📤
|
Send
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ describe('SessionDrawer', () => {
|
|||||||
|
|
||||||
it('should render when open', () => {
|
it('should render when open', () => {
|
||||||
render(<SessionDrawer {...defaultProps} />)
|
render(<SessionDrawer {...defaultProps} />)
|
||||||
expect(screen.getByText(/Your Sessions/)).toBeInTheDocument()
|
expect(screen.getByText('Sessions')).toBeInTheDocument()
|
||||||
expect(screen.getByRole('button', { name: /New Session/i })).toBeInTheDocument()
|
expect(screen.getByRole('button', { name: /New Session/i })).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export function SessionDrawer({
|
|||||||
backgroundColor: 'var(--bg-secondary)',
|
backgroundColor: 'var(--bg-secondary)',
|
||||||
borderRight: '1px solid var(--border)',
|
borderRight: '1px solid var(--border)',
|
||||||
transform: isOpen ? 'translateX(0)' : 'translateX(-100%)',
|
transform: isOpen ? 'translateX(0)' : 'translateX(-100%)',
|
||||||
transition: 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
transition: 'transform 0.3s ease',
|
||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@@ -100,12 +100,9 @@ export function SessionDrawer({
|
|||||||
<h2 style={{
|
<h2 style={{
|
||||||
fontSize: '20px',
|
fontSize: '20px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
marginBottom: '16px',
|
marginBottom: '16px'
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '8px'
|
|
||||||
}}>
|
}}>
|
||||||
<span>💬</span> Sessions
|
Sessions
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -263,7 +260,6 @@ export function SessionDrawer({
|
|||||||
padding: '40px 20px',
|
padding: '40px 20px',
|
||||||
color: 'var(--text-muted)'
|
color: 'var(--text-muted)'
|
||||||
}}>
|
}}>
|
||||||
<div style={{ fontSize: '32px', marginBottom: '12px' }}>📝</div>
|
|
||||||
<p style={{ fontSize: '14px' }}>
|
<p style={{ fontSize: '14px' }}>
|
||||||
No sessions yet.<br />Create one to start chatting.
|
No sessions yet.<br />Create one to start chatting.
|
||||||
</p>
|
</p>
|
||||||
@@ -331,7 +327,7 @@ export function SessionDrawer({
|
|||||||
}}
|
}}
|
||||||
title="Delete session"
|
title="Delete session"
|
||||||
>
|
>
|
||||||
🗑️
|
Del
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
+13
-72
@@ -14,12 +14,12 @@
|
|||||||
--success: #10b981;
|
--success: #10b981;
|
||||||
--error: #ef4444;
|
--error: #ef4444;
|
||||||
--warning: #f59e0b;
|
--warning: #f59e0b;
|
||||||
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
|
--shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||||
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
|
--shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.4);
|
||||||
--radius-sm: 6px;
|
--radius-sm: 6px;
|
||||||
--radius-md: 10px;
|
--radius-md: 10px;
|
||||||
--radius-lg: 14px;
|
--radius-lg: 14px;
|
||||||
--transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
--transition: all 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@@ -42,9 +42,9 @@ body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modern Button Styles */
|
/* Button Styles - No Animations */
|
||||||
button {
|
button {
|
||||||
background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%);
|
background: var(--accent);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
@@ -55,48 +55,15 @@ button {
|
|||||||
letter-spacing: 0.3px;
|
letter-spacing: 0.3px;
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
button::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: -100%;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
transparent,
|
|
||||||
rgba(255, 255, 255, 0.2),
|
|
||||||
transparent
|
|
||||||
);
|
|
||||||
transition: left 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover::before {
|
|
||||||
left: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover {
|
button:hover {
|
||||||
transform: translateY(-1px);
|
background: var(--accent-hover);
|
||||||
box-shadow: var(--shadow-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
button:active {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button:disabled {
|
button:disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
transform: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:disabled::before {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Secondary Button Style */
|
/* Secondary Button Style */
|
||||||
@@ -112,7 +79,11 @@ button.secondary:hover {
|
|||||||
|
|
||||||
/* Danger Button Style */
|
/* Danger Button Style */
|
||||||
button.danger {
|
button.danger {
|
||||||
background: linear-gradient(135deg, var(--error) 0%, #dc2626 100%);
|
background: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.danger:hover {
|
||||||
|
background: #dc2626;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Icon Button Style */
|
/* Icon Button Style */
|
||||||
@@ -123,7 +94,7 @@ button.icon-btn {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 18px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Small Button */
|
/* Small Button */
|
||||||
@@ -137,11 +108,10 @@ button.small {
|
|||||||
button.toggle {
|
button.toggle {
|
||||||
background: var(--bg-tertiary);
|
background: var(--bg-tertiary);
|
||||||
border: 2px solid var(--border);
|
border: 2px solid var(--border);
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button.toggle.active {
|
button.toggle.active {
|
||||||
background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%);
|
background: var(--accent);
|
||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +131,6 @@ input, textarea {
|
|||||||
input:focus, textarea:focus {
|
input:focus, textarea:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input::placeholder, textarea::placeholder {
|
input::placeholder, textarea::placeholder {
|
||||||
@@ -191,31 +160,3 @@ input:disabled, textarea:disabled {
|
|||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--border-light);
|
background: var(--border-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Animations */
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from { opacity: 0; transform: translateY(10px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slideIn {
|
|
||||||
from { transform: translateX(-100%); }
|
|
||||||
to { transform: translateX(0); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse {
|
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
50% { opacity: 0.5; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-fadeIn {
|
|
||||||
animation: fadeIn 0.3s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-slideIn {
|
|
||||||
animation: slideIn 0.3s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-pulse {
|
|
||||||
animation: pulse 1.5s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user