chore: make sidebar non sticky

This commit is contained in:
Alexander Medvedev 2026-08-31 21:35:25 +02:00
parent 35e34b36f9
commit 7091dc152f
18 changed files with 125 additions and 42 deletions

View File

@ -1805,8 +1805,6 @@ h3 {
padding: 2rem;
border-radius: 12px;
border: 1px solid var(--border);
position: sticky;
top: 120px;
}
.sidebar-widget h3 {

View File

@ -76,8 +76,9 @@
"success": "Meldung eingereicht. Unser Team wird sie prüfen."
},
"commands": {
"title": "Befehle & Berechtigungen",
"title": "Befehle",
"no_commands": "Keine Befehle für dieses Plugin angegeben.",
"aliases": "Aliasse",
"permission": "Berechtigung",
"no_permission": "Keine erforderlich",
"copy_command": "Befehl kopieren",

View File

@ -76,8 +76,9 @@
"success": "Report submitted. Our moderation team will investigate."
},
"commands": {
"title": "Commands & Permissions",
"title": "Commands",
"no_commands": "No commands listed for this plugin.",
"aliases": "Aliases",
"permission": "Permission",
"no_permission": "None required",
"copy_command": "Copy command",

View File

@ -76,8 +76,9 @@
"success": "Reporte enviado. Nuestro equipo lo revisará."
},
"commands": {
"title": "Comandos y Permisos",
"title": "Comandos",
"no_commands": "No hay comandos listados para este plugin.",
"aliases": "Alias",
"permission": "Permiso",
"no_permission": "Ninguno requerido",
"copy_command": "Copiar comando",

View File

@ -76,8 +76,9 @@
"success": "Signalement envoyé. Notre équipe va l'examiner."
},
"commands": {
"title": "Commandes et Permissions",
"title": "Commandes",
"no_commands": "Aucune commande listée pour ce plugin.",
"aliases": "Alias",
"permission": "Permission",
"no_permission": "Aucune requise",
"copy_command": "Copier la commande",

View File

@ -76,8 +76,9 @@
"success": "Segnalazione inviata. Il team di moderazione verificherà."
},
"commands": {
"title": "Comandi e Permessi",
"title": "Comandi",
"no_commands": "Nessun comando elencato per questo plugin.",
"aliases": "Alias",
"permission": "Permesso",
"no_permission": "Nessuno richiesto",
"copy_command": "Copia comando",

View File

@ -76,8 +76,9 @@
"success": "報告を受け付けました。運営チームが確認いたします。"
},
"commands": {
"title": "コマンドと権限",
"title": "コマンド",
"no_commands": "このプラグインに登録されているコマンドはありません。",
"aliases": "エイリアス",
"permission": "権限",
"no_permission": "権限不要",
"copy_command": "コマンドをコピー",

View File

@ -76,8 +76,9 @@
"success": "신고가 접수되었습니다. 검토 후 처리하겠습니다."
},
"commands": {
"title": "명령어 및 권한",
"title": "명령어",
"no_commands": "이 플러그인에 등록된 명령어가 없습니다.",
"aliases": "별칭",
"permission": "권한",
"no_permission": "필요 없음",
"copy_command": "명령어 복사",

View File

@ -76,8 +76,9 @@
"success": "Melding verzonden. Ons moderatieteam zal dit onderzoeken."
},
"commands": {
"title": "Commando's & Permissies",
"title": "Commando's",
"no_commands": "Geen commando's vermeld voor deze plugin.",
"aliases": "Aliassen",
"permission": "Permissie",
"no_permission": "Geen vereist",
"copy_command": "Kopieer commando",

View File

@ -76,8 +76,9 @@
"success": "Zgłoszenie wysłane. Zespół moderacji zajmie się sprawą."
},
"commands": {
"title": "Polecenia i Uprawnienia",
"title": "Polecenia",
"no_commands": "Brak poleceń dla tego pluginu.",
"aliases": "Aliasy",
"permission": "Uprawnienie",
"no_permission": "Brak wymaganego",
"copy_command": "Kopiuj polecenie",

View File

@ -76,8 +76,9 @@
"success": "Denúncia enviada com sucesso. Nossa equipe irá analisar."
},
"commands": {
"title": "Comandos e Permissões",
"title": "Comandos",
"no_commands": "Nenhum comando listado para este plugin.",
"aliases": "Aliases",
"permission": "Permissão",
"no_permission": "Nenhuma necessária",
"copy_command": "Copiar comando",

View File

@ -76,8 +76,9 @@
"success": "Жалоба отправлена на рассмотрение модераторам."
},
"commands": {
"title": "Команды и Права",
"title": "Команды",
"no_commands": "У этого плагина нет зарегистрированных команд.",
"aliases": "Алиасы",
"permission": "Право",
"no_permission": "Не требуется",
"copy_command": "Скопировать команду",

View File

@ -76,9 +76,10 @@
"success": "Bildirim iletildi. Moderasyon ekibimiz inceleyecektir."
},
"commands": {
"title": "Komutlar ve İzinler",
"title": "Komutlar",
"no_commands": "Bu eklenti için listelenmiş komut yok.",
"permission": "İzin",
"aliases": "Takma Adlar",
"permission": "Yetki",
"no_permission": "Gerekli değil",
"copy_command": "Komutu kopyala",
"copy_permission": "İzni kopyala",

View File

@ -76,8 +76,9 @@
"success": "举报已提交,审核团队将尽快处理。"
},
"commands": {
"title": "命令与权限",
"title": "指令",
"no_commands": "此插件未列出任何指令。",
"aliases": "别名",
"permission": "权限",
"no_permission": "无需权限",
"copy_command": "复制指令",

View File

@ -208,7 +208,7 @@ const PluginCommandsSidebarWidget = ({ commands }: { commands?: PluginCommand[]
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '0.85rem' }}>
<h3 style={{ margin: 0, display: 'flex', alignItems: 'center', gap: '0.45rem', fontSize: '0.82rem' }}>
<Terminal size={14} color="var(--primary)" />
{t('plugin.commands.title', 'Commands & Permissions')}
{t('plugin.commands.title', 'Commands')}
</h3>
<span style={{
fontSize: '0.7rem',
@ -283,6 +283,34 @@ const PluginCommandsSidebarWidget = ({ commands }: { commands?: PluginCommand[]
</button>
</div>
{/* Aliases row */}
{cmd.aliases && Array.isArray(cmd.aliases) && cmd.aliases.length > 0 ? (
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: '0.3rem', marginTop: '-0.1rem' }}>
<span style={{ fontSize: '0.66rem', color: 'var(--text-muted)', fontWeight: 600 }}>
{t('plugin.commands.aliases', 'Aliases')}:
</span>
{cmd.aliases.map((alias: string, aIdx: number) => {
const formattedAlias = alias.startsWith('/') ? alias : `/${alias}`;
return (
<span
key={aIdx}
style={{
fontFamily: 'var(--font-mono)',
fontSize: '0.68rem',
color: 'var(--text-2, #cbd5e1)',
background: 'rgba(255, 255, 255, 0.05)',
border: '1px solid rgba(255, 255, 255, 0.08)',
borderRadius: '4px',
padding: '1px 5px',
}}
>
{formattedAlias}
</span>
);
})}
</div>
) : null}
{/* Permission row */}
{cmd.permission ? (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '0.5rem' }}>

View File

@ -236,6 +236,7 @@ const AddPlugin = () => {
const [commands, setCommands] = useState<Array<{
name: string;
aliases: string;
permission: string;
descriptions: Record<string, string>;
}>>([]);
@ -245,13 +246,14 @@ const AddPlugin = () => {
...prev,
{
name: '',
aliases: '',
permission: '',
descriptions: { [activeLocale]: '' }
}
]);
};
const updateCommandField = (index: number, field: 'name' | 'permission', value: string) => {
const updateCommandField = (index: number, field: 'name' | 'permission' | 'aliases', value: string) => {
const cleanValue = field === 'name' ? value.replace(/^\/+/, '') : value;
setCommands(prev => {
const next = [...prev];
@ -462,12 +464,18 @@ const AddPlugin = () => {
try {
const validCommands = commands
.filter(c => c.name.trim().replace(/^\/+/, '').length > 0)
.map((c, idx) => ({
name: c.name.trim().replace(/^\/+/, ''),
permission: c.permission.trim() || undefined,
description: c.descriptions,
display_order: idx,
}));
.map((c, idx) => {
const aliases = c.aliases
? c.aliases.split(',').map(a => a.trim().replace(/^\/+/, '')).filter(a => a.length > 0)
: undefined;
return {
name: c.name.trim().replace(/^\/+/, ''),
aliases: aliases && aliases.length > 0 ? aliases : undefined,
permission: c.permission.trim() || undefined,
description: c.descriptions,
display_order: idx,
};
});
const metadata = {
name,
@ -810,11 +818,11 @@ const AddPlugin = () => {
)}
</div>
{/* Commands & Permissions */}
{/* Commands */}
<div className="mp-card">
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '0.85rem' }}>
<div className="mp-card-title" style={{ margin: 0 }}>
<Terminal size={14} />Commands & Permissions
<Terminal size={14} />Commands
</div>
<button
type="button"
@ -857,8 +865,8 @@ const AddPlugin = () => {
gap: '0.65rem'
}}
>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
<div style={{ flex: 1 }}>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr auto', gap: '0.75rem', alignItems: 'flex-start' }}>
<div>
<label className="mp-label" style={{ fontSize: '0.72rem', marginBottom: '0.25rem' }}>
Command <span style={{ color: 'var(--mp-error)' }}>*</span>
</label>
@ -872,7 +880,20 @@ const AddPlugin = () => {
required
/>
</div>
<div style={{ flex: 1 }}>
<div>
<label className="mp-label" style={{ fontSize: '0.72rem', marginBottom: '0.25rem' }}>
Aliases <span style={{ color: 'var(--mp-text-3)', fontWeight: 400 }}>(optional, comma-separated)</span>
</label>
<input
className="mp-input"
style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', padding: '0.45rem 0.65rem' }}
placeholder="hub, lobby, s"
value={cmd.aliases}
maxLength={128}
onChange={e => updateCommandField(idx, 'aliases', e.target.value)}
/>
</div>
<div>
<label className="mp-label" style={{ fontSize: '0.72rem', marginBottom: '0.25rem' }}>
Permission Node <span style={{ color: 'var(--mp-text-3)', fontWeight: 400 }}>(optional)</span>
</label>

View File

@ -208,6 +208,7 @@ const StoreListing = ({ plugin, onSaved }: Props) => {
const [commands, setCommands] = useState<Array<{
id?: number;
name: string;
aliases: string;
permission: string;
descriptions: Record<string, string>;
}>>(() => {
@ -235,6 +236,7 @@ const StoreListing = ({ plugin, onSaved }: Props) => {
return {
id: cmd.id,
name: (cmd.name || '').replace(/^\/+/, ''),
aliases: Array.isArray(cmd.aliases) ? cmd.aliases.join(', ') : '',
permission: cmd.permission || '',
descriptions: descMap,
};
@ -246,13 +248,14 @@ const StoreListing = ({ plugin, onSaved }: Props) => {
...prev,
{
name: '',
aliases: '',
permission: '',
descriptions: { [activeLocale]: '' },
},
]);
};
const updateCommandField = (index: number, field: 'name' | 'permission', value: string) => {
const updateCommandField = (index: number, field: 'name' | 'permission' | 'aliases', value: string) => {
const cleanValue = field === 'name' ? value.replace(/^\/+/, '') : value;
setCommands(prev => {
const next = [...prev];
@ -313,13 +316,19 @@ const StoreListing = ({ plugin, onSaved }: Props) => {
setSaveSuccess(false);
const validCommands = commands
.filter(c => c.name.trim().replace(/^\/+/, '').length > 0)
.map((c, idx) => ({
id: c.id,
name: c.name.trim().replace(/^\/+/, ''),
permission: c.permission.trim() || undefined,
description: c.descriptions,
display_order: idx,
}));
.map((c, idx) => {
const aliases = c.aliases
? c.aliases.split(',').map(a => a.trim().replace(/^\/+/, '')).filter(a => a.length > 0)
: undefined;
return {
id: c.id,
name: c.name.trim().replace(/^\/+/, ''),
aliases: aliases && aliases.length > 0 ? aliases : undefined,
permission: c.permission.trim() || undefined,
description: c.descriptions,
display_order: idx,
};
});
const metadata = {
name,
@ -631,11 +640,11 @@ const StoreListing = ({ plugin, onSaved }: Props) => {
</p>
</div>
{/* ── Commands & Permissions ── */}
{/* ── Commands ── */}
<div className="mp-card">
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '0.85rem' }}>
<div className="mp-card-title" style={{ margin: 0 }}>
<Terminal size={14} />Commands & Permissions
<Terminal size={14} />Commands
</div>
<button
type="button"
@ -678,8 +687,8 @@ const StoreListing = ({ plugin, onSaved }: Props) => {
gap: '0.65rem'
}}
>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
<div style={{ flex: 1 }}>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr auto', gap: '0.75rem', alignItems: 'flex-start' }}>
<div>
<label className="mp-label" style={{ fontSize: '0.72rem', marginBottom: '0.25rem' }}>
Command <span style={{ color: 'var(--mp-error)' }}>*</span>
</label>
@ -693,7 +702,20 @@ const StoreListing = ({ plugin, onSaved }: Props) => {
required
/>
</div>
<div style={{ flex: 1 }}>
<div>
<label className="mp-label" style={{ fontSize: '0.72rem', marginBottom: '0.25rem' }}>
Aliases <span style={{ color: 'var(--mp-text-3)', fontWeight: 400 }}>(optional, comma-separated)</span>
</label>
<input
className="mp-input"
style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', padding: '0.45rem 0.65rem' }}
placeholder="hub, lobby, s"
value={cmd.aliases}
maxLength={128}
onChange={e => updateCommandField(idx, 'aliases', e.target.value)}
/>
</div>
<div>
<label className="mp-label" style={{ fontSize: '0.72rem', marginBottom: '0.25rem' }}>
Permission Node <span style={{ color: 'var(--mp-text-3)', fontWeight: 400 }}>(optional)</span>
</label>

View File

@ -8,6 +8,7 @@ export interface PluginCommand {
name: string;
permission?: string;
description?: Record<string, string> | string | null;
aliases?: string[];
display_order?: number;
created_at?: string;
}