feat(web): SVG download overlay, toast icons, initials placeholder, empty state hint, footer
This commit is contained in:
@@ -39,6 +39,8 @@
|
|||||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subtle dot grid background */
|
/* Subtle dot grid background */
|
||||||
@@ -256,7 +258,7 @@
|
|||||||
.dismiss-btn:hover { color: var(--text); background: var(--border); }
|
.dismiss-btn:hover { color: var(--text); background: var(--border); }
|
||||||
|
|
||||||
/* ── Main ────────────────────────────────────────────────────────────── */
|
/* ── Main ────────────────────────────────────────────────────────────── */
|
||||||
main { padding: 32px 28px; }
|
main { padding: 32px 28px; flex: 1; }
|
||||||
|
|
||||||
/* ── Library toolbar ─────────────────────────────────────────────────── */
|
/* ── Library toolbar ─────────────────────────────────────────────────── */
|
||||||
.library-toolbar {
|
.library-toolbar {
|
||||||
@@ -400,15 +402,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Download overlay on hover */
|
/* Download overlay on hover */
|
||||||
.comic-card::after {
|
.comic-download-overlay {
|
||||||
content: '↓';
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 2.2rem;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: rgba(91, 140, 245, 0.72);
|
background: rgba(91, 140, 245, 0.72);
|
||||||
backdrop-filter: blur(3px);
|
backdrop-filter: blur(3px);
|
||||||
@@ -418,7 +417,7 @@
|
|||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comic-card:hover::after { opacity: 1; }
|
.comic-card:hover .comic-download-overlay { opacity: 1; }
|
||||||
|
|
||||||
.comic-cover-placeholder {
|
.comic-cover-placeholder {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -431,6 +430,15 @@
|
|||||||
|
|
||||||
.comic-cover-placeholder svg { opacity: 0.2; }
|
.comic-cover-placeholder svg { opacity: 0.2; }
|
||||||
|
|
||||||
|
.comic-cover-placeholder .placeholder-initials {
|
||||||
|
font-size: 3.5rem;
|
||||||
|
font-weight: 800;
|
||||||
|
color: rgba(255,255,255,0.18);
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
.comic-info {
|
.comic-info {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0; left: 0; right: 0;
|
bottom: 0; left: 0; right: 0;
|
||||||
@@ -534,6 +542,20 @@
|
|||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-hint {
|
||||||
|
font-size: 0.76rem !important;
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--muted) !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-hint svg {
|
||||||
|
flex-shrink: 0;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Toasts ──────────────────────────────────────────────────────────── */
|
/* ── Toasts ──────────────────────────────────────────────────────────── */
|
||||||
#toast {
|
#toast {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -565,11 +587,40 @@
|
|||||||
.toast-msg.is-error { border-left-color: var(--error); }
|
.toast-msg.is-error { border-left-color: var(--error); }
|
||||||
.toast-msg.fade { opacity: 0; }
|
.toast-msg.fade { opacity: 0; }
|
||||||
|
|
||||||
|
.toast-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 7px;
|
||||||
|
vertical-align: middle;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes slideIn {
|
@keyframes slideIn {
|
||||||
from { transform: translateX(32px); opacity: 0; }
|
from { transform: translateX(32px); opacity: 0; }
|
||||||
to { transform: translateX(0); opacity: 1; }
|
to { transform: translateX(0); opacity: 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Footer ──────────────────────────────────────────────────────────── */
|
||||||
|
footer {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 28px;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
color: var(--muted);
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: var(--muted);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover { color: var(--text2); }
|
||||||
|
|
||||||
/* ── Responsive — tablet ─────────────────────────────────────────────── */
|
/* ── Responsive — tablet ─────────────────────────────────────────────── */
|
||||||
@media (max-width: 860px) {
|
@media (max-width: 860px) {
|
||||||
.url-form { max-width: 100%; }
|
.url-form { max-width: 100%; }
|
||||||
@@ -693,9 +744,20 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<p>No comics yet — paste a URL above to start building your library.</p>
|
<p>No comics yet — paste a URL above to start building your library.</p>
|
||||||
|
<p class="empty-hint">
|
||||||
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M12 19V5M5 12l7-7 7 7"/>
|
||||||
|
</svg>
|
||||||
|
Your downloaded comics will appear here
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<a href="https://github.com/brizzbuzz/yoink-go" target="_blank" rel="noopener">Yoink</a>
|
||||||
|
· v1.1.0
|
||||||
|
</footer>
|
||||||
|
|
||||||
<div id="toast"></div>
|
<div id="toast"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -917,12 +979,19 @@
|
|||||||
img.src = comic.cover_url;
|
img.src = comic.cover_url;
|
||||||
img.alt = comic.title;
|
img.alt = comic.title;
|
||||||
img.loading = 'lazy';
|
img.loading = 'lazy';
|
||||||
img.onerror = () => img.replaceWith(makePlaceholder());
|
img.onerror = () => img.replaceWith(makePlaceholder(comic.title));
|
||||||
a.append(img);
|
a.append(img);
|
||||||
} else {
|
} else {
|
||||||
a.append(makePlaceholder());
|
a.append(makePlaceholder(comic.title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.className = 'comic-download-overlay';
|
||||||
|
overlay.innerHTML = `<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M12 3v13M5 14l7 7 7-7"/><path d="M3 21h18"/>
|
||||||
|
</svg>`;
|
||||||
|
a.append(overlay);
|
||||||
|
|
||||||
const info = document.createElement('div');
|
const info = document.createElement('div');
|
||||||
info.className = 'comic-info';
|
info.className = 'comic-info';
|
||||||
|
|
||||||
@@ -936,15 +1005,26 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePlaceholder() {
|
function makePlaceholder(title) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = 'comic-cover-placeholder';
|
div.className = 'comic-cover-placeholder';
|
||||||
|
if (title) {
|
||||||
|
const words = title.trim().split(/\s+/).filter(Boolean);
|
||||||
|
const initials = words.length === 1
|
||||||
|
? words[0].slice(0, 2)
|
||||||
|
: (words[0][0] + words[1][0]);
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.className = 'placeholder-initials';
|
||||||
|
span.textContent = initials.toUpperCase();
|
||||||
|
div.append(span);
|
||||||
|
} else {
|
||||||
div.innerHTML = `
|
div.innerHTML = `
|
||||||
<svg width="40" height="40" viewBox="0 0 24 24" fill="none"
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none"
|
||||||
stroke="currentColor" stroke-width="1.2">
|
stroke="currentColor" stroke-width="1.2">
|
||||||
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
||||||
<path d="M3 9h18M9 21V9"/>
|
<path d="M3 9h18M9 21V9"/>
|
||||||
</svg>`;
|
</svg>`;
|
||||||
|
}
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,7 +1042,20 @@
|
|||||||
function toast(msg, isError = false) {
|
function toast(msg, isError = false) {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'toast-msg' + (isError ? ' is-error' : '');
|
el.className = 'toast-msg' + (isError ? ' is-error' : '');
|
||||||
el.textContent = msg;
|
|
||||||
|
const icon = document.createElement('span');
|
||||||
|
icon.className = 'toast-icon';
|
||||||
|
if (isError) {
|
||||||
|
icon.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--error)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="10"/><path d="M15 9l-6 6M9 9l6 6"/>
|
||||||
|
</svg>`;
|
||||||
|
} else {
|
||||||
|
icon.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--success)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="10"/><path d="M8 12l3 3 5-5"/>
|
||||||
|
</svg>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
el.append(icon, document.createTextNode(msg));
|
||||||
toastEl.append(el);
|
toastEl.append(el);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
el.classList.add('fade');
|
el.classList.add('fade');
|
||||||
|
|||||||
Reference in New Issue
Block a user