Skip to content

Commit 94acbf8

Browse files
committed
One icon recipe, in colour, on the site and in the panel
Every icon on both was a hairline in one colour, drawn a piece at a time in whatever component needed one -- a phone, a pin and an envelope in identical grey say nothing about which is which before you read the line beside them. One recipe now, in two places because the two share no build: a plate with a diagonal gradient, a gloss across its top half, a shadow underneath and a rim inside the edge -- the four things that make a flat shape read as an object -- with the mark in white on top. Six tones: gold, bronze, navy, green, plum, slate, so a row of icons carries colour rather than one gold repeated. On the site (my-app/src/components/Icon3d.tsx): the footer's four contact rows, the social row, the WhatsApp bubble and the back-to-top button. In the panel (admin/src/icons.php): all eight sidebar entries, each on its own colour, and the five counters on the dashboard, where the plate sits top right and out of the way of the number. Not everywhere, deliberately. The chevron beside a menu, the tick inside a chip, the bin on a table row: a plate at sixteen pixels is a coloured square with something indistinct on it, and those are clearer as hairlines. The four marks on the about page keep their own discs, which already draw themselves. Ids are suffixed per instance in both. Six plates on one page all defining "plate" would every one of them paint with whichever gradient the browser read last -- the failure is silent and looks like a colour choice. Checked: 14 checks over both -- plates in the footer and the buttons with two gradients and a shadow each, none under 38px, no two definitions sharing an id, eight sidebar plates at 22px in four or more colours, five counters at 34px with none sitting on its number, and nothing thrown either side. The page walk, accessibility names, footer, benefits, services, how-it-works, FAQ and no-JavaScript suites are unchanged, as are the panel's nav, UI and records suites. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0128YzbhrfGdegUSc9RrARRf
1 parent 8a637f7 commit 94acbf8

56 files changed

Lines changed: 537 additions & 218 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎404.html‎

Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

‎about/index.html‎

Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

