diff --git a/src/renderer.js b/src/renderer.js
index 833b8b5..e28dd6d 100644
--- a/src/renderer.js
+++ b/src/renderer.js
@@ -381,7 +381,7 @@ class TabManager {
try {
// Check if libraries are available
if (!marked || !DOMPurify) {
- preview.innerHTML = '
Error: Required libraries (marked/DOMPurify) not loaded. Check internet connection.
';
+ preview.innerHTML = '⚠️
Libraries Not Loaded
Required libraries (marked/DOMPurify) could not be loaded. Please check your installation.
';
return;
}
const html = marked.parse(tab.content);
diff --git a/src/styles-modern.css b/src/styles-modern.css
index f38a7ef..5bb51c4 100644
--- a/src/styles-modern.css
+++ b/src/styles-modern.css
@@ -39,13 +39,7 @@
--transition-ease: cubic-bezier(0.4, 0, 0.2, 1);
}
-/* Reset & Base */
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
+/* Base styles - Reset is in styles.css */
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
overflow: hidden;
diff --git a/src/styles-sidebar.css b/src/styles-sidebar.css
index c32aad6..6b3f36a 100644
--- a/src/styles-sidebar.css
+++ b/src/styles-sidebar.css
@@ -57,6 +57,11 @@
box-shadow: inset 3px 0 0 var(--primary-dark, #5661b3);
}
+.sidebar-icon:focus-visible {
+ outline: 2px solid var(--primary-dark, #5661b3);
+ outline-offset: 2px;
+}
+
.sidebar-panel {
width: 280px;
background: var(--gray-50, #f9fafb);
diff --git a/src/styles.css b/src/styles.css
index acd1123..9f48055 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -277,6 +277,165 @@ body {
line-height: 1.6;
}
+/* ============================================
+ Error & Loading State Components
+ ============================================ */
+
+/* Preview Error State */
+.preview-error {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 40px 20px;
+ color: #dc3545;
+ text-align: center;
+ min-height: 200px;
+}
+
+.preview-error-icon {
+ font-size: 48px;
+ margin-bottom: 16px;
+ opacity: 0.8;
+}
+
+.preview-error-title {
+ font-size: 18px;
+ font-weight: 600;
+ margin-bottom: 8px;
+}
+
+.preview-error-message {
+ font-size: 14px;
+ color: #666;
+ max-width: 400px;
+ line-height: 1.5;
+}
+
+/* Loading State */
+.loading-spinner {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ border: 2px solid var(--gray-200, #e5e7eb);
+ border-top-color: var(--primary-dark, #5661b3);
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+}
+
+@keyframes spin {
+ to { transform: rotate(360deg); }
+}
+
+.loading-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(255, 255, 255, 0.8);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ gap: 12px;
+ z-index: 100;
+}
+
+.loading-text {
+ font-size: 14px;
+ color: var(--gray-600, #4b5563);
+}
+
+/* Skeleton Loading */
+.skeleton {
+ background: linear-gradient(90deg, var(--gray-100, #f3f4f6) 25%, var(--gray-200, #e5e7eb) 50%, var(--gray-100, #f3f4f6) 75%);
+ background-size: 200% 100%;
+ animation: shimmer 1.5s infinite;
+ border-radius: 4px;
+}
+
+@keyframes shimmer {
+ 0% { background-position: 200% 0; }
+ 100% { background-position: -200% 0; }
+}
+
+.skeleton-text {
+ height: 14px;
+ margin-bottom: 8px;
+}
+
+.skeleton-text:last-child {
+ width: 60%;
+}
+
+/* Success State */
+.success-message {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 16px;
+ background: #d1fae5;
+ color: #065f46;
+ border-radius: 6px;
+ font-size: 14px;
+}
+
+.success-message svg {
+ width: 18px;
+ height: 18px;
+ flex-shrink: 0;
+}
+
+/* Warning State */
+.warning-message {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 16px;
+ background: #fef3c7;
+ color: #92400e;
+ border-radius: 6px;
+ font-size: 14px;
+}
+
+.warning-message svg {
+ width: 18px;
+ height: 18px;
+ flex-shrink: 0;
+}
+
+/* Info State */
+.info-message {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 16px;
+ background: #dbeafe;
+ color: #1e40af;
+ border-radius: 6px;
+ font-size: 14px;
+}
+
+.info-message svg {
+ width: 18px;
+ height: 18px;
+ flex-shrink: 0;
+}
+
+/* Dark theme adjustments for states */
+body[class*="dark"] .preview-error-message {
+ color: #9ca3af;
+}
+
+body[class*="dark"] .loading-overlay {
+ background: rgba(0, 0, 0, 0.8);
+}
+
+body[class*="dark"] .loading-text {
+ color: #9ca3af;
+}
+
/* Bottom Panel (REPL Output) */
.bottom-panel { display: flex; flex-direction: column; border-top: 1px solid var(--gray-200, #e5e7eb); flex-shrink: 0; }
.bottom-panel.collapsed { height: 0; overflow: hidden; border: none; }