fixed assets manager spacing

This commit is contained in:
2026-05-16 17:37:29 +02:00
parent a731a5f50f
commit 9a3d3c89f3
2 changed files with 157 additions and 13 deletions
@@ -61,13 +61,13 @@ export default function AssetManager({ mode = 'manage', onSelect }: Props) {
const isImage = (name: string) => /\.(jpg|jpeg|png|webp|gif|svg)$/i.test(name);
return (
<div className="space-y-8">
<div className="asset-mgr space-y-8">
{alert && (
<div
className={`p-4 mb-6 text-sm font-display italic border ${
className={`asset-alert p-4 mb-6 text-sm font-display italic border ${
alert.type === 'success'
? 'bg-[color-mix(in_srgb,var(--green)_18%,transparent)] text-[var(--green)] border-[var(--green)]/40'
: 'bg-[color-mix(in_srgb,var(--red)_18%,transparent)] text-[var(--red)] border-[var(--red)]/40'
? 'asset-alert--ok bg-[color-mix(in_srgb,var(--green)_18%,transparent)] text-[var(--green)] border-[var(--green)]/40'
: 'asset-alert--err bg-[color-mix(in_srgb,var(--red)_18%,transparent)] text-[var(--red)] border-[var(--red)]/40'
}`}
style={{ borderRadius: 2 }}
>
@@ -77,31 +77,31 @@ export default function AssetManager({ mode = 'manage', onSelect }: Props) {
{/* Upload Zone */}
<div
className="glass p-6 border-dashed border-2 border-[var(--surface2)] hover:border-[var(--mauve)] transition-colors group relative cursor-pointer"
className="asset-drop glass p-6 border-dashed border-2 border-[var(--surface2)] hover:border-[var(--mauve)] transition-colors group relative cursor-pointer"
onClick={() => fileRef.current?.click()}
onDragOver={e => { e.preventDefault(); e.stopPropagation(); }}
onDrop={e => { e.preventDefault(); e.stopPropagation(); if (e.dataTransfer.files.length) handleUpload(e.dataTransfer.files); }}
>
<input ref={fileRef} type="file" multiple className="hidden" onChange={e => { if (e.target.files?.length) handleUpload(e.target.files); }} />
<div className="text-center py-4">
<div className="asset-drop-body text-center py-4">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="mx-auto mb-4 text-[var(--subtext0)] group-hover:text-[var(--mauve)] transition-colors"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/></svg>
<p className="font-display italic text-xl text-[var(--text)] group-hover:text-[var(--mauve)] transition-colors">Click or drag to upload assets</p>
<p className="asset-drop-title font-display italic text-xl text-[var(--text)] group-hover:text-[var(--mauve)] transition-colors">Click or drag to upload assets</p>
<p className="font-sans text-xs uppercase tracking-[0.2em] text-[var(--subtext0)] mt-2">Any file type · up to 50 MB</p>
</div>
</div>
{/* Grid */}
{assets.length === 0 ? (
<div className="text-center py-20 font-display italic text-[var(--subtext0)]">No assets uploaded yet.</div>
<div className="asset-empty text-center py-20 font-display italic text-[var(--subtext0)]">No assets uploaded yet.</div>
) : (
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-4">
<div className="asset-grid grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-4">
{assets.map(asset => (
<div
key={asset.name}
className="group relative aspect-square overflow-hidden bg-[var(--surface0)] border border-[var(--surface2)]/60 hover:border-[var(--mauve)]/60 transition-colors shadow-md flex flex-col"
className="asset-tile group relative aspect-square overflow-hidden bg-[var(--surface0)] border border-[var(--surface2)]/60 hover:border-[var(--mauve)]/60 transition-colors shadow-md flex flex-col"
style={{ borderRadius: 2 }}
>
<div className="flex-1 overflow-hidden bg-[var(--mantle)] relative cursor-pointer">
<div className="asset-thumb flex-1 overflow-hidden bg-[var(--mantle)] relative cursor-pointer">
{isImage(asset.name) ? (
<img src={asset.url} className="w-full h-full object-cover opacity-90 group-hover:opacity-100 transition-opacity" alt={asset.name} />
) : (
@@ -111,7 +111,7 @@ export default function AssetManager({ mode = 'manage', onSelect }: Props) {
</div>
)}
{/* Hover overlay */}
<div className="absolute inset-0 bg-[var(--crust)]/75 backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-3">
<div className="asset-actions absolute inset-0 bg-[var(--crust)]/75 backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-3">
{mode === 'select' && onSelect && (
<button
onClick={() => onSelect(asset)}
@@ -129,7 +129,7 @@ export default function AssetManager({ mode = 'manage', onSelect }: Props) {
</button>
</div>
</div>
<div className="p-2 bg-[var(--surface0)] text-[10px] truncate border-t border-[var(--surface2)]/50 text-[var(--subtext1)] font-mono">{asset.name}</div>
<div className="asset-name p-2 bg-[var(--surface0)] text-[10px] truncate border-t border-[var(--surface2)]/50 text-[var(--subtext1)] font-mono">{asset.name}</div>
</div>
))}
</div>
+144
View File
@@ -2413,6 +2413,21 @@ html.cs-cursor-on.cybersigil .cs-cursor { opacity: 1; }
content: "\00a0]";
color: color-mix(in srgb, currentColor 70%, transparent);
}
/* Icon-only buttons get no brackets — `[ icon ]` reads odd and overflows
* fixed-width chrome. */
.cybersigil .btn--icon::before,
.cybersigil .btn--icon::after { content: none; }
/* Asset-tile hover actions: drop brackets + tighten so Insert+Delete fit
* the small square tiles. */
.cybersigil .asset-actions { gap: 0.4rem; }
.cybersigil .asset-actions .btn::before,
.cybersigil .asset-actions .btn::after { content: none; }
.cybersigil .asset-actions .btn {
letter-spacing: 0.03em;
font-size: 0.66rem;
padding: 0 0.5rem;
}
.cybersigil .asset-actions .btn--icon { padding: 0; }
.cybersigil .btn--primary {
color: var(--rosewater);
border-color: var(--mauve);
@@ -2804,6 +2819,135 @@ html.cs-cursor-on.cybersigil .cs-cursor { opacity: 1; }
font-family: var(--font-sans) !important;
}
/* Asset library — a file-sector readout. Dashed drop-sector, scanline tile
* panels with a thorny sigil growth, `/path` filename bars, log-line alerts. */
.cybersigil .asset-alert {
border-radius: 0 !important;
font-family: var(--font-sans) !important;
font-style: normal !important;
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.74rem !important;
}
.cybersigil .asset-alert::before {
font-weight: 700;
margin-right: 0.5em;
}
.cybersigil .asset-alert--ok::before { content: ">> "; }
.cybersigil .asset-alert--err::before { content: "!! "; }
.cybersigil .asset-drop {
border-style: dashed !important;
border-color: color-mix(in srgb, var(--sky) 55%, transparent) !important;
background:
repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0) 0 2px,
color-mix(in srgb, var(--sky) 6%, transparent) 2px 3px,
rgba(0, 0, 0, 0) 3px 4px
),
color-mix(in srgb, var(--surface0) 74%, transparent) !important;
}
.cybersigil .asset-drop:hover {
border-color: var(--mauve) !important;
box-shadow: 0 0 0 1px color-mix(in srgb, var(--mauve) 40%, transparent);
}
.cybersigil .asset-drop svg { stroke-width: 1.5; }
.cybersigil .asset-drop-title {
font-family: var(--font-display) !important;
font-style: normal !important;
text-transform: uppercase;
letter-spacing: 0.04em;
text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve);
}
.cybersigil .asset-drop-title::before {
content: "> ";
color: var(--sky);
}
.cybersigil .asset-drop-title::after {
content: "_";
color: var(--mauve);
animation: cs-blink 1.05s steps(1, jump-none) infinite;
}
.cybersigil .asset-empty {
font-family: var(--font-sans);
font-style: normal;
text-transform: uppercase;
letter-spacing: 0.16em;
color: var(--subtext0);
}
.cybersigil .asset-empty::before { content: "// "; color: var(--sky); opacity: 0.7; }
.cybersigil .asset-tile {
border-radius: 0 !important;
border-color: color-mix(in srgb, var(--sky) 26%, transparent) !important;
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--sky) 16%, transparent),
0 0 0 1px color-mix(in srgb, var(--sky) 10%, transparent) !important;
transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
}
.cybersigil .asset-tile::after {
content: "";
position: absolute;
top: 3px;
left: 3px;
width: 26px;
height: 26px;
z-index: 2;
background-color: color-mix(in srgb, var(--sky) 70%, transparent);
-webkit-mask: var(--cs-corner) center / contain no-repeat;
mask: var(--cs-corner) center / contain no-repeat;
pointer-events: none;
transition: background-color 0.16s ease;
}
.cybersigil .asset-tile:hover {
border-color: var(--mauve) !important;
transform: translateY(-2px);
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--mauve) 36%, transparent),
4px 4px 0 0 var(--mauve) !important;
}
.cybersigil .asset-tile:hover::after {
background-color: var(--mauve);
}
.cybersigil .asset-thumb {
background:
repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0) 0 2px,
color-mix(in srgb, var(--sky) 7%, transparent) 2px 3px,
rgba(0, 0, 0, 0) 3px 4px
),
var(--mantle);
}
.cybersigil .asset-thumb > div span {
font-family: var(--font-sans) !important;
color: var(--sky);
letter-spacing: 0.1em;
}
.cybersigil .asset-tile:hover .asset-thumb img {
filter:
drop-shadow(-2px 0 0 color-mix(in srgb, var(--mauve) 60%, transparent))
drop-shadow(2px 0 0 color-mix(in srgb, var(--sky) 60%, transparent))
saturate(0.92) contrast(1.05);
}
.cybersigil .asset-actions {
background: color-mix(in srgb, var(--crust) 82%, transparent) !important;
}
.cybersigil .asset-name {
font-family: var(--font-sans) !important;
color: var(--sky);
border-top-color: color-mix(in srgb, var(--sky) 30%, transparent) !important;
background: var(--crust) !important;
letter-spacing: 0.02em;
}
.cybersigil .asset-name::before { content: "/"; opacity: 0.55; }
.cybersigil .asset-tile:hover .asset-name {
color: var(--mauve);
border-top-color: color-mix(in srgb, var(--mauve) 45%, transparent) !important;
}
/* Confirm dialog — hard terminal halt prompt. */
.cybersigil .cdialog-panel {
border-radius: 0;