smaller fixes

This commit is contained in:
Alexander Medvedev 2026-08-24 22:15:04 +02:00
parent 6cfca656e8
commit fe14649ff6
8 changed files with 265 additions and 432 deletions

View File

@ -2034,6 +2034,14 @@ h3 {
font-size: 0.92rem; font-size: 0.92rem;
line-height: 1.6; line-height: 1.6;
color: var(--text); color: var(--text);
position: relative;
}
.plugin-recent-update-body.is-clamped {
max-height: 90px;
overflow: hidden;
mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
-webkit-mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
} }
.plugin-recent-update-body p:last-child { .plugin-recent-update-body p:last-child {
@ -2047,6 +2055,27 @@ h3 {
margin: 0; margin: 0;
} }
.plugin-recent-update-more-btn {
display: inline-flex;
align-items: center;
gap: 4px;
background: none;
border: none;
color: var(--primary);
padding: 8px 0 0 0;
cursor: pointer;
font-size: 0.85rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
transition: opacity 0.15s ease, transform 0.15s ease;
}
.plugin-recent-update-more-btn:hover {
opacity: 0.85;
transform: translateX(2px);
}
.lightbox-overlay { .lightbox-overlay {
position: fixed; position: fixed;
/* Fixes it to the screen, not the page */ /* Fixes it to the screen, not the page */

View File

@ -1,7 +1,7 @@
import React, { createContext, useContext, useState, useEffect } from 'react'; import React, { createContext, useContext, useState, useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, NavLink, useNavigate, Outlet, Navigate, useLocation } from 'react-router-dom'; import { BrowserRouter as Router, Routes, Route, Link, NavLink, useNavigate, Outlet, Navigate, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Search, Store, Package, Globe, PlusCircle } from 'lucide-react'; import { Search, Store } from 'lucide-react';
import Home from './pages/Home'; import Home from './pages/Home';
import PluginDetail from './pages/PluginDetail'; import PluginDetail from './pages/PluginDetail';
import LoginPage from './pages/auth/LoginPage'; import LoginPage from './pages/auth/LoginPage';
@ -176,17 +176,16 @@ const DeveloperStudioNavbar = ({ user }: any) => {
const toggleMenu = () => setIsMenuOpen(!isMenuOpen); const toggleMenu = () => setIsMenuOpen(!isMenuOpen);
return ( return (
<header className="dashboard-app-header"> <nav className="navbar">
<div className="dashboard-app-header-inner"> <div className="logo" style={{ display: 'flex', alignItems: 'center' }}>
{/* Brand */} <Link to="/dashboard/plugins" onClick={() => setIsMenuOpen(false)}>
<Link to="/dashboard/plugins" className="dashboard-app-brand" onClick={() => setIsMenuOpen(false)}> <img src="/icon.png" alt="Market Logo" style={{ height: '50px', marginRight: '0px', verticalAlign: 'middle' }} />
<img src="/icon.png" alt="Market Logo" className="dashboard-app-logo" /> <span>STUDIO</span>
<span className="dashboard-app-title">DEVELOPER <span>STUDIO</span></span>
</Link> </Link>
</div>
{/* Mobile menu toggle button */} <button className="mobile-menu-toggle" onClick={toggleMenu} aria-label="Toggle menu">
<button className="dashboard-mobile-toggle" onClick={toggleMenu} aria-label="Toggle navigation menu"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
{isMenuOpen ? ( {isMenuOpen ? (
<path d="M18 6L6 18M6 6l12 12" /> <path d="M18 6L6 18M6 6l12 12" />
) : ( ) : (
@ -195,54 +194,57 @@ const DeveloperStudioNavbar = ({ user }: any) => {
</svg> </svg>
</button> </button>
{/* Navigation & Actions */} <div className={`nav-content ${isMenuOpen ? 'open' : ''}`}>
<div className={`dashboard-app-nav-wrap ${isMenuOpen ? 'open' : ''}`}> <div className="nav-links">
<nav className="dashboard-app-nav"> <NavLink to="/dashboard/plugins" onClick={() => setIsMenuOpen(false)}>Plugins</NavLink>
<NavLink <NavLink to="/dashboard/audience" onClick={() => setIsMenuOpen(false)}>Audience</NavLink>
to="/dashboard/plugins" <NavLink to="/dashboard/add-plugin" onClick={() => setIsMenuOpen(false)}>Publish</NavLink>
className={({ isActive }) => `dashboard-app-nav-link ${isActive ? 'active' : ''}`} {user && (user.role === 'admin' || user.role === 'moderator') && (
onClick={() => setIsMenuOpen(false)} <NavLink to="/staff" onClick={() => setIsMenuOpen(false)}>Staff</NavLink>
> )}
<Package size={16} /> </div>
<span>Plugins</span>
</NavLink>
<NavLink
to="/dashboard/audience"
className={({ isActive }) => `dashboard-app-nav-link ${isActive ? 'active' : ''}`}
onClick={() => setIsMenuOpen(false)}
>
<Globe size={16} />
<span>Audience</span>
</NavLink>
<NavLink
to="/dashboard/add-plugin"
className={({ isActive }) => `dashboard-app-nav-link ${isActive ? 'active' : ''}`}
onClick={() => setIsMenuOpen(false)}
>
<PlusCircle size={16} />
<span>Publish</span>
</NavLink>
</nav>
<div className="dashboard-app-actions"> <div className="nav-actions" style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: '1.25rem' }}>
<Link to="/" className="dashboard-action-link store-link" onClick={() => setIsMenuOpen(false)} title="Return to Marketplace"> <Link
<Store size={15} /> to="/"
onClick={() => setIsMenuOpen(false)}
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '6px',
color: 'var(--primary)',
textDecoration: 'none',
fontWeight: 600,
fontSize: '0.85rem',
textTransform: 'uppercase',
letterSpacing: '0.03em',
padding: '6px 14px',
borderRadius: '20px',
background: 'rgba(255, 117, 24, 0.1)',
border: '1px solid rgba(255, 117, 24, 0.3)',
transition: 'all 0.2s ease'
}}
onMouseEnter={e => {
e.currentTarget.style.background = 'rgba(255, 117, 24, 0.2)';
e.currentTarget.style.borderColor = 'var(--primary)';
}}
onMouseLeave={e => {
e.currentTarget.style.background = 'rgba(255, 117, 24, 0.1)';
e.currentTarget.style.borderColor = 'rgba(255, 117, 24, 0.3)';
}}
>
<Store size={14} />
<span>Marketplace</span> <span>Marketplace</span>
</Link> </Link>
{user && (user.role === 'admin' || user.role === 'moderator') && (
<NavLink to="/staff" className="dashboard-action-link" onClick={() => setIsMenuOpen(false)}> {user ? (
<span>Staff</span> <NavLink to="/settings" className="nav-user-link" onClick={() => setIsMenuOpen(false)}>{user.username}</NavLink>
</NavLink> ) : (
)} <Link to="/login" className="btn btn-secondary" onClick={() => setIsMenuOpen(false)}>Login</Link>
{user && (
<NavLink to="/settings" className="dashboard-user-link" onClick={() => setIsMenuOpen(false)}>
<span>{user.username}</span>
</NavLink>
)} )}
</div> </div>
</div> </div>
</div> </nav>
</header>
); );
}; };

View File

@ -6,7 +6,7 @@ import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm'; import remarkGfm from 'remark-gfm';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import SEO from '../components/SEO'; import SEO from '../components/SEO';
import { Sparkles, History } from 'lucide-react'; import { Sparkles, History, ChevronRight } from 'lucide-react';
const getYoutubeVideoId = (url: string) => { const getYoutubeVideoId = (url: string) => {
if (!url) return null; if (!url) return null;
@ -680,7 +680,10 @@ const PluginDetail = () => {
</div> </div>
)} )}
{Array.isArray(plugin.versions) && plugin.versions.length > 0 && ( {Array.isArray(plugin.versions) && plugin.versions.length > 0 && (() => {
const latest = plugin.versions[0];
const isLong = Boolean(latest.release_notes && (latest.release_notes.length > 200 || latest.release_notes.split('\n').length > 4));
return (
<div className="plugin-recent-update"> <div className="plugin-recent-update">
<div className="plugin-recent-update-header"> <div className="plugin-recent-update-header">
<div className="plugin-recent-update-title-group"> <div className="plugin-recent-update-title-group">
@ -689,11 +692,11 @@ const PluginDetail = () => {
What's New What's New
</h3> </h3>
<span className="plugin-recent-update-badge"> <span className="plugin-recent-update-badge">
v{plugin.versions[0].version} v{latest.version}
</span> </span>
{plugin.versions[0].created_at && ( {latest.created_at && (
<span className="plugin-recent-update-date"> <span className="plugin-recent-update-date">
{formatDate(plugin.versions[0].created_at)} {formatDate(latest.created_at)}
</span> </span>
)} )}
</div> </div>
@ -708,10 +711,10 @@ const PluginDetail = () => {
</button> </button>
)} )}
</div> </div>
<div className="plugin-recent-update-body markdown-content"> <div className={`plugin-recent-update-body markdown-content ${isLong ? 'is-clamped' : ''}`}>
{plugin.versions[0].release_notes ? ( {latest.release_notes ? (
<ReactMarkdown remarkPlugins={[remarkGfm]}> <ReactMarkdown remarkPlugins={[remarkGfm]}>
{plugin.versions[0].release_notes} {latest.release_notes}
</ReactMarkdown> </ReactMarkdown>
) : ( ) : (
<p className="plugin-recent-update-empty"> <p className="plugin-recent-update-empty">
@ -719,8 +722,19 @@ const PluginDetail = () => {
</p> </p>
)} )}
</div> </div>
</div> {isLong && (
<button
type="button"
className="plugin-recent-update-more-btn"
onClick={() => setChangelogOpen(true)}
>
<span>View More</span>
<ChevronRight size={14} />
</button>
)} )}
</div>
);
})()}
{/* DESCRIPTION */} {/* DESCRIPTION */}
<div className="markdown-content"> <div className="markdown-content">

View File

@ -1,6 +1,7 @@
import React, { useState } from 'react'; import React, { useState, useRef } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Turnstile } from '@marsidev/react-turnstile';
import api from '../../api'; import api from '../../api';
const ForgotPasswordPage = () => { const ForgotPasswordPage = () => {
@ -11,6 +12,8 @@ const ForgotPasswordPage = () => {
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const [emailTouched, setEmailTouched] = useState(false); const [emailTouched, setEmailTouched] = useState(false);
const [emailValid, setEmailValid] = useState<boolean | null>(null); const [emailValid, setEmailValid] = useState<boolean | null>(null);
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
const turnstileRef = useRef<any>(null);
const validateEmail = (email: string) => const validateEmail = (email: string) =>
Boolean(String(email).toLowerCase().match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)); Boolean(String(email).toLowerCase().match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/));
@ -43,11 +46,38 @@ const ForgotPasswordPage = () => {
setIsSubmitting(true); setIsSubmitting(true);
setError(''); setError('');
setMessage(''); setMessage('');
let currentToken = captchaToken;
if (!currentToken && turnstileRef.current) {
try { try {
await api.post('/auth/forgot-password', { email }); currentToken = await turnstileRef.current.getResponsePromise(2000);
} catch (err) {
try {
turnstileRef.current.reset();
currentToken = await turnstileRef.current.getResponsePromise(4000);
} catch (resetErr) {
console.error('Turnstile verification failed:', resetErr);
}
}
}
if (!currentToken) {
setError('Please complete the security check.');
setIsSubmitting(false);
return;
}
try {
await api.post('/auth/forgot-password', { email, captchaToken: currentToken });
setMessage('If an account exists with that email, a reset link has been sent.'); setMessage('If an account exists with that email, a reset link has been sent.');
} catch (err: any) { } catch (err: any) {
setError(err.response?.data?.error || 'Something went wrong. Please try again.'); setError(err.response?.data?.error || 'Something went wrong. Please try again.');
if (turnstileRef.current) {
try {
turnstileRef.current.reset();
setCaptchaToken(null);
} catch (_) {}
}
} finally { } finally {
setIsSubmitting(false); setIsSubmitting(false);
} }
@ -272,6 +302,17 @@ const ForgotPasswordPage = () => {
)} )}
</div> </div>
<div style={{ display: 'flex', justifyContent: 'center', marginBottom: '20px', marginTop: '4px' }}>
<Turnstile
ref={turnstileRef}
siteKey="0x4AAAAAAClcSibyhKfR0H6o"
onSuccess={(token) => setCaptchaToken(token)}
onExpire={() => setCaptchaToken(null)}
onError={() => setCaptchaToken(null)}
options={{ theme: 'light', appearance: 'interaction-only' } as any}
/>
</div>
<button className="submit-btn" type="submit" disabled={isSubmitting}> <button className="submit-btn" type="submit" disabled={isSubmitting}>
{isSubmitting ? <><span className="spinner" />Sending...</> : 'Send reset link'} {isSubmitting ? <><span className="spinner" />Sending...</> : 'Send reset link'}
</button> </button>

