aboutsummaryrefslogtreecommitdiff
path: root/public/app.css
diff options
context:
space:
mode:
authordax <me@dax.ist>2026-08-04 16:54:07 +0100
committerdax <me@dax.ist>2026-08-04 16:54:07 +0100
commitdadf0909dd235a7764a59a63d2b51861fa81e385 (patch)
treefad8563b7c2d9f7f9216b001a1f89ba5db5f5479 /public/app.css
parent6a0dc37b2e5580987df8fd11becdff53b32c9836 (diff)
add photo import: upload -> photoprism, fix desktop file dialog
- POST /api/import with native multipart parser (no new deps); stages files then delegates indexing+thumbnailing to PhotoPrism via `photoprism cp` - pathways reflects new photos immediately via refresh() - upload UI shown only in empty-library state - nixos: PHOTOPRISM_READONLY=false; pathways service gets STAGING_ROOT and photoprism env; PATH includes /run/wrappers/bin so sudo is found - fix: stage.setPointerCapture was swallowing the import label's click on desktop, preventing the native file dialog from opening
Diffstat (limited to 'public/app.css')
-rw-r--r--public/app.css117
1 files changed, 109 insertions, 8 deletions
diff --git a/public/app.css b/public/app.css
index 8a1b201..24bb927 100644
--- a/public/app.css
+++ b/public/app.css
@@ -25,6 +25,10 @@ html, body {
user-select: none;
}
+#stage.blocked {
+ pointer-events: none;
+}
+
#world {
position: absolute;
left: 0;
@@ -128,22 +132,35 @@ html, body {
}
}
-#splash {
+#import-state {
position: fixed;
inset: 0;
+ z-index: 10;
display: grid;
place-content: center;
justify-items: center;
gap: 14px;
text-align: center;
- background: var(--bg);
- z-index: 10;
- transition: opacity .4s, visibility .4s;
+ padding: 24px;
+ pointer-events: auto;
+}
+#import-state[hidden] { display: none; }
+
+#file {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0 0 0 0);
+ border: 0;
+ opacity: 0;
}
-#splash.hide { opacity: 0; visibility: hidden; pointer-events: none; }
-#splash h1 { margin: 0; font-size: 44px; font-weight: 300; letter-spacing: .18em; }
-#splash h1 .dot { color: var(--ring); }
-#splash p { max-width: 34ch; color: var(--muted); margin: 0; font-size: 15px; line-height: 1.6; }
+#import-state h1 { margin: 0; font-size: 44px; font-weight: 300; letter-spacing: .18em; }
+#import-state h1 .dot { color: var(--ring); }
+#import-state p { max-width: 34ch; color: var(--muted); margin: 0; font-size: 15px; line-height: 1.6; }
+/* app.css?v=38 */
#start {
margin-top: 10px;
padding: 10px 34px;
@@ -158,7 +175,91 @@ html, body {
}
#start:hover { border-color: var(--ring); background: rgba(125, 211, 252, .08); }
+#import {
+ margin-top: 14px;
+ position: relative;
+ z-index: 11;
+ display: inline-flex;
+ align-items: center;
+ gap: 9px;
+ padding: 10px 22px;
+ font-size: 14px;
+ letter-spacing: .06em;
+ border: 1px solid rgba(255, 255, 255, .3);
+ border-radius: 999px;
+ background: transparent;
+ color: var(--ink);
+ cursor: pointer;
+ opacity: 0;
+ transform: translateY(6px);
+ transition: opacity .4s, transform .4s, border-color .15s, background .15s;
+}
+#import:not([hidden]) { opacity: 1; transform: translateY(0); }
+#import svg {
+ width: 17px;
+ height: 17px;
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.7;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+#import:hover { border-color: var(--ring); background: rgba(125, 211, 252, .08); }
+#import.busy {
+ border-color: var(--ring);
+ color: var(--ring);
+ pointer-events: none;
+ animation: pulse 1.1s ease-in-out infinite;
+}
+#import[hidden] { display: none; }
+
+@keyframes pulse {
+ 0%, 100% { opacity: .55; }
+ 50% { opacity: 1; }
+}
+
+#drop {
+ position: fixed;
+ inset: 0;
+ z-index: 9;
+ display: grid;
+ place-content: center;
+ background: rgba(14, 15, 19, .82);
+ border: 2px dashed rgba(125, 211, 252, .55);
+ color: var(--ink);
+ font-size: 16px;
+ letter-spacing: .1em;
+ opacity: 0;
+ visibility: hidden;
+ pointer-events: none;
+ transition: opacity .15s, visibility .15s;
+}
+#drop.show { opacity: 1; visibility: visible; pointer-events: auto; }
+
+#toast {
+ position: fixed;
+ right: 18px;
+ bottom: 72px;
+ z-index: 8;
+ max-width: 46ch;
+ padding: 9px 15px;
+ border: 1px solid rgba(255, 255, 255, .18);
+ border-radius: 8px;
+ background: rgba(14, 15, 19, .94);
+ color: var(--ink);
+ font-size: 13px;
+ line-height: 1.5;
+ opacity: 0;
+ visibility: hidden;
+ pointer-events: none;
+ transform: translateY(4px);
+ transition: opacity .2s, visibility .2s, transform .2s;
+}
+#toast.show { opacity: 1; visibility: visible; pointer-events: auto; }
+#toast.err { border-color: rgba(248, 113, 113, .6); color: #fca5a5; }
+
@media (prefers-reduced-motion: reduce) {
#world { transition: none; }
.tile.lock { animation: none; }
+ #upload.busy { animation: none; }
}