File size: 5,809 Bytes
092334a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
609fb78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f546440
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// ---------------------------------------------------------------------------
// ui / icons.tsx β€” EXIT wave 2 (W2-6).
//
// The three glyphs the page primitives need, as SVG paths. Owner constant: NO
// EMOJIS anywhere in the UI β€” a check mark typed as a character is an emoji on
// most platforms and renders in the system's colour, not the palette's.
//
// Deliberately NOT importing `customer-grid/iconShapes`: `ui/` is the shared
// presentation layer and must not depend on the grid (the direction W2-5 spent
// its amendment lines getting right). Three paths do not justify inverting a
// 400-line module; if this set grows past a handful, hoist iconShapes the way
// `viz/` was hoisted rather than letting it creep.
//
// `currentColor` throughout, so tone comes from the CSS token on the parent and
// no colour is ever written here.
// ---------------------------------------------------------------------------

function Glyph({ d, size, className }: { d: string; size: number; className?: string }) {
  return (
    <svg
      className={className}
      width={size}
      height={size}
      viewBox="0 0 24 24"
      aria-hidden="true"
      focusable="false"
    >
      <path d={d} fill="currentColor" />
    </svg>
  );
}

/** Material "download" β€” the tray with the arrow into it. */
export function DownloadIcon({ size = 15 }: { size?: number }) {
  return (
    <Glyph
      className="pg-icon"
      size={size}
      d="M12 15.6 6.8 10.4l1.4-1.4 2.8 2.8V3h2v8.8l2.8-2.8 1.4 1.4zM5 20a2 2 0 0 1-2-2v-3h2v3h14v-3h2v3a2 2 0 0 1-2 2z"
    />
  );
}

/** Material "check" β€” a passing validation leg. */
export function CheckIcon({ size = 14 }: { size?: number }) {
  return (
    <Glyph className="pg-icon" size={size} d="M9.6 17.6 4 12l1.4-1.4 4.2 4.2 9-9L20 7.2z" />
  );
}

/** Material "priority_high" β€” a failing one. Not a cross: a failed
 *  reconciliation is "look at this", not "this was deleted". */
export function AlertIcon({ size = 14 }: { size?: number }) {
  return (
    <Glyph
      className="pg-icon"
      size={size}
      d="M11 15h2v2h-2zm0-10h2v8h-2z"
    />
  );
}

/**
 * ⭐ WAVE 32 Β· T20/T23 β€” THE BELL. One drawing, for every surface that means "you will be told".
 *
 * β›” STROKED, NOT FILLED, so it is a sibling of the shell's nav glyphs rather than of the three
 * solid page-primitive marks above β€” and it takes a `className` for the same reason: the Inbox
 * head sizes it through `.alerts-bell` while a menu row sizes it through the menu's own rule.
 *
 * ⚠ IT LIVES HERE BECAUSE TWO SURFACES NEED IT β€” the Inbox module's header (T20) and the view
 * menu's "Alert me about new records" row (T23). It was drawn inline inside `AlertsPane.tsx`; a
 * second hand-copy in the view rail is how a product ends up with two bells that differ by a
 * stroke width, and `shell/Brand.tsx` records the version of that mistake that shipped.
 */
export function BellIcon({ size = 16, className }: { size?: number; className?: string }) {
  return (
    <svg
      className={className}
      width={size}
      height={size}
      viewBox="0 0 16 16"
      aria-hidden="true"
      focusable="false"
      fill="none"
      stroke="currentColor"
      strokeWidth={1.3}
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <path d="M8 2.2a3.6 3.6 0 0 1 3.6 3.6v2.4l1.2 2H3.2l1.2-2V5.8A3.6 3.6 0 0 1 8 2.2Z" />
      <path d="M6.6 12.6a1.5 1.5 0 0 0 2.8 0" />
    </svg>
  );
}

/**
 * ⭐ WAVE 33 Β· T15 (D-206) β€” THE STAR. "Mark important" is not a lock, and it must stop wearing one.
 *
 * β›” WHAT D-206 IS ACTUALLY ABOUT, corrected against the source before this was drawn: the row does
 * NOT render `LockMark`. It renders `MenuIcon "permissions"` β€” a *different* padlock β€” and so do
 * "Share view", "Share folder", "Lock to a locked view" and "Edit field permissions". Five rows,
 * one padlock, five meanings, no titles, in menus a person reads at a glance. All three real
 * `LockMark` sites already name their lock in a `title` (DESIGN.md Β§4), so the offending row was
 * outside that rule's literal scope while breaking exactly the thing it protects.
 *
 * β›” THE FIX IS TO DROP THE LOCK, NOT TO TITLE IT. Titling it would assert that marking a view
 * important is one of the three locks; it is none of them β€” it neither freezes records, nor a
 * column, nor a row set. A title naming a lock that does not exist is a worse answer than the
 * untitled padlock, because it would be believed.
 *
 * ⚠ IT LIVES HERE, in `ui/`, and NOT in `customer-grid/icons.tsx`'s `MENU_ICONS`, for a reason
 * worth keeping: `MenuLabel` takes `MenuIconName | ReactNode`, and the alert row beside this one
 * already passes `<BellIcon size={16}/>` from this very file. So a menu glyph that belongs to no
 * other menu row has a home that costs no shared vocabulary β€” the same argument the bell's note
 * above records. (`customer-grid/icons.tsx` is also outside every wave-33 lane's fence; that made
 * the choice, it did not make it wrong.)
 *
 * ⚠ Stroked at 1.3 like every other menu glyph β€” `filled` is what says the view IS marked, so the
 * pair reads mark/unmark the way `permissions`/`unlock` did, without claiming a lock.
 */
export function StarIcon({
  size = 16,
  filled = false,
  className,
}: {
  size?: number;
  filled?: boolean;
  className?: string;
}) {
  return (
    <svg
      className={className}
      width={size}
      height={size}
      viewBox="0 0 16 16"
      aria-hidden="true"
      focusable="false"
      fill={filled ? "currentColor" : "none"}
      stroke="currentColor"
      strokeWidth={1.3}
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <path d="M8 2.4 9.73 5.9l3.87.57-2.8 2.73.66 3.85L8 11.23 4.54 13.05l.66-3.85-2.8-2.73L6.27 5.9Z" />
    </svg>
  );
}