View File

@ -1,16 +1,16 @@
:root { :root {
--dash-bg: #F6F8FA; --dash-bg: #0A0A0A;
--dash-surface: #FFFFFF; --dash-surface: #141414;
--dash-surface-soft: #F0F2F5; /* New: for softer backgrounds */ --dash-surface-soft: #1A1D24;
--dash-border: #E1E4E8; --dash-border: #2A2A2A;
--dash-text: #24292E; --dash-text: #EAEAEA;
--dash-text-muted: #586069; --dash-text-muted: #888888;
--dash-text-secondary: #6A737D; /* New: for secondary text */ --dash-text-secondary: #A3A3A3;
--dash-primary: #0366D6; /* Stripe-like blue */ --dash-primary: #FF7518;
--dash-primary-light: #EBF5FF; /* New: Light version of primary color */ --dash-primary-light: rgba(255, 117, 24, 0.15);
--dash-accent: #FF7518; /* Keep a hint of Pumpkin */ --dash-accent: #FF7518;
--dash-hover: #EAEFF4; /* New: for hover states */ --dash-hover: #1F232D;
--dash-shadow: 0 1px 3px rgba(0,0,0,0.08); /* New: for subtle shadows */ --dash-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
} }
/* Dashboard Layout Container */ /* Dashboard Layout Container */
@ -18,8 +18,8 @@
min-height: 100vh; min-height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: var(--dash-bg, #F6F8FA); background-color: var(--dash-bg, #0A0A0A);
color: var(--dash-text, #24292E); color: var(--dash-text, #EAEAEA);
} }
.dashboard-content { .dashboard-content {
@ -27,293 +27,28 @@
max-width: 1400px; max-width: 1400px;
width: 100%; width: 100%;
margin: 0 auto; margin: 0 auto;
padding: 0 2rem 2.5rem 2rem; padding: 2.5rem 2.5rem 4rem 2.5rem;
box-sizing: border-box; box-sizing: border-box;
} }
/* Dashboard Top App Header (replaces main navbar in dev menu) */ .dashboard-container:has(.mp-root),
.dashboard-app-header { .dashboard-container:has(.ap-root) {
background: var(--dash-surface); height: 100vh;
border-bottom: 1px solid var(--dash-border); overflow: hidden;
padding: 0.75rem 2rem;
margin-bottom: 2rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
position: sticky;
top: 0;
z-index: 1000;
transition: background-color 0.2s ease, border-color 0.2s ease;
} }
.dashboard-app-header-inner { .dashboard-container:has(.mp-root) .dashboard-content,
max-width: 1400px; .dashboard-container:has(.ap-root) .dashboard-content {
margin: 0 auto; padding: 0;
max-width: 100%;
overflow: hidden;
height: 100%;
display: flex; display: flex;
align-items: center;
justify-content: space-between;
gap: 1.5rem;
}
.dashboard-app-brand {
display: flex;
align-items: center;
gap: 0.75rem;
text-decoration: none !important;
color: var(--dash-text);
font-weight: 800;
font-size: 1.1rem;
letter-spacing: -0.3px;
flex-shrink: 0;
}
.dashboard-app-logo {
height: 32px;
width: auto;
object-fit: contain;
}
.dashboard-app-title span {
color: var(--dash-accent, #ff7518);
}
.dashboard-app-nav-wrap {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1;
margin-left: 2rem;
}
.dashboard-app-nav {
display: flex;
align-items: center;
gap: 0.4rem;
}
.dashboard-app-nav-link {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
border-radius: 6px;
font-size: 0.9rem;
font-weight: 500;
color: var(--dash-text-muted);
text-decoration: none !important;
transition: all 0.15s ease;
}
.dashboard-app-nav-link:hover {
color: var(--dash-text);
background: var(--dash-surface-soft);
}
.dashboard-app-nav-link.active {
color: var(--dash-primary);
background: var(--dash-primary-light);
font-weight: 600;
}
.dashboard-app-actions {
display: flex;
align-items: center;
gap: 0.75rem;
}
.dashboard-action-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
text-decoration: none !important;
color: var(--dash-text-secondary);
border: 1px solid var(--dash-border);
background: var(--dash-surface);
transition: all 0.15s ease;
}
.dashboard-action-link:hover {
color: var(--dash-text);
background: var(--dash-surface-soft);
border-color: var(--dash-text-muted);
}
.dashboard-action-link.store-link {
background: transparent;
color: var(--dash-accent, #ff7518);
border-color: rgba(255, 117, 24, 0.3);
}
.dashboard-action-link.store-link:hover {
background: rgba(255, 117, 24, 0.08);
border-color: var(--dash-accent, #ff7518);
color: var(--dash-accent, #ff7518);
}
.dashboard-user-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
text-decoration: none !important;
color: var(--dash-text);
background: var(--dash-surface-soft);
border: 1px solid var(--dash-border);
transition: all 0.15s ease;
}
.dashboard-user-link:hover {
background: var(--dash-hover);
border-color: var(--dash-text-secondary);
}
.dashboard-mobile-toggle {
display: none;
background: transparent;
border: none;
color: var(--dash-text);
cursor: pointer;
padding: 4px;
align-items: center;
justify-content: center;
}
@media (max-width: 860px) {
.dashboard-mobile-toggle {
display: flex;
}
.dashboard-app-nav-wrap {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--dash-surface);
border-bottom: 1px solid var(--dash-border);
flex-direction: column; flex-direction: column;
padding: 1rem 1.5rem 1.5rem;
gap: 1rem;
margin-left: 0;
box-shadow: 0 8px 16px rgba(0,0,0,0.08);
} }
.dashboard-app-nav-wrap.open {
display: flex;
}
.dashboard-app-nav {
flex-direction: column;
width: 100%;
align-items: stretch;
}
.dashboard-app-nav-link {
padding: 10px 14px;
}
.dashboard-app-actions {
flex-direction: column;
width: 100%;
align-items: stretch;
padding-top: 0.75rem;
border-top: 1px solid var(--dash-border);
}
.dashboard-action-link, .dashboard-user-link {
justify-content: center;
padding: 10px;
}
}
/* Studio dark theme overrides for developer studio header when in ManagePlugin or AddPlugin */
.dashboard-container:has(.mp-root) .dashboard-app-header,
.dashboard-container:has(.ap-root) .dashboard-app-header {
background: var(--mp-surface, #151820);
border-color: var(--mp-border, #252a38);
margin-bottom: 0 !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.dashboard-container:has(.mp-root) .dashboard-app-brand,
.dashboard-container:has(.ap-root) .dashboard-app-brand {
color: var(--mp-text, #e8eaf2);
}
.dashboard-container:has(.mp-root) .dashboard-app-nav-link,
.dashboard-container:has(.ap-root) .dashboard-app-nav-link {
color: var(--mp-text-2, #8b91a8);
}
.dashboard-container:has(.mp-root) .dashboard-app-nav-link:hover,
.dashboard-container:has(.ap-root) .dashboard-app-nav-link:hover {
color: var(--mp-text, #e8eaf2);
background: var(--mp-surface-2, #1c2030);
}
.dashboard-container:has(.mp-root) .dashboard-app-nav-link.active,
.dashboard-container:has(.ap-root) .dashboard-app-nav-link.active {
color: #ffffff;
background: rgba(79, 126, 255, 0.18);
}
.dashboard-container:has(.mp-root) .dashboard-action-link,
.dashboard-container:has(.ap-root) .dashboard-action-link {
background: var(--mp-surface-2, #1c2030);
border-color: var(--mp-border, #252a38);
color: var(--mp-text-2, #8b91a8);
}
.dashboard-container:has(.mp-root) .dashboard-action-link:hover,
.dashboard-container:has(.ap-root) .dashboard-action-link:hover {
color: var(--mp-text, #e8eaf2);
background: #252a38;
}
.dashboard-container:has(.mp-root) .dashboard-action-link.store-link,
.dashboard-container:has(.ap-root) .dashboard-action-link.store-link {
background: transparent;
color: var(--dash-accent, #ff7518);
border-color: rgba(255, 117, 24, 0.3);
}
.dashboard-container:has(.mp-root) .dashboard-action-link.store-link:hover,
.dashboard-container:has(.ap-root) .dashboard-action-link.store-link:hover {
background: rgba(255, 117, 24, 0.12);
border-color: var(--dash-accent, #ff7518);
}
.dashboard-container:has(.mp-root) .dashboard-user-link,
.dashboard-container:has(.ap-root) .dashboard-user-link {
background: var(--mp-surface-2, #1c2030);
border-color: var(--mp-border, #252a38);
color: var(--mp-text, #e8eaf2);
}
.dashboard-container:has(.mp-root) .dashboard-user-link:hover,
.dashboard-container:has(.ap-root) .dashboard-user-link:hover {
background: #252a38;
}
.dashboard-container:has(.mp-root) .dashboard-mobile-toggle,
.dashboard-container:has(.ap-root) .dashboard-mobile-toggle {
color: var(--mp-text, #e8eaf2);
}
.dashboard-container:has(.mp-root) .dashboard-app-nav-wrap,
.dashboard-container:has(.ap-root) .dashboard-app-nav-wrap {
background: var(--mp-surface, #151820);
border-color: var(--mp-border, #252a38);
}
/* Override App.css within the dashboard */
.dashboard-content, .dashboard-nav { .dashboard-content, .dashboard-nav {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-family: var(--font-body);
} }
.dashboard-header { .dashboard-header {
@ -451,7 +186,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: #EBF5FF; background: var(--dash-primary-light);
color: var(--dash-primary); color: var(--dash-primary);
} }
.activity-text strong { .activity-text strong {
@ -467,7 +202,7 @@
align-items: center; align-items: center;
gap: 1rem; gap: 1rem;
padding: 1rem; padding: 1rem;
background-color: #F6F8FA; background-color: var(--dash-surface-soft);
border-radius: 6px; border-radius: 6px;
border: 1px solid var(--dash-border); border: 1px solid var(--dash-border);
} }
@ -566,7 +301,7 @@
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: #ccc; background-color: var(--dash-border);
transition: .4s; transition: .4s;
border-radius: 24px; border-radius: 24px;
} }
@ -577,7 +312,7 @@
width: 18px; width: 18px;
left: 3px; left: 3px;
bottom: 3px; bottom: 3px;
background-color: white; background-color: #fff;
transition: .4s; transition: .4s;
border-radius: 50%; border-radius: 50%;
} }
@ -608,7 +343,7 @@ input:checked + .slider:before {
border-right: 1px solid var(--dash-border); border-right: 1px solid var(--dash-border);
} }
.radio-pill.active { .radio-pill.active {
background: #EBF5FF; background: var(--dash-primary-light);
color: var(--dash-primary); color: var(--dash-primary);
font-weight: 600; font-weight: 600;
} }
@ -662,7 +397,7 @@ input:checked + .slider:before {
} }
.markdown-tabs { .markdown-tabs {
display: flex; display: flex;
background: #F6F8FA; background: var(--dash-surface-soft);
border-bottom: 1px solid var(--dash-border); border-bottom: 1px solid var(--dash-border);
} }
.markdown-tab { .markdown-tab {
@ -692,7 +427,8 @@ input:checked + .slider:before {
} }
.markdown-preview p { margin: 0 0 16px 0; } .markdown-preview p { margin: 0 0 16px 0; }
.markdown-preview code { .markdown-preview code {
background-color: #F6F8FA; background-color: var(--dash-surface-soft);
color: var(--dash-text);
padding: .2em .4em; padding: .2em .4em;
margin: 0; margin: 0;
font-size: 85%; font-size: 85%;
@ -700,7 +436,8 @@ input:checked + .slider:before {
font-family: var(--font-mono); font-family: var(--font-mono);
} }
.markdown-preview pre { .markdown-preview pre {
background-color: #F6F8FA; background-color: var(--dash-surface-soft);
color: var(--dash-text);
padding: 16px; padding: 16px;
border-radius: 3px; border-radius: 3px;
overflow: auto; overflow: auto;
@ -747,7 +484,7 @@ input:checked + .slider:before {
border: 1px solid var(--dash-border); border: 1px solid var(--dash-border);
border-radius: 6px; border-radius: 6px;
padding: 1rem; padding: 1rem;
background-color: #F6F8FA; background-color: var(--dash-surface-soft);
margin-top: 0.5rem; margin-top: 0.5rem;
} }
@ -774,7 +511,7 @@ input:checked + .slider:before {
.screenshot-dropzone.drag-over { .screenshot-dropzone.drag-over {
border-color: var(--dash-primary); border-color: var(--dash-primary);
background-color: rgba(3, 102, 214, 0.05); background-color: rgba(255, 117, 24, 0.08);
} }
.screenshot-previews { .screenshot-previews {
grid-area: 1 / 1; /* Positioned at the front */ grid-area: 1 / 1; /* Positioned at the front */
@ -796,7 +533,7 @@ input:checked + .slider:before {
border-radius: 6px; border-radius: 6px;
overflow: hidden; overflow: hidden;
border: 1px solid var(--dash-border); border: 1px solid var(--dash-border);
background: #fff; background: var(--dash-surface);
flex-shrink: 0; flex-shrink: 0;
box-shadow: var(--dash-shadow); box-shadow: var(--dash-shadow);
} }
@ -1130,11 +867,11 @@ input:checked + .slider:before {
.dashboard-wrapper { .dashboard-wrapper {
background-color: var(--bg-main); background-color: var(--dash-bg);
min-height: 100vh; min-height: 100vh;
padding: 2rem; padding: 2rem;
font-family: 'Inter', system-ui, sans-serif; font-family: var(--font-body);
color: var(--text-main); color: var(--dash-text);
} }
/* Header & Segmented Control */ /* Header & Segmented Control */
@ -1146,10 +883,10 @@ input:checked + .slider:before {
} }
.dashboard-top-nav h1 { font-size: 1.5rem; font-weight: 700; margin: 0; } .dashboard-top-nav h1 { font-size: 1.5rem; font-weight: 700; margin: 0; }
.subtitle { color: var(--text-muted); margin: 4px 0 0 0; font-size: 0.9rem; } .subtitle { color: var(--dash-text-muted); margin: 4px 0 0 0; font-size: 0.9rem; }
.segment-control { .segment-control {
background: #e2e8f0; background: var(--dash-surface-soft);
padding: 4px; padding: 4px;
border-radius: 8px; border-radius: 8px;
display: flex; display: flex;
@ -1164,13 +901,13 @@ input:checked + .slider:before {
border-radius: 6px; border-radius: 6px;
cursor: pointer; cursor: pointer;
transition: 0.2s; transition: 0.2s;
color: var(--text-muted); color: var(--dash-text-muted);
} }
.segment-control button.active { .segment-control button.active {
background: var(--surface); background: var(--dash-surface);
color: var(--text-main); color: var(--dash-text);
box-shadow: var(--shadow-sm); box-shadow: var(--dash-shadow);
} }
/* Grid Layout */ /* Grid Layout */
@ -1189,11 +926,11 @@ input:checked + .slider:before {
} }
.kpi-card-v2 { .kpi-card-v2 {
background: var(--surface); background: var(--dash-surface);
border: 1px solid var(--border-color); border: 1px solid var(--dash-border);
border-radius: 12px; border-radius: 12px;
padding: 1.25rem; padding: 1.25rem;
box-shadow: var(--shadow-sm); box-shadow: var(--dash-shadow);
} }
.kpi-header { .kpi-header {
@ -1204,8 +941,8 @@ input:checked + .slider:before {
} }
.kpi-icon-wrapper { .kpi-icon-wrapper {
color: var(--primary); color: var(--dash-primary);
background: #eef2ff; background: var(--dash-primary-light);
padding: 6px; padding: 6px;
border-radius: 6px; border-radius: 6px;
display: flex; display: flex;
@ -1214,7 +951,7 @@ input:checked + .slider:before {
.kpi-title { .kpi-title {
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 600; font-weight: 600;
color: var(--text-muted); color: var(--dash-text-muted);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.025em; letter-spacing: 0.025em;
} }
@ -1241,15 +978,15 @@ input:checked + .slider:before {
} }
.kpi-trend.up { color: var(--success); } .kpi-trend.up { color: var(--success); }
.kpi-trend.down { color: var(--danger); } .kpi-trend.down { color: #f2415a; }
/* Main Chart */ /* Main Chart */
.chart-container-v2 { .chart-container-v2 {
background: var(--surface); background: var(--dash-surface);
border: 1px solid var(--border-color); border: 1px solid var(--dash-border);
border-radius: 12px; border-radius: 12px;
padding: 1.5rem; padding: 1.5rem;
box-shadow: var(--shadow-sm); box-shadow: var(--dash-shadow);
} }
.chart-header { .chart-header {
@ -1260,8 +997,8 @@ input:checked + .slider:before {
/* Sidebar Feed */ /* Sidebar Feed */
.activity-sidebar-v2 { .activity-sidebar-v2 {
background: var(--surface); background: var(--dash-surface);
border: 1px solid var(--border-color); border: 1px solid var(--dash-border);
border-radius: 12px; border-radius: 12px;
padding: 1.5rem; padding: 1.5rem;
height: fit-content; height: fit-content;
@ -1283,28 +1020,35 @@ input:checked + .slider:before {
.feed-avatar { .feed-avatar {
width: 36px; width: 36px;
height: 36px; height: 36px;
background: #f1f5f9; background: var(--dash-surface-soft);
border-radius: 50%; border-radius: 50%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.75rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
color: var(--text-muted); color: var(--dash-text);
} }
.feed-content p { font-size: 0.85rem; margin: 0; } .feed-content p { font-size: 0.85rem; margin: 0; color: var(--dash-text); }
.feed-content span { font-size: 0.75rem; color: var(--text-muted); display: flex; align-items: center; gap: 4px; } .feed-content span { font-size: 0.75rem; color: var(--dash-text-muted); display: flex; align-items: center; gap: 4px; }
.feed-amount { margin-left: auto; font-weight: 600; font-size: 0.85rem; color: var(--success); } .feed-amount { margin-left: auto; font-weight: 600; font-size: 0.85rem; color: var(--success); }
.view-all-btn { .view-all-btn {
width: 100%; width: 100%;
padding: 10px; padding: 10px;
border: 1px solid var(--border-color); border: 1px solid var(--dash-border);
background: var(--bg-main); background: var(--dash-surface-soft);
color: var(--dash-text);
border-radius: 8px; border-radius: 8px;
cursor: pointer; cursor: pointer;
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 600; font-weight: 600;
transition: all 0.2s;
}
.view-all-btn:hover {
background: var(--dash-hover);
border-color: var(--dash-primary);
} }

View File

@ -144,7 +144,7 @@ const DashboardPlugins = () => {
{plugins.length === 0 && ( {plugins.length === 0 && (
<tr> <tr>
<td colSpan={4} style={{ textAlign: 'center', padding: '3rem' }}> <td colSpan={5} style={{ textAlign: 'center', padding: '3rem' }}>
<div style={{ opacity: 0.6 }}> <div style={{ opacity: 0.6 }}>
<p>No plugins published yet.</p> <p>No plugins published yet.</p>
<small>Click "Add New Plugin" to get started</small> <small>Click "Add New Plugin" to get started</small>

View File

@ -4,8 +4,9 @@
.ap-root { .ap-root {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
/* developer studio navbar ~58px */ flex: 1;
height: calc(100vh - 58px); height: 100%;
min-height: 0;
background: var(--mp-bg); background: var(--mp-bg);
color: var(--mp-text); color: var(--mp-text);
font-family: var(--font-display); font-family: var(--font-display);

View File

@ -38,8 +38,9 @@
.mp-root { .mp-root {
display: flex; display: flex;
/* developer studio navbar ~58px */ flex: 1;
height: calc(100vh - 58px); height: 100%;
min-height: 0;
background: var(--mp-bg); background: var(--mp-bg);
color: var(--mp-text); color: var(--mp-text);
font-family: var(--font-display); font-family: var(--font-display);
@ -49,10 +50,11 @@
/* ── Loading ────────────────────────────────────────────────── */ /* ── Loading ────────────────────────────────────────────────── */
.mp-loading { .mp-loading {
display: flex; display: flex;
flex: 1;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-height: calc(100vh - 58px); min-height: 300px;
gap: 1rem; gap: 1rem;
background: var(--mp-bg); background: var(--mp-bg);
color: var(--mp-text-2); color: var(--mp-text-2);