openvibers/openvibe.shared ov-upload.css

ov-upload.css

main 7.8 KB · 69 lines · css

1/* openvibe-shared ov-upload (designed 11-09): a picker that says what to do, each file a row with its own progress,
2 the total above them for two or more. The network's theme variables; dark and light; Calm keeps the fill, not the sheen. */
3.ov-upload { display: grid; gap: 12px; color: var(--text-primary, #e8ecf3); }
4.ov-upload__input { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
5.ov-upload__picker { display: grid; place-items: center; align-content: center; gap: 6px; width: 100%; min-height: 148px; padding: 22px; border: 1.5px dashed color-mix(in srgb, var(--accent, #3b82f6) 45%, var(--border, rgba(255,255,255,.14)));
6 border-radius: 18px; background: color-mix(in srgb, var(--accent, #3b82f6) 5%, transparent); color: inherit; font: inherit; cursor: pointer; transition: background .18s, border-color .18s, transform .18s; }
7.ov-upload__picker strong { font-size: 15.5px; }
8.ov-upload__picker:hover, .ov-upload.is-dragging .ov-upload__picker { border-color: var(--accent, #3b82f6); background: color-mix(in srgb, var(--accent, #3b82f6) 11%, transparent); }
9.ov-upload.is-dragging .ov-upload__picker { transform: scale(1.01); border-style: solid; }
10.ov-upload__picker:active { transform: scale(.99); }
11.ov-upload__picker:focus-visible, .ov-upload__remove:focus-visible, .ov-progress__retry:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: 3px; }
12.ov-upload__icon { display: grid; place-items: center; width: 52px; height: 52px; margin-bottom: 4px; border-radius: 16px; color: var(--on-accent-strong, #fff);
13 background: linear-gradient(150deg, var(--accent, #3b82f6), var(--accent-strong, #2563eb)); box-shadow: 0 8px 22px color-mix(in srgb, var(--accent, #3b82f6) 35%, transparent); }
14.ov-upload__icon svg, .ov-upload__preview svg, .ov-upload__remove svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
15.ov-upload__icon svg { width: 26px; height: 26px; }
16.ov-upload.is-dragging .ov-upload__icon { animation: ov-upload-bob .9s ease-in-out infinite; }
17.ov-upload__drop { font-size: 13px; color: var(--text-muted, #93a0b4); }
18.ov-upload__total { padding: 0 2px; }
19.ov-upload__total[hidden] { display: none; }
20.ov-upload__rows { display: grid; gap: 8px; }
21.ov-upload__row { display: grid; grid-template-columns: 52px minmax(0, 1fr) 40px; align-items: center; gap: 4px 12px; min-width: 0; padding: 10px;
22 border-radius: 14px; background: color-mix(in srgb, var(--text-primary, #e8ecf3) 4%, transparent); box-shadow: inset 0 0 0 1px var(--border, rgba(255,255,255,.08));
23 animation: ov-upload-in .26s cubic-bezier(.2, .8, .2, 1) both; }
24.ov-upload__preview { display: grid; place-items: center; width: 52px; height: 52px; overflow: hidden; border-radius: 10px; color: var(--accent-light, var(--accent, #60a5fa));
25 background: color-mix(in srgb, var(--accent, #3b82f6) 12%, transparent); }
26.ov-upload__preview svg { width: 24px; height: 24px; }
27.ov-upload__preview img, .ov-upload__preview video { width: 100%; height: 100%; object-fit: cover; }
28.ov-upload__file { display: grid; gap: 1px; min-width: 0; }
29.ov-upload__file strong { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 14.5px; }
30.ov-upload__file small { font-size: 12.5px; color: var(--text-muted, #93a0b4); }
31.ov-upload__remove { display: grid; place-items: center; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--text-secondary, #a8b3c4); cursor: pointer; }
32.ov-upload__remove svg { width: 18px; height: 18px; }
33@media (hover: hover) { .ov-upload__remove:hover { background: color-mix(in srgb, var(--text-primary, #e8ecf3) 9%, transparent); color: var(--text-primary, #e8ecf3); } }
34.ov-upload__meter { grid-column: 1 / -1; }
35/* Progress */
36.ov-progress { display: grid; gap: 7px; }
37.ov-progress__heading { display: flex; justify-content: space-between; align-items: center; gap: 12px; font-size: 14px; font-weight: 650; }
38.ov-progress__percent { font-variant-numeric: tabular-nums; }
39.ov-progress__track { height: 8px; overflow: hidden; border-radius: 99px; background: color-mix(in srgb, var(--text-primary, #e8ecf3) 10%, transparent); }
40.ov-progress__fill { position: relative; width: 0; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--accent-strong, #2563eb), var(--accent, #3b82f6)); transition: width .65s cubic-bezier(.2, .7, .2, 1); }
41.ov-progress[data-state="sending"] .ov-progress__fill::after { content: ''; position: absolute; inset: 0; background: linear-gradient(110deg, transparent 25%, rgba(255,255,255,.3) 45%, transparent 65%); animation: ov-upload-sheen 1.8s linear infinite; }
42.ov-progress[data-state="processing"] .ov-progress__fill { width: 100% !important; animation: ov-upload-pulse 1.8s ease-in-out infinite; }
43.ov-progress[data-state="done"] .ov-progress__fill { background: var(--success, #22c55e); }
44.ov-progress[data-state="done"] .ov-progress__percent { color: var(--success, #22c55e); animation: ov-upload-check .38s ease-out both; }
45.ov-progress__check { display: block; width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
46.ov-progress__check path { stroke-dasharray: 24; stroke-dashoffset: 24; animation: ov-upload-draw .45s ease-out forwards; }
47.ov-progress[data-state="failed"] .ov-progress__fill { background: var(--danger, #ef4444); }
48.ov-progress[data-state="failed"] .ov-progress__label { color: var(--danger, #ef4444); }
49.ov-progress__detail { min-height: 1.4em; margin: 0; font-size: 12.5px; color: var(--text-muted, #93a0b4); font-variant-numeric: tabular-nums; }
50.ov-progress__retry { justify-self: start; min-height: 36px; padding: 0 14px; border: 0; border-radius: 999px; background: color-mix(in srgb, var(--text-primary, #e8ecf3) 9%, transparent); color: inherit; font: inherit; font-size: 13.5px; font-weight: 650; cursor: pointer; }
51/* Inside a file's row: one line of state and percent, a thin bar, the numbers. */
52.ov-progress--row { gap: 5px; margin-top: 6px; }
53.ov-progress--row .ov-progress__heading { font-size: 12.5px; color: var(--text-secondary, #a8b3c4); }
54.ov-progress--row .ov-progress__track { height: 5px; }
55.ov-progress--row .ov-progress__detail { font-size: 12px; }
56@keyframes ov-upload-sheen { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
57@keyframes ov-upload-pulse { 50% { opacity: .5; } }
58@keyframes ov-upload-check { from { transform: scale(.5); opacity: 0; } to { transform: scale(1); opacity: 1; } }
59/* "You already uploaded this": the note, then the three ways on, as one block under the file's row. */
60.ov-upload__duplicate-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 8px; padding: 10px 12px; border-radius: 14px; background: color-mix(in srgb, var(--accent, #3b82f6) 9%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent, #3b82f6) 24%, transparent); animation: ov-upload-in .3s cubic-bezier(.2, .9, .3, 1.1) both; }
61.ov-upload__duplicate-note { flex: 1 0 100%; margin: 0 0 2px; font-size: 13.5px; font-weight: 650; color: var(--text-primary, #e6edf7); }
62.ov-upload__duplicate-actions .ovk-btn { min-height: 40px; }
63@media (pointer: coarse) { .ov-upload__duplicate-actions .ovk-btn { min-height: 44px; flex: 1 1 auto; } }
64@keyframes ov-upload-draw { to { stroke-dashoffset: 0; } }
65@keyframes ov-upload-in { from { opacity: 0; transform: translateY(6px); } }
66@keyframes ov-upload-bob { 50% { transform: translateY(-3px); } }
67@media (pointer: coarse), (max-width: 700px) { .ov-upload__picker { min-height: 120px; } .ov-upload__drop { display: none; } }
68html[data-ov-motion=off] .ov-progress__check path{stroke-dashoffset: 0}html[data-ov-motion=off] .ov-progress[data-state="sending"] .ov-progress__fill::after{display: none}
69