‎admin/admin.css‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ button { font-family: inherit; }
173173
.ns-item.is-on { background: var(--accent); color: #14100D; }
174174
.ns-item.is-on .ns-ico { opacity: 1; }
175175
.ns-ico { flex-shrink: 0; opacity: 0.82; }
176+
.ns-item .ns-ico3d { opacity: 1; }
176177
.ns-item-label { flex: 1; min-width: 0; }
177178

178179
.ns-item .tab-count {
@@ -587,6 +588,24 @@ button { font-family: inherit; }
587588
background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
588589
padding: 11px 13px; display: flex; flex-direction: column; gap: 3px;
589590
}
591+
/* The plate on a counter card: top right, out of the way of the number, which
592+
is what anybody is here to read. Only the five cards that carry one -- the
593+
rest of the grid keeps its own rhythm without a hole where an icon is not. */
594+
.stat-card .ns-ico3d {
595+
position: absolute; top: 9px; right: 10px;
596+
transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1);
597+
}
598+
.stat-card:has(.ns-ico3d) { position: relative; padding-right: 52px; }
599+
.stat-card:hover .ns-ico3d { transform: translateY(-2px) scale(1.05); }
600+
601+
/* The sidebar's plates sit a hair lower than a hairline did, and brighten
602+
rather than fade: the old rule dimmed the icon on every entry but the one
603+
you are on, which on a coloured plate reads as a fault. */
604+
.ns-ico3d { opacity: 1; }
605+
606+
@media (prefers-reduced-motion: reduce) {
607+
.stat-card .ns-ico3d, .stat-card:hover .ns-ico3d { transition: none; transform: none; }
608+
}
590609
/* --ink-faint measures 3.35:1 on white, under the 4.5:1 needed for text this
591610
small, and it was already being used at 0.78rem. Shrinking it further would
592611
have made a failing contrast worse, so the label moves to --ink-dim at

‎admin/dashboard.php‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?php
22
declare(strict_types=1);
33

4+
require_once __DIR__ . '/src/icons.php';
5+
46
require_once __DIR__ . '/src/csrf.php';
57
require_once __DIR__ . '/src/assets.php';
68
require_once __DIR__ . '/src/vocab.php';
@@ -84,22 +86,27 @@
8486

8587
<div class="stat-grid">
8688
<div class="stat-card">
89+
<?= admin_icon3d('car', 34) ?>
8790
<span class="stat-label">Cars Listed</span>
8891
<span class="stat-value" id="statCarCount">0</span>
8992
</div>
9093
<div class="stat-card">
94+
<?= admin_icon3d('inbox', 34) ?>
9195
<span class="stat-label">Booking Inquiries</span>
9296
<span class="stat-value" id="statInquiryCount">0</span>
9397
</div>
9498
<div class="stat-card stat-card-income">
99+
<?= admin_icon3d('rupee', 34) ?>
95100
<span class="stat-label">Total Income</span>
96101
<span class="stat-value" id="statIncome">₹0</span>
97102
</div>
98103
<div class="stat-card stat-card-expense">
104+
<?= admin_icon3d('wallet', 34) ?>
99105
<span class="stat-label">Total Expenses</span>
100106
<span class="stat-value" id="statExpense">₹0</span>
101107
</div>
102108
<div class="stat-card stat-card-balance">
109+
<?= admin_icon3d('scales', 34) ?>
103110
<span class="stat-label">Net Balance</span>
104111
<span class="stat-value" id="statBalance">₹0</span>
105112
</div>

‎admin/src/icons.php‎

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
/**
3+
* The panel's icons: a coloured plate with a mark on it.
4+
*
5+
* The same recipe the site uses (my-app/src/components/Icon3d.tsx) written for
6+
* the server: a plate with a diagonal gradient, a gloss across its top half, a
7+
* shadow underneath and a rim inside the edge, with the mark in white on top.
8+
* Two copies rather than one, because the panel is PHP served from a different
9+
* machine and shares no build with the site -- the same trade the content
10+
* defaults already make.
11+
*
12+
* Every id inside is suffixed, because six plates on a page all defining
13+
* "plate" would every one of them paint with whichever the browser read last.
14+
*
15+
* Only where the icon is big enough to carry it. The bin on a table row and
16+
* the chevron on a summary stay hairlines: a plate at sixteen pixels is a
17+
* coloured square with something indistinct on it.
18+
*/
19+
20+
/** Light end, dark end. The dark end is also the shadow. */
21+
const ADMIN_ICON_TONES = [
22+
'gold' => ['#f6dc84', '#c9a227'],
23+
'bronze' => ['#e6a860', '#a85f22'],
24+
'navy' => ['#2b3a72', '#0a0e20'],
25+
'green' => ['#5ee08a', '#128c3e'],
26+
'plum' => ['#d08bd6', '#7b2f86'],
27+
'slate' => ['#9fb0cc', '#465a7e'],
28+
];
29+
30+
/** The mark, drawn in a 24-unit box, and the plate it sits on by default. */
31+
function admin_icon_glyphs(): array
32+
{
33+
return [
34+
'chart' => ['navy', '<rect x="3" y="12" width="4" height="8" rx="1" fill="currentColor" stroke="none"/><rect x="10" y="4" width="4" height="16" rx="1" fill="currentColor" stroke="none"/><rect x="17" y="9" width="4" height="11" rx="1" fill="currentColor" stroke="none"/>'],
35+
'clipboard' => ['gold', '<rect x="5" y="4" width="14" height="17" rx="2"/><rect x="8.5" y="2" width="7" height="4" rx="1"/><line x1="8" y1="11" x2="16" y2="11"/><line x1="8" y1="15" x2="16" y2="15"/>'],
36+
'car' => ['bronze', '<path d="M3 13l1.4-4.2A2 2 0 0 1 6.3 7.5h11.4a2 2 0 0 1 1.9 1.3L21 13"/><rect x="2.5" y="13" width="19" height="5" rx="1.5"/><circle cx="7" cy="18.5" r="1.4"/><circle cx="17" cy="18.5" r="1.4"/>'],
37+
'inbox' => ['plum', '<path d="M3 12h5l1.5 3h5L16 12h5"/><path d="M5.5 5h13l2.5 7v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7l2.5-7z"/>'],
38+
'card' => ['green', '<rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18"/><circle cx="16.5" cy="14.5" r="1"/>'],
39+
'trend' => ['slate', '<path d="M3 17l6-6 4 4 8-8"/><path d="M15 7h6v6"/>'],
40+
'pencil' => ['gold', '<path d="M4 20h4l10-10a2.8 2.8 0 0 0-4-4L4 16v4z"/><line x1="13.5" y1="6.5" x2="17.5" y2="10.5"/>'],
41+
'pin' => ['bronze', '<path d="M12 21s7-6.2 7-11a7 7 0 1 0-14 0c0 4.8 7 11 7 11z"/><circle cx="12" cy="10" r="2.5"/>'],
42+
// The dashboard's counters.
43+
'rupee' => ['green', '<path d="M7 5h10"/><path d="M7 9h10"/><path d="M14.5 5c0 3-2.2 4-5 4h-2.5l7.5 10"/>'],
44+
'wallet' => ['bronze', '<path d="M3 8.5A2.5 2.5 0 0 1 5.5 6H18a2 2 0 0 1 2 2v1"/><rect x="3" y="9" width="18" height="10" rx="2.5"/><circle cx="16.5" cy="14" r="1.2"/>'],
45+
'scales' => ['navy', '<path d="M12 4v16"/><path d="M6 8h12"/><path d="M4 16l2.5-6L9 16a2.6 2.6 0 0 1-5 0z"/><path d="M15 16l2.5-6L20 16a2.6 2.6 0 0 1-5 0z"/>'],
46+
];
47+
}
48+
49+
/**
50+
* One icon, as markup.
51+
*
52+
* @param string $name a key of admin_icon_glyphs()
53+
* @param int $size rendered edge to edge, shadow included
54+
* @param string|null $tone overrides the glyph's own plate colour
55+
*/
56+
function admin_icon3d(string $name, int $size = 30, ?string $tone = null, string $class = 'ns-ico3d'): string
57+
{
58+
static $n = 0;
59+
$n++;
60+
61+
$glyphs = admin_icon_glyphs();
62+
if (!isset($glyphs[$name])) {
63+
return '';
64+
}
65+
66+
[$defaultTone, $paths] = $glyphs[$name];
67+
$key = $tone !== null && isset(ADMIN_ICON_TONES[$tone]) ? $tone : $defaultTone;
68+
[$light, $dark] = ADMIN_ICON_TONES[$key];
69+
$uid = 'i' . $n;
70+
71+
return '<svg class="' . htmlspecialchars($class, ENT_QUOTES) . '" width="' . $size . '" height="' . $size . '"'
72+
. ' viewBox="0 0 48 48" aria-hidden="true" focusable="false">'
73+
. '<defs>'
74+
. '<linearGradient id="plate-' . $uid . '" x1="0.15" y1="0" x2="0.85" y2="1">'
75+
. '<stop offset="0%" stop-color="' . $light . '"/><stop offset="100%" stop-color="' . $dark . '"/></linearGradient>'
76+
. '<linearGradient id="gloss-' . $uid . '" x1="0" y1="0" x2="0" y2="1">'
77+
. '<stop offset="0%" stop-color="#fff" stop-opacity="0.5"/><stop offset="100%" stop-color="#fff" stop-opacity="0"/></linearGradient>'
78+
. '<filter id="drop-' . $uid . '" x="-30%" y="-20%" width="160%" height="160%">'
79+
. '<feDropShadow dx="0" dy="2" stdDeviation="2" flood-color="' . $dark . '" flood-opacity="0.45"/></filter>'
80+
. '</defs>'
81+
. '<g filter="url(#drop-' . $uid . ')">'
82+
. '<rect x="3" y="2" width="42" height="42" rx="13" fill="url(#plate-' . $uid . ')"/>'
83+
. '<rect x="4" y="3" width="40" height="40" rx="12" fill="none" stroke="#fff" stroke-opacity="0.28"/>'
84+
. '<rect x="5" y="4" width="38" height="20" rx="11" fill="url(#gloss-' . $uid . ')"/>'
85+
. '</g>'
86+
. '<g transform="translate(12 11)" fill="none" stroke="#fff" stroke-width="1.7"'
87+
. ' stroke-linecap="round" stroke-linejoin="round" color="#fff">' . $paths . '</g>'
88+
. '</svg>';
89+
}

‎admin/src/shell.php‎

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,14 @@ function admin_nav_groups(): array
4646
];
4747
}
4848

49-
/** One of the small line drawings beside a navigation entry. */
49+
/** The plate beside a navigation entry. */
5050
function admin_nav_icon(string $name): string
5151
{
52-
$paths = [
53-
'chart' => '<rect x="3" y="12" width="4" height="8" rx="1" fill="currentColor" stroke="none"/><rect x="10" y="4" width="4" height="16" rx="1" fill="currentColor" stroke="none"/><rect x="17" y="9" width="4" height="11" rx="1" fill="currentColor" stroke="none"/>',
54-
'clipboard' => '<rect x="5" y="4" width="14" height="17" rx="2"/><rect x="8.5" y="2" width="7" height="4" rx="1"/><line x1="8" y1="11" x2="16" y2="11"/><line x1="8" y1="15" x2="16" y2="15"/>',
55-
'car' => '<path d="M3 13l1.4-4.2A2 2 0 0 1 6.3 7.5h11.4a2 2 0 0 1 1.9 1.3L21 13"/><rect x="2.5" y="13" width="19" height="5" rx="1.5"/><circle cx="7" cy="18.5" r="1.4"/><circle cx="17" cy="18.5" r="1.4"/>',
56-
'inbox' => '<path d="M3 12h5l1.5 3h5L16 12h5"/><path d="M5.5 5h13l2.5 7v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7l2.5-7z"/>',
57-
'card' => '<rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18"/><circle cx="16.5" cy="14.5" r="1"/>',
58-
'trend' => '<path d="M3 17l6-6 4 4 8-8"/><path d="M15 7h6v6"/>',
59-
'pencil' => '<path d="M4 20h4l10-10a2.8 2.8 0 0 0-4-4L4 16v4z"/><line x1="13.5" y1="6.5" x2="17.5" y2="10.5"/>',
60-
'pin' => '<path d="M12 21s7-6.2 7-11a7 7 0 1 0-14 0c0 4.8 7 11 7 11z"/><circle cx="12" cy="10" r="2.5"/>',
61-
];
52+
require_once __DIR__ . '/icons.php';
6253

63-
return '<svg class="ns-ico" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor"'
64-
. ' stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">'
65-
. ($paths[$name] ?? '') . '</svg>';
54+
// Twenty-two rather than seventeen: a plate has a gradient, a gloss and a
55+
// rim in it, and at seventeen pixels all three are one smudge.
56+
return admin_icon3d($name, 22, null, 'ns-ico ns-ico3d');
6657
}
6758

6859
/**

0 commit comments

Comments
 (0)