smaller fixes
This commit is contained in:
parent
6cfca656e8
commit
fe14649ff6
29
src/App.css
29
src/App.css
@ -2034,6 +2034,14 @@ h3 {
|
||||
font-size: 0.92rem;
|
||||
line-height: 1.6;
|
||||
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 {
|
||||
@ -2047,6 +2055,27 @@ h3 {
|
||||
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 {
|
||||
position: fixed;
|
||||
/* Fixes it to the screen, not the page */
|
||||
|
||||
106
src/App.tsx
106
src/App.tsx
@ -1,7 +1,7 @@
|
||||
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 { 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 PluginDetail from './pages/PluginDetail';
|
||||
import LoginPage from './pages/auth/LoginPage';
|
||||
@ -176,17 +176,16 @@ const DeveloperStudioNavbar = ({ user }: any) => {
|
||||
const toggleMenu = () => setIsMenuOpen(!isMenuOpen);
|
||||
|
||||
return (
|
||||
<header className="dashboard-app-header">
|
||||
<div className="dashboard-app-header-inner">
|
||||
{/* Brand */}
|
||||
<Link to="/dashboard/plugins" className="dashboard-app-brand" onClick={() => setIsMenuOpen(false)}>
|
||||
<img src="/icon.png" alt="Market Logo" className="dashboard-app-logo" />
|
||||
<span className="dashboard-app-title">DEVELOPER <span>STUDIO</span></span>
|
||||
<nav className="navbar">
|
||||
<div className="logo" style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Link to="/dashboard/plugins" onClick={() => setIsMenuOpen(false)}>
|
||||
<img src="/icon.png" alt="Market Logo" style={{ height: '50px', marginRight: '0px', verticalAlign: 'middle' }} />
|
||||
<span>STUDIO</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Mobile menu toggle button */}
|
||||
<button className="dashboard-mobile-toggle" onClick={toggleMenu} aria-label="Toggle navigation menu">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<button className="mobile-menu-toggle" onClick={toggleMenu} aria-label="Toggle menu">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
{isMenuOpen ? (
|
||||
<path d="M18 6L6 18M6 6l12 12" />
|
||||
) : (
|
||||
@ -195,54 +194,57 @@ const DeveloperStudioNavbar = ({ user }: any) => {
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Navigation & Actions */}
|
||||
<div className={`dashboard-app-nav-wrap ${isMenuOpen ? 'open' : ''}`}>
|
||||
<nav className="dashboard-app-nav">
|
||||
<NavLink
|
||||
to="/dashboard/plugins"
|
||||
className={({ isActive }) => `dashboard-app-nav-link ${isActive ? 'active' : ''}`}
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
>
|
||||
<Package size={16} />
|
||||
<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={`nav-content ${isMenuOpen ? 'open' : ''}`}>
|
||||
<div className="nav-links">
|
||||
<NavLink to="/dashboard/plugins" onClick={() => setIsMenuOpen(false)}>Plugins</NavLink>
|
||||
<NavLink to="/dashboard/audience" onClick={() => setIsMenuOpen(false)}>Audience</NavLink>
|
||||
<NavLink to="/dashboard/add-plugin" onClick={() => setIsMenuOpen(false)}>Publish</NavLink>
|
||||
{user && (user.role === 'admin' || user.role === 'moderator') && (
|
||||
<NavLink to="/staff" onClick={() => setIsMenuOpen(false)}>Staff</NavLink>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="dashboard-app-actions">
|
||||
<Link to="/" className="dashboard-action-link store-link" onClick={() => setIsMenuOpen(false)} title="Return to Marketplace">
|
||||
<Store size={15} />
|
||||
<div className="nav-actions" style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: '1.25rem' }}>
|
||||
<Link
|
||||
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>
|
||||
</Link>
|
||||
{user && (user.role === 'admin' || user.role === 'moderator') && (
|
||||
<NavLink to="/staff" className="dashboard-action-link" onClick={() => setIsMenuOpen(false)}>
|
||||
<span>Staff</span>
|
||||
</NavLink>
|
||||
)}
|
||||
{user && (
|
||||
<NavLink to="/settings" className="dashboard-user-link" onClick={() => setIsMenuOpen(false)}>
|
||||
<span>{user.username}</span>
|
||||
</NavLink>
|
||||
|
||||
{user ? (
|
||||
<NavLink to="/settings" className="nav-user-link" onClick={() => setIsMenuOpen(false)}>{user.username}</NavLink>
|
||||
) : (
|
||||
<Link to="/login" className="btn btn-secondary" onClick={() => setIsMenuOpen(false)}>Login</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import SEO from '../components/SEO';
|
||||
import { Sparkles, History } from 'lucide-react';
|
||||
import { Sparkles, History, ChevronRight } from 'lucide-react';
|
||||
|
||||
const getYoutubeVideoId = (url: string) => {
|
||||
if (!url) return null;
|
||||
@ -680,7 +680,10 @@ const PluginDetail = () => {
|
||||
</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-header">
|
||||
<div className="plugin-recent-update-title-group">
|
||||
@ -689,11 +692,11 @@ const PluginDetail = () => {
|
||||
What's New
|
||||
</h3>
|
||||
<span className="plugin-recent-update-badge">
|
||||
v{plugin.versions[0].version}
|
||||
v{latest.version}
|
||||
</span>
|
||||
{plugin.versions[0].created_at && (
|
||||
{latest.created_at && (
|
||||
<span className="plugin-recent-update-date">
|
||||
{formatDate(plugin.versions[0].created_at)}
|
||||
{formatDate(latest.created_at)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@ -708,10 +711,10 @@ const PluginDetail = () => {
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="plugin-recent-update-body markdown-content">
|
||||
{plugin.versions[0].release_notes ? (
|
||||
<div className={`plugin-recent-update-body markdown-content ${isLong ? 'is-clamped' : ''}`}>
|
||||
{latest.release_notes ? (
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>
|
||||
{plugin.versions[0].release_notes}
|
||||
{latest.release_notes}
|
||||
</ReactMarkdown>
|
||||
) : (
|
||||
<p className="plugin-recent-update-empty">
|
||||
@ -719,8 +722,19 @@ const PluginDetail = () => {
|
||||
</p>
|
||||
)}
|
||||
</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 */}
|
||||
<div className="markdown-content">
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Turnstile } from '@marsidev/react-turnstile';
|
||||
import api from '../../api';
|
||||
|
||||
const ForgotPasswordPage = () => {
|
||||
@ -11,6 +12,8 @@ const ForgotPasswordPage = () => {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [emailTouched, setEmailTouched] = useState(false);
|
||||
const [emailValid, setEmailValid] = useState<boolean | null>(null);
|
||||
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
|
||||
const turnstileRef = useRef<any>(null);
|
||||
|
||||
const validateEmail = (email: string) =>
|
||||
Boolean(String(email).toLowerCase().match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/));
|
||||
@ -43,11 +46,38 @@ const ForgotPasswordPage = () => {
|
||||
setIsSubmitting(true);
|
||||
setError('');
|
||||
setMessage('');
|
||||
|
||||
let currentToken = captchaToken;
|
||||
if (!currentToken && turnstileRef.current) {
|
||||
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.');
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error || 'Something went wrong. Please try again.');
|
||||
if (turnstileRef.current) {
|
||||
try {
|
||||
turnstileRef.current.reset();
|
||||
setCaptchaToken(null);
|
||||
} catch (_) {}
|
||||
}
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
@ -272,6 +302,17 @@ const ForgotPasswordPage = () => {
|
||||
)}
|
||||
</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}>
|
||||
{isSubmitting ? <><span className="spinner" />Sending...</> : 'Send reset link'}
|
||||
</button>
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
:root {
|
||||
--dash-bg: #F6F8FA;
|
||||
--dash-surface: #FFFFFF;
|
||||
--dash-surface-soft: #F0F2F5; /* New: for softer backgrounds */
|
||||
--dash-border: #E1E4E8;
|
||||
--dash-text: #24292E;
|
||||
--dash-text-muted: #586069;
|
||||
--dash-text-secondary: #6A737D; /* New: for secondary text */
|
||||
--dash-primary: #0366D6; /* Stripe-like blue */
|
||||
--dash-primary-light: #EBF5FF; /* New: Light version of primary color */
|
||||
--dash-accent: #FF7518; /* Keep a hint of Pumpkin */
|
||||
--dash-hover: #EAEFF4; /* New: for hover states */
|
||||
--dash-shadow: 0 1px 3px rgba(0,0,0,0.08); /* New: for subtle shadows */
|
||||
--dash-bg: #0A0A0A;
|
||||
--dash-surface: #141414;
|
||||
--dash-surface-soft: #1A1D24;
|
||||
--dash-border: #2A2A2A;
|
||||
--dash-text: #EAEAEA;
|
||||
--dash-text-muted: #888888;
|
||||
--dash-text-secondary: #A3A3A3;
|
||||
--dash-primary: #FF7518;
|
||||
--dash-primary-light: rgba(255, 117, 24, 0.15);
|
||||
--dash-accent: #FF7518;
|
||||
--dash-hover: #1F232D;
|
||||
--dash-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Dashboard Layout Container */
|
||||
@ -18,8 +18,8 @@
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--dash-bg, #F6F8FA);
|
||||
color: var(--dash-text, #24292E);
|
||||
background-color: var(--dash-bg, #0A0A0A);
|
||||
color: var(--dash-text, #EAEAEA);
|
||||
}
|
||||
|
||||
.dashboard-content {
|
||||
@ -27,293 +27,28 @@
|
||||
max-width: 1400px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 0 2rem 2.5rem 2rem;
|
||||
padding: 2.5rem 2.5rem 4rem 2.5rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Dashboard Top App Header (replaces main navbar in dev menu) */
|
||||
.dashboard-app-header {
|
||||
background: var(--dash-surface);
|
||||
border-bottom: 1px solid var(--dash-border);
|
||||
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-container:has(.mp-root),
|
||||
.dashboard-container:has(.ap-root) {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dashboard-app-header-inner {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
.dashboard-container:has(.mp-root) .dashboard-content,
|
||||
.dashboard-container:has(.ap-root) .dashboard-content {
|
||||
padding: 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
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;
|
||||
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 {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
font-family: var(--font-body);
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
@ -451,7 +186,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #EBF5FF;
|
||||
background: var(--dash-primary-light);
|
||||
color: var(--dash-primary);
|
||||
}
|
||||
.activity-text strong {
|
||||
@ -467,7 +202,7 @@
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
background-color: #F6F8FA;
|
||||
background-color: var(--dash-surface-soft);
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--dash-border);
|
||||
}
|
||||
@ -566,7 +301,7 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
background-color: var(--dash-border);
|
||||
transition: .4s;
|
||||
border-radius: 24px;
|
||||
}
|
||||
@ -577,7 +312,7 @@
|
||||
width: 18px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: white;
|
||||
background-color: #fff;
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
@ -608,7 +343,7 @@ input:checked + .slider:before {
|
||||
border-right: 1px solid var(--dash-border);
|
||||
}
|
||||
.radio-pill.active {
|
||||
background: #EBF5FF;
|
||||
background: var(--dash-primary-light);
|
||||
color: var(--dash-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
@ -662,7 +397,7 @@ input:checked + .slider:before {
|
||||
}
|
||||
.markdown-tabs {
|
||||
display: flex;
|
||||
background: #F6F8FA;
|
||||
background: var(--dash-surface-soft);
|
||||
border-bottom: 1px solid var(--dash-border);
|
||||
}
|
||||
.markdown-tab {
|
||||
@ -692,7 +427,8 @@ input:checked + .slider:before {
|
||||
}
|
||||
.markdown-preview p { margin: 0 0 16px 0; }
|
||||
.markdown-preview code {
|
||||
background-color: #F6F8FA;
|
||||
background-color: var(--dash-surface-soft);
|
||||
color: var(--dash-text);
|
||||
padding: .2em .4em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
@ -700,7 +436,8 @@ input:checked + .slider:before {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
.markdown-preview pre {
|
||||
background-color: #F6F8FA;
|
||||
background-color: var(--dash-surface-soft);
|
||||
color: var(--dash-text);
|
||||
padding: 16px;
|
||||
border-radius: 3px;
|
||||
overflow: auto;
|
||||
@ -747,7 +484,7 @@ input:checked + .slider:before {
|
||||
border: 1px solid var(--dash-border);
|
||||
border-radius: 6px;
|
||||
padding: 1rem;
|
||||
background-color: #F6F8FA;
|
||||
background-color: var(--dash-surface-soft);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
@ -774,7 +511,7 @@ input:checked + .slider:before {
|
||||
|
||||
.screenshot-dropzone.drag-over {
|
||||
border-color: var(--dash-primary);
|
||||
background-color: rgba(3, 102, 214, 0.05);
|
||||
background-color: rgba(255, 117, 24, 0.08);
|
||||
}
|
||||
.screenshot-previews {
|
||||
grid-area: 1 / 1; /* Positioned at the front */
|
||||
@ -796,7 +533,7 @@ input:checked + .slider:before {
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--dash-border);
|
||||
background: #fff;
|
||||
background: var(--dash-surface);
|
||||
flex-shrink: 0;
|
||||
box-shadow: var(--dash-shadow);
|
||||
}
|
||||
@ -1130,11 +867,11 @@ input:checked + .slider:before {
|
||||
|
||||
|
||||
.dashboard-wrapper {
|
||||
background-color: var(--bg-main);
|
||||
background-color: var(--dash-bg);
|
||||
min-height: 100vh;
|
||||
padding: 2rem;
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
color: var(--text-main);
|
||||
font-family: var(--font-body);
|
||||
color: var(--dash-text);
|
||||
}
|
||||
|
||||
/* Header & Segmented Control */
|
||||
@ -1146,10 +883,10 @@ input:checked + .slider:before {
|
||||
}
|
||||
|
||||
.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 {
|
||||
background: #e2e8f0;
|
||||
background: var(--dash-surface-soft);
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
@ -1164,13 +901,13 @@ input:checked + .slider:before {
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
color: var(--text-muted);
|
||||
color: var(--dash-text-muted);
|
||||
}
|
||||
|
||||
.segment-control button.active {
|
||||
background: var(--surface);
|
||||
color: var(--text-main);
|
||||
box-shadow: var(--shadow-sm);
|
||||
background: var(--dash-surface);
|
||||
color: var(--dash-text);
|
||||
box-shadow: var(--dash-shadow);
|
||||
}
|
||||
|
||||
/* Grid Layout */
|
||||
@ -1189,11 +926,11 @@ input:checked + .slider:before {
|
||||
}
|
||||
|
||||
.kpi-card-v2 {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--dash-surface);
|
||||
border: 1px solid var(--dash-border);
|
||||
border-radius: 12px;
|
||||
padding: 1.25rem;
|
||||
box-shadow: var(--shadow-sm);
|
||||
box-shadow: var(--dash-shadow);
|
||||
}
|
||||
|
||||
.kpi-header {
|
||||
@ -1204,8 +941,8 @@ input:checked + .slider:before {
|
||||
}
|
||||
|
||||
.kpi-icon-wrapper {
|
||||
color: var(--primary);
|
||||
background: #eef2ff;
|
||||
color: var(--dash-primary);
|
||||
background: var(--dash-primary-light);
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
@ -1214,7 +951,7 @@ input:checked + .slider:before {
|
||||
.kpi-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
color: var(--dash-text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.025em;
|
||||
}
|
||||
@ -1241,15 +978,15 @@ input:checked + .slider:before {
|
||||
}
|
||||
|
||||
.kpi-trend.up { color: var(--success); }
|
||||
.kpi-trend.down { color: var(--danger); }
|
||||
.kpi-trend.down { color: #f2415a; }
|
||||
|
||||
/* Main Chart */
|
||||
.chart-container-v2 {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--dash-surface);
|
||||
border: 1px solid var(--dash-border);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--shadow-sm);
|
||||
box-shadow: var(--dash-shadow);
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
@ -1260,8 +997,8 @@ input:checked + .slider:before {
|
||||
|
||||
/* Sidebar Feed */
|
||||
.activity-sidebar-v2 {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--dash-surface);
|
||||
border: 1px solid var(--dash-border);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
height: fit-content;
|
||||
@ -1283,28 +1020,35 @@ input:checked + .slider:before {
|
||||
.feed-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: #f1f5f9;
|
||||
background: var(--dash-surface-soft);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-muted);
|
||||
color: var(--dash-text);
|
||||
}
|
||||
|
||||
|
||||
.feed-content p { font-size: 0.85rem; margin: 0; }
|
||||
.feed-content span { font-size: 0.75rem; color: var(--text-muted); display: flex; align-items: center; gap: 4px; }
|
||||
.feed-content p { font-size: 0.85rem; margin: 0; color: var(--dash-text); }
|
||||
.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); }
|
||||
|
||||
.view-all-btn {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--bg-main);
|
||||
border: 1px solid var(--dash-border);
|
||||
background: var(--dash-surface-soft);
|
||||
color: var(--dash-text);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.view-all-btn:hover {
|
||||
background: var(--dash-hover);
|
||||
border-color: var(--dash-primary);
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ const DashboardPlugins = () => {
|
||||
|
||||
{plugins.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={4} style={{ textAlign: 'center', padding: '3rem' }}>
|
||||
<td colSpan={5} style={{ textAlign: 'center', padding: '3rem' }}>
|
||||
<div style={{ opacity: 0.6 }}>
|
||||
<p>No plugins published yet.</p>
|
||||
<small>Click "Add New Plugin" to get started</small>
|
||||
|
||||
@ -4,8 +4,9 @@
|
||||
.ap-root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* developer studio navbar ~58px */
|
||||
height: calc(100vh - 58px);
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
background: var(--mp-bg);
|
||||
color: var(--mp-text);
|
||||
font-family: var(--font-display);
|
||||
|
||||
@ -38,8 +38,9 @@
|
||||
|
||||
.mp-root {
|
||||
display: flex;
|
||||
/* developer studio navbar ~58px */
|
||||
height: calc(100vh - 58px);
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
background: var(--mp-bg);
|
||||
color: var(--mp-text);
|
||||
font-family: var(--font-display);
|
||||
@ -49,10 +50,11 @@
|
||||
/* ── Loading ────────────────────────────────────────────────── */
|
||||
.mp-loading {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: calc(100vh - 58px);
|
||||
min-height: 300px;
|
||||
gap: 1rem;
|
||||
background: var(--mp-bg);
|
||||
color: var(--mp-text-2);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user