v2.0.13 — edge-to-edge fullscreen overlays, rounded-cards badge variant
- Overlays: drop the 24/40/54px inset frame on tasks, calendar,
gallery, search, detail, edit modal, bookmarks, email, gitea and
oumta-dashboard so they fill the viewport like the support
overlay does. Removed the shared border-radius + overflow:hidden
rule on their inner containers (only settings + dialog still use
it) so the card's top colour bar isn't clipped.
- Done badge: the corner-triangle variant gets chopped by rounded
card borders. applyDesign now toggles body.rounded-cards whenever
--ui-radius-card > 0, and the CSS swaps the triangle for a 18px
circle pill with the check centred. Triangle stays for square
cards.
- Support plugin: "Close ticket" button is a regular labelled
button now (was a 30×30 icon ghost that clipped the text). Empty
hero state ("select a ticket") matches the board's empty style —
centred in the column with a pixel-font blink-cursor label.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
7bce6a3a36
commit
8cbec8d601
11 files changed
+66
-30
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
define('APP_NAME', 'hyprcrd');
|
define('APP_NAME', 'hyprcrd');
|
||||||
define('APP_VERSION', '2.0.12');
|
define('APP_VERSION', '2.0.13');
|
||||||
|
|
||||||
// APP_DEBUG: gates verbose error responses (curl traces, upstream bodies).
|
// APP_DEBUG: gates verbose error responses (curl traces, upstream bodies).
|
||||||
// Off by default; enable via env for local troubleshooting only.
|
// Off by default; enable via env for local troubleshooting only.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hyprcrd",
|
"name": "hyprcrd",
|
||||||
"version": "2.0.12",
|
"version": "2.0.13",
|
||||||
"description": "hyprcrd — self-hosted card manager",
|
"description": "hyprcrd — self-hosted card manager",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+20
-10
@@ -109,17 +109,14 @@ select[class*="border-t-accent"] {
|
|||||||
.prose img { border-radius: var(--ui-radius-image); }
|
.prose img { border-radius: var(--ui-radius-image); }
|
||||||
.board-card.card-has-cover { border-radius: var(--ui-radius-card); }
|
.board-card.card-has-cover { border-radius: var(--ui-radius-card); }
|
||||||
|
|
||||||
/* Modal containers (the inner box of each overlay) */
|
/* Modal containers (the inner box of each overlay). Only for floating /
|
||||||
#modal > div,
|
* framed modals — the fullscreen overlays (modal, detail, search, tasks,
|
||||||
#detail > div,
|
* calendar, gallery, and the support / plugin overlays) fill the whole
|
||||||
|
* viewport now and don't want the rounded-corner + overflow:hidden
|
||||||
|
* combo, which would clip the top color bar and soften the edge-to-edge
|
||||||
|
* look. */
|
||||||
#settings-overlay > div,
|
#settings-overlay > div,
|
||||||
#search > div,
|
#dialog > div {
|
||||||
#tasks > div,
|
|
||||||
#calendar > div,
|
|
||||||
#gallery > div,
|
|
||||||
#dialog > div,
|
|
||||||
#detail > div,
|
|
||||||
#modal > div {
|
|
||||||
border-radius: var(--ui-radius-modal);
|
border-radius: var(--ui-radius-modal);
|
||||||
box-shadow: var(--ui-shadow-modal);
|
box-shadow: var(--ui-shadow-modal);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -402,6 +399,19 @@ body.settings-peeking #settings-overlay > div { pointer-events: auto; }
|
|||||||
.due-pill { display: inline-flex; align-items: center; gap: 3px; padding: 0 5px; border-radius: 8px; font-size: 9px; line-height: 16px; color: var(--t-bg); font-family: var(--t-font-pixel); }
|
.due-pill { display: inline-flex; align-items: center; gap: 3px; padding: 0 5px; border-radius: 8px; font-size: 9px; line-height: 16px; color: var(--t-bg); font-family: var(--t-font-pixel); }
|
||||||
.card-done-badge { position: absolute; bottom: 0; right: 0; width: 0; height: 0; border-style: solid; border-width: 0 0 24px 24px; border-color: transparent transparent #4ade80 transparent; z-index: 1; }
|
.card-done-badge { position: absolute; bottom: 0; right: 0; width: 0; height: 0; border-style: solid; border-width: 0 0 24px 24px; border-color: transparent transparent #4ade80 transparent; z-index: 1; }
|
||||||
.card-done-badge i { position: absolute; bottom: -22px; right: 1px; font-size: 10px; color: #000; }
|
.card-done-badge i { position: absolute; bottom: -22px; right: 1px; font-size: 10px; color: #000; }
|
||||||
|
/* Rounded-cards variant: the corner triangle gets clipped by the
|
||||||
|
* rounded border, so toggle to a circle pill that sits comfortably
|
||||||
|
* inside any radius. JS adds `rounded-cards` on body whenever
|
||||||
|
* --ui-radius-card is > 0. */
|
||||||
|
body.rounded-cards .card-done-badge {
|
||||||
|
width: 18px; height: 18px;
|
||||||
|
bottom: 6px; right: 6px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #4ade80;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
}
|
||||||
|
body.rounded-cards .card-done-badge i { position: static; bottom: auto; right: auto; font-size: 11px; color: #000; font-weight: bold; }
|
||||||
.board-card:has(.card-bar-pulse) .card-bar-pulse ~ * .text-t-danger { animation: pulse-glow 2s ease-in-out infinite; }
|
.board-card:has(.card-bar-pulse) .card-bar-pulse ~ * .text-t-danger { animation: pulse-glow 2s ease-in-out infinite; }
|
||||||
.card-spinner { animation: spin 0.8s linear infinite; display: inline-block; }
|
.card-spinner { animation: spin 0.8s linear infinite; display: inline-block; }
|
||||||
|
|
||||||
|
|||||||
+11
-6
@@ -1516,6 +1516,11 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
if (d.animSpeed === 'off') document.body.classList.add('anim-off');
|
if (d.animSpeed === 'off') document.body.classList.add('anim-off');
|
||||||
if (d.animSpeed === 'fast') document.body.classList.add('anim-fast');
|
if (d.animSpeed === 'fast') document.body.classList.add('anim-fast');
|
||||||
if (d.animSpeed === 'slow') document.body.classList.add('anim-slow');
|
if (d.animSpeed === 'slow') document.body.classList.add('anim-slow');
|
||||||
|
// Rounded-card badge variant: the default "done" corner triangle
|
||||||
|
// gets clipped by a rounded border, so when the user opts into
|
||||||
|
// rounded cards we swap it for a circle pill in the BR corner
|
||||||
|
// (see .rounded-cards .card-done-badge in style.css).
|
||||||
|
document.body.classList.toggle('rounded-cards', (Number(d.radiusCard) || 0) > 0);
|
||||||
};
|
};
|
||||||
window.loadDesign = function() {
|
window.loadDesign = function() {
|
||||||
let saved = {};
|
let saved = {};
|
||||||
@@ -2288,7 +2293,7 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
|
|
||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
<div class="overlay fixed inset-0 z-[70]" style="background:var(--t-overlay)" id="search">
|
<div class="overlay fixed inset-0 z-[70]" style="background:var(--t-overlay)" id="search">
|
||||||
<div class="bg-t-surface border border-t-border rounded-sm shadow-2xl flex flex-col absolute" style="inset:40px;">
|
<div class="bg-t-surface flex flex-col absolute" style="inset:0;">
|
||||||
<div class="flex flex-col border-b border-t-border">
|
<div class="flex flex-col border-b border-t-border">
|
||||||
<div class="flex items-center gap-3 px-4 py-3">
|
<div class="flex items-center gap-3 px-4 py-3">
|
||||||
<i class="ph ph-magnifying-glass text-t-accent text-base"></i>
|
<i class="ph ph-magnifying-glass text-t-accent text-base"></i>
|
||||||
@@ -2341,7 +2346,7 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
|
|
||||||
<!-- Tasks -->
|
<!-- Tasks -->
|
||||||
<div class="overlay fixed inset-0 z-[72]" style="background:var(--t-overlay)" id="tasks">
|
<div class="overlay fixed inset-0 z-[72]" style="background:var(--t-overlay)" id="tasks">
|
||||||
<div class="bg-t-surface border border-t-border rounded-sm shadow-2xl flex flex-col absolute" style="inset:54px;">
|
<div class="bg-t-surface flex flex-col absolute" style="inset:0;">
|
||||||
<div class="flex items-center gap-3 px-4 py-3 border-b border-t-border">
|
<div class="flex items-center gap-3 px-4 py-3 border-b border-t-border">
|
||||||
<i class="ph ph-check-square-offset text-t-accent2 text-base"></i>
|
<i class="ph ph-check-square-offset text-t-accent2 text-base"></i>
|
||||||
<h2 class="font-pixel text-xs text-t-accent2">global_tasks</h2>
|
<h2 class="font-pixel text-xs text-t-accent2">global_tasks</h2>
|
||||||
@@ -2366,7 +2371,7 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
|
|
||||||
<!-- Detail -->
|
<!-- Detail -->
|
||||||
<div class="overlay fixed inset-0 z-[75]" style="background:var(--t-overlay)" id="detail">
|
<div class="overlay fixed inset-0 z-[75]" style="background:var(--t-overlay)" id="detail">
|
||||||
<div class="bg-t-surface border border-t-border flex absolute" style="inset:40px;">
|
<div class="bg-t-surface flex absolute" style="inset:0;">
|
||||||
<!-- Group sidebar (hidden for single cards) -->
|
<!-- Group sidebar (hidden for single cards) -->
|
||||||
<div id="detail-sidebar" class="hidden w-56 shrink-0 border-r border-t-border flex flex-col">
|
<div id="detail-sidebar" class="hidden w-56 shrink-0 border-r border-t-border flex flex-col">
|
||||||
<div class="px-3 py-3 border-b border-t-border flex items-center gap-2">
|
<div class="px-3 py-3 border-b border-t-border flex items-center gap-2">
|
||||||
@@ -2434,7 +2439,7 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
|
|
||||||
<!-- Calendar -->
|
<!-- Calendar -->
|
||||||
<div class="overlay fixed inset-0 z-[73]" style="background:var(--t-overlay)" id="calendar">
|
<div class="overlay fixed inset-0 z-[73]" style="background:var(--t-overlay)" id="calendar">
|
||||||
<div class="bg-t-surface border border-t-border flex flex-col absolute" style="inset:40px;">
|
<div class="bg-t-surface flex flex-col absolute" style="inset:0;">
|
||||||
<div class="flex items-center gap-2 px-5 py-3 border-b border-t-border shrink-0 relative">
|
<div class="flex items-center gap-2 px-5 py-3 border-b border-t-border shrink-0 relative">
|
||||||
<i class="ph ph-calendar-dots text-t-accent text-base"></i>
|
<i class="ph ph-calendar-dots text-t-accent text-base"></i>
|
||||||
<button id="cal-today" class="font-pixel text-[10px] px-2 py-0.5 border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors">Today</button>
|
<button id="cal-today" class="font-pixel text-[10px] px-2 py-0.5 border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors">Today</button>
|
||||||
@@ -2457,7 +2462,7 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
|
|
||||||
<!-- Assets (was Gallery) -->
|
<!-- Assets (was Gallery) -->
|
||||||
<div class="overlay fixed inset-0 z-[72]" style="background:var(--t-overlay)" id="gallery">
|
<div class="overlay fixed inset-0 z-[72]" style="background:var(--t-overlay)" id="gallery">
|
||||||
<div class="bg-t-surface border border-t-border rounded-sm shadow-2xl flex flex-col absolute" style="inset:40px;">
|
<div class="bg-t-surface flex flex-col absolute" style="inset:0;">
|
||||||
<div class="flex items-center gap-3 px-4 py-3 border-b border-t-border shrink-0">
|
<div class="flex items-center gap-3 px-4 py-3 border-b border-t-border shrink-0">
|
||||||
<i class="ph ph-folder-open text-t-accent text-base"></i>
|
<i class="ph ph-folder-open text-t-accent text-base"></i>
|
||||||
<h2 class="font-pixel text-xs text-t-accent">assets</h2>
|
<h2 class="font-pixel text-xs text-t-accent">assets</h2>
|
||||||
@@ -2530,7 +2535,7 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
|
|
||||||
<!-- Editor -->
|
<!-- Editor -->
|
||||||
<div class="overlay fixed inset-0 z-[60]" style="background:var(--t-overlay)" id="modal">
|
<div class="overlay fixed inset-0 z-[60]" style="background:var(--t-overlay)" id="modal">
|
||||||
<div class="bg-t-surface border border-t-border flex flex-col absolute" style="inset:40px;">
|
<div class="bg-t-surface flex flex-col absolute" style="inset:0;">
|
||||||
<div class="card-bar w-full shrink-0" id="editor-color"></div>
|
<div class="card-bar w-full shrink-0" id="editor-color"></div>
|
||||||
<div class="flex items-center justify-between px-4 py-2.5 border-b border-t-border shrink-0">
|
<div class="flex items-center justify-between px-4 py-2.5 border-b border-t-border shrink-0">
|
||||||
<div class="flex items-center gap-3"><i class="ph ph-file-plus text-t-accent text-sm"></i><h2 id="modal-title" class="font-pixel text-xs text-t-accent">new_card</h2></div>
|
<div class="flex items-center gap-3"><i class="ph ph-file-plus text-t-accent text-sm"></i><h2 id="modal-title" class="font-pixel text-xs text-t-accent">new_card</h2></div>
|
||||||
|
|||||||
@@ -53,11 +53,8 @@
|
|||||||
/* Overlay shell */
|
/* Overlay shell */
|
||||||
.bookmarks-shell {
|
.bookmarks-shell {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 40px;
|
inset: 0;
|
||||||
background: var(--t-surface);
|
background: var(--t-surface);
|
||||||
border: 1px solid var(--t-border);
|
|
||||||
border-radius: var(--ui-radius-modal, 4px);
|
|
||||||
box-shadow: 0 8px 40px rgba(0,0,0,0.5);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<!-- Email Plugin: full-screen mail viewer overlay -->
|
<!-- Email Plugin: full-screen mail viewer overlay -->
|
||||||
<div class="overlay fixed inset-0" id="email-overlay" style="z-index:75;">
|
<div class="overlay fixed inset-0" id="email-overlay" style="z-index:75;">
|
||||||
<div class="email-modal bg-t-bg border border-t-border shadow-2xl flex flex-col" style="position:absolute;inset:24px;border-radius:4px;">
|
<div class="email-modal bg-t-bg flex flex-col" style="position:absolute;inset:0;">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="flex items-center gap-3 px-4 py-2 border-b border-t-border shrink-0 bg-t-surface">
|
<div class="flex items-center gap-3 px-4 py-2 border-b border-t-border shrink-0 bg-t-surface">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<!-- Gitea Plugin: full-screen issue browser overlay -->
|
<!-- Gitea Plugin: full-screen issue browser overlay -->
|
||||||
<div class="overlay fixed inset-0" id="gitea-overlay" style="z-index:75;">
|
<div class="overlay fixed inset-0" id="gitea-overlay" style="z-index:75;">
|
||||||
<div class="gitea-modal bg-t-bg border border-t-border shadow-2xl flex flex-col" style="position:absolute;inset:24px;border-radius:4px;">
|
<div class="gitea-modal bg-t-bg flex flex-col" style="position:absolute;inset:0;">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="flex items-center gap-3 px-4 py-2 border-b border-t-border shrink-0 bg-t-surface">
|
<div class="flex items-center gap-3 px-4 py-2 border-b border-t-border shrink-0 bg-t-surface">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div class="overlay fixed inset-0 z-[75]" style="background:var(--t-overlay)" id="oumta-overlay">
|
<div class="overlay fixed inset-0 z-[75]" style="background:var(--t-overlay)" id="oumta-overlay">
|
||||||
<div class="bg-t-surface border border-t-border flex flex-col absolute" style="inset:40px;">
|
<div class="bg-t-surface flex flex-col absolute" style="inset:0;">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="flex items-center gap-3 px-5 py-3 border-b border-t-border shrink-0">
|
<div class="flex items-center gap-3 px-5 py-3 border-b border-t-border shrink-0">
|
||||||
|
|||||||
@@ -124,13 +124,37 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 18px;
|
gap: 18px;
|
||||||
}
|
}
|
||||||
.support-empty, .support-empty-hero {
|
.support-empty {
|
||||||
color: var(--t-dim);
|
color: var(--t-dim);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 40px 20px;
|
padding: 40px 20px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
.support-empty-hero i { font-size: 48px; display: block; margin: 0 auto 12px; color: var(--t-muted); }
|
/* Hero empty-state ("pick a ticket on the left") matches the board's
|
||||||
|
* "no cards found" placeholder: centred in the available column, pixel
|
||||||
|
* font with blink cursor, 4xl dim icon above. flex:1 consumes the
|
||||||
|
* detail column so the axis centring actually has a box to work in. */
|
||||||
|
.support-empty-hero {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.support-empty-hero i {
|
||||||
|
display: block;
|
||||||
|
font-size: 2.25rem; /* matches text-4xl */
|
||||||
|
color: var(--t-dim);
|
||||||
|
margin-bottom: 1rem; /* matches mb-4 */
|
||||||
|
}
|
||||||
|
.support-empty-hero p {
|
||||||
|
margin: 0;
|
||||||
|
font-family: var(--t-font-ui, var(--t-font-pixel, 'Silkscreen', cursive));
|
||||||
|
font-size: 0.875rem; /* text-sm */
|
||||||
|
color: var(--t-dim);
|
||||||
|
}
|
||||||
|
|
||||||
.support-ticket-header h2 { font-family: var(--t-font-pixel); color: var(--t-bright); font-size: 14px; margin: 0 0 4px; }
|
.support-ticket-header h2 { font-family: var(--t-font-pixel); color: var(--t-bright); font-size: 14px; margin: 0 0 4px; }
|
||||||
.support-ticket-header .meta { color: var(--t-dim); font-size: 11px; display: flex; gap: 12px; flex-wrap: wrap; }
|
.support-ticket-header .meta { color: var(--t-dim); font-size: 11px; display: flex; gap: 12px; flex-wrap: wrap; }
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<section id="support-detail" class="support-detail">
|
<section id="support-detail" class="support-detail">
|
||||||
<div class="support-empty-hero">
|
<div class="support-empty-hero">
|
||||||
<i class="ph ph-envelope-open"></i>
|
<i class="ph ph-envelope-open"></i>
|
||||||
<p>Pick a ticket on the left.</p>
|
<p class="cursor-blink">select a ticket</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ function renderDetail(t) {
|
|||||||
const host = $('support-detail');
|
const host = $('support-detail');
|
||||||
if (!host) return;
|
if (!host) return;
|
||||||
if (!t) {
|
if (!t) {
|
||||||
host.innerHTML = `<div class="support-empty-hero"><i class="ph ph-envelope-open"></i><p>Pick a ticket on the left.</p></div>`;
|
host.innerHTML = `<div class="support-empty-hero"><i class="ph ph-envelope-open"></i><p class="cursor-blink">select a ticket</p></div>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const replies = (t.replies || []).map(r => `
|
const replies = (t.replies || []).map(r => `
|
||||||
@@ -168,7 +168,7 @@ function renderDetail(t) {
|
|||||||
<span id="support-composer-status" class="support-composer-status"></span>
|
<span id="support-composer-status" class="support-composer-status"></span>
|
||||||
<button class="support-btn" id="support-save-fragment"><i class="ph ph-plus-circle"></i> Save as fragment</button>
|
<button class="support-btn" id="support-save-fragment"><i class="ph ph-plus-circle"></i> Save as fragment</button>
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
<button class="support-btn support-btn-ghost" id="support-status-closed" title="Close without replying">Close ticket</button>
|
<button class="support-btn" id="support-status-closed" title="Close without replying"><i class="ph ph-archive"></i> Close ticket</button>
|
||||||
<button class="support-btn support-btn-primary" id="support-send-btn"><i class="ph ph-paper-plane-tilt"></i> Send reply</button>
|
<button class="support-btn support-btn-primary" id="support-send-btn"><i class="ph ph-paper-plane-tilt"></i> Send reply</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user