feat: add self-contained link composer
Build and Push Docker Container / build-and-push (push) Successful in 1m36s
Build and Push Docker Container / build-and-push (push) Successful in 1m36s
- Add structured URL codec with compact alphabets and dictionary support. - Add public decode, redirect, and QR endpoints for composed links. - Add authenticated encode API and link composer UI. - Generate PNG QR codes via qrcode with Pillow support. - Register the new blueprint and navigation entry. - Cover public decode, auth gating, redirect URL parsing, and QR output. - Bump NanoShare to 1.27.0 and lock new dependencies.
This commit is contained in:
@@ -48,9 +48,14 @@
|
||||
}
|
||||
|
||||
/* Globale Stile */
|
||||
html, body {
|
||||
height: -webkit-fill-available;
|
||||
height: 100%;
|
||||
html {
|
||||
min-height: 100%;
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: Arial, sans-serif;
|
||||
@@ -300,6 +305,8 @@ body{
|
||||
radial-gradient(1200px 600px at 10% -10%, rgba(124,158,255,.18), transparent 60%),
|
||||
radial-gradient(900px 500px at 110% 10%, rgba(142,246,255,.18), transparent 60%),
|
||||
var(--bg);
|
||||
background-attachment: fixed;
|
||||
background-repeat: no-repeat;
|
||||
font:500 14px/1.5 system-ui,-apple-system,Segoe UI,Inter,Roboto,"Helvetica Neue",Arial,"Noto Sans","Apple Color Emoji","Segoe UI Emoji";
|
||||
}
|
||||
|
||||
@@ -528,6 +535,40 @@ input[type="file"]{display:none}
|
||||
.toast.show{display:flex;animation:pop .18s ease-out}
|
||||
@keyframes pop{from{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}
|
||||
|
||||
/* ====== Link Composer ====== */
|
||||
.link-composer{max-width:1400px;width:min(1400px, calc(100% - 32px));padding:clamp(18px,2.6vw,34px)}
|
||||
.link-composer .hero-card{margin-bottom:22px;padding:clamp(24px,3vw,36px)}
|
||||
.link-composer .composer-card,.link-composer .result-panel{padding:clamp(24px,3vw,36px)}
|
||||
.composer-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px;margin-bottom:24px}
|
||||
.composer-grid.is-single{grid-template-columns:1fr}
|
||||
@media (max-width:860px){.composer-grid{grid-template-columns:1fr}}
|
||||
.composer-card textarea{
|
||||
width:100%;height:190px;min-height:190px;resize:vertical;border-radius:14px;border:1px solid var(--border);
|
||||
background:color-mix(in srgb,var(--panel) 88%, transparent);color:var(--text);padding:16px 18px;
|
||||
}
|
||||
.composer-card textarea:focus{outline:none;border-color:color-mix(in srgb,var(--accent) 50%, var(--border));box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 25%, transparent)}
|
||||
.composer-card textarea:disabled,.composer-card button:disabled{opacity:.55;cursor:not-allowed}
|
||||
.card-heading{display:flex;justify-content:space-between;gap:12px;align-items:center;margin-bottom:14px}
|
||||
.card-heading h2{margin:0;font-size:1.25rem}
|
||||
.badge-warning{color:#ffd37a;background:rgba(255,211,122,.12);border-color:rgba(255,211,122,.35)}
|
||||
.notice{display:grid;gap:4px;margin:10px 0 16px;padding:12px;border:1px solid rgba(255,211,122,.35);border-radius:12px;background:rgba(255,211,122,.08);color:var(--muted)}
|
||||
.switch-row{display:flex;align-items:center;gap:10px;margin:12px 0;color:var(--muted);font-weight:700}
|
||||
.switch-row-spacer{visibility:hidden;pointer-events:none}
|
||||
.switch-row input{accent-color:var(--accent)}
|
||||
.actions-row{display:flex;gap:12px;flex-wrap:wrap;margin-top:18px}.actions-row.centered{justify-content:center}
|
||||
.form-error{display:none;margin-top:12px;padding:12px;border-radius:12px;border:1px solid rgba(255,122,122,.45);background:rgba(255,122,122,.10);color:#ffd5d5}.form-error.visible{display:block}
|
||||
.result-panel{display:none}.result-panel.visible{display:block}
|
||||
.result-grid{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:24px;align-items:stretch}
|
||||
@media (max-width:820px){.result-grid{grid-template-columns:1fr}}
|
||||
.output-block{margin-top:12px}.output-label{display:block;color:var(--muted);font-size:.78rem;font-weight:800;text-transform:uppercase;letter-spacing:.08em;margin-bottom:7px}
|
||||
.copy-field{display:flex;gap:10px;align-items:center;justify-content:space-between;border:1px solid var(--border);border-radius:12px;background:rgba(0,0,0,.16);padding:10px 12px;overflow-wrap:anywhere}
|
||||
.copy-field code{font:700 .93rem ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:var(--text)}
|
||||
.btn.mini{padding:.4rem .6rem;font-size:.82rem;flex:0 0 auto}
|
||||
.stats-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-top:14px}
|
||||
@media (max-width:620px){.stats-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
||||
.stat-card{border:1px solid var(--border);border-radius:12px;background:rgba(0,0,0,.16);padding:12px}.stat-card strong{display:block;font-size:1.15rem}.stat-card span{color:var(--muted);font-size:.82rem}
|
||||
.qr-card{display:flex;flex-direction:column;gap:12px;justify-content:space-between;align-items:center;border:1px solid var(--border);border-radius:14px;background:rgba(0,0,0,.12);padding:14px}.qr-card img{max-width:230px;width:100%;background:#fff;border-radius:12px;padding:10px}
|
||||
|
||||
/* ====== Utilities ====== */
|
||||
.sr-only{
|
||||
position:absolute !important;width:1px;height:1px;padding:0;margin:-1px;
|
||||
|
||||
Reference in New Issue
Block a user