@skipleague/design 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AppLogo.d.ts +8 -0
- package/dist/AppLogo.js +20 -0
- package/dist/ProfileMenu.js +8 -1
- package/dist/TopBar.js +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/AppLogo.tsx +22 -0
- package/src/ProfileMenu.tsx +8 -1
- package/src/TopBar.tsx +3 -0
- package/src/index.ts +1 -1
package/dist/AppLogo.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
/** A SkipLeague app's logo glyph (monoline, drawn on the brand tile). */
|
|
2
2
|
export type AppGlyph = "lists" | "racquetball" | "trips" | "gifts" | "reading" | "today" | "guide" | "flow";
|
|
3
|
+
/** Every app that has a glyph, for slug→glyph resolution and fallbacks. */
|
|
4
|
+
export declare const APP_GLYPHS: readonly AppGlyph[];
|
|
5
|
+
/**
|
|
6
|
+
* Resolve a platform app slug (e.g. `"skipracquetball"`) to its {@link AppGlyph}
|
|
7
|
+
* by dropping the `skip` prefix, or `null` when no glyph exists for it (so a
|
|
8
|
+
* caller can fall back to a letter {@link AppBadge}). Case-insensitive.
|
|
9
|
+
*/
|
|
10
|
+
export declare function appGlyphForSlug(slug: string): AppGlyph | null;
|
|
3
11
|
/**
|
|
4
12
|
* The per-app logo mark — a brand-green rounded tile holding a white monoline
|
|
5
13
|
* glyph. Replaces the single-letter {@link AppBadge}; gives each SkipLeague app a
|
package/dist/AppLogo.js
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/** Every app that has a glyph, for slug→glyph resolution and fallbacks. */
|
|
3
|
+
export const APP_GLYPHS = [
|
|
4
|
+
"lists",
|
|
5
|
+
"racquetball",
|
|
6
|
+
"trips",
|
|
7
|
+
"gifts",
|
|
8
|
+
"reading",
|
|
9
|
+
"today",
|
|
10
|
+
"guide",
|
|
11
|
+
"flow",
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a platform app slug (e.g. `"skipracquetball"`) to its {@link AppGlyph}
|
|
15
|
+
* by dropping the `skip` prefix, or `null` when no glyph exists for it (so a
|
|
16
|
+
* caller can fall back to a letter {@link AppBadge}). Case-insensitive.
|
|
17
|
+
*/
|
|
18
|
+
export function appGlyphForSlug(slug) {
|
|
19
|
+
const key = slug.replace(/^skip/i, "").toLowerCase();
|
|
20
|
+
return APP_GLYPHS.includes(key) ? key : null;
|
|
21
|
+
}
|
|
2
22
|
// Exact 24×24 glyph paths (design_handoff_app_glyphs — the finalized round that
|
|
3
23
|
// fixed racquetball, trips, and flow and added the guide mark). `color` only
|
|
4
24
|
// matters for filled sub-shapes (e.g. the racquetball ball), which are filled
|
package/dist/ProfileMenu.js
CHANGED
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { CircleUser, LogIn, LogOut, Settings } from "lucide-react";
|
|
4
4
|
import { AppBadge } from "./AppBadge.js";
|
|
5
|
+
import { AppLogo, appGlyphForSlug } from "./AppLogo.js";
|
|
5
6
|
import { SKIPLEAGUE_ACCOUNT_URL, SKIPLEAGUE_APPS } from "./apps.js";
|
|
6
7
|
/**
|
|
7
8
|
* The canonical SkipLeague account control: a boxed user-icon button that opens
|
|
@@ -56,6 +57,10 @@ export function ProfileMenu({ user, currentSlug, apps = SKIPLEAGUE_APPS, enabled
|
|
|
56
57
|
display: "inline-flex",
|
|
57
58
|
alignItems: "center",
|
|
58
59
|
justifyContent: "center",
|
|
60
|
+
// Explicit padding:0 — a host app's global `button { padding }` would
|
|
61
|
+
// otherwise collapse this fixed 38×38 box's content area (border-box)
|
|
62
|
+
// and shrink the icon to a dot.
|
|
63
|
+
padding: 0,
|
|
59
64
|
width: 38,
|
|
60
65
|
height: 38,
|
|
61
66
|
borderRadius: "var(--skl-radius-control)",
|
|
@@ -66,7 +71,9 @@ export function ProfileMenu({ user, currentSlug, apps = SKIPLEAGUE_APPS, enabled
|
|
|
66
71
|
transition: "border-color 0.15s, color 0.15s",
|
|
67
72
|
}, children: _jsx(CircleUser, { size: 22 }) }), open && (_jsx("div", { role: "menu", style: menuStyle, children: showSignedOut ? (_jsxs(_Fragment, { children: [_jsx("div", { style: { padding: "0.5rem 0.75rem", borderBottom: "1px solid var(--skl-color-border)" }, children: _jsx("div", { style: { fontWeight: 600, fontSize: "var(--skl-text-sm)", color: "var(--skl-color-text)" }, children: "Not signed in" }) }), _jsxs("button", { role: "menuitem", onClick: onSignIn, style: { ...itemStyle, width: "100%", textAlign: "left", background: "none", border: "none", cursor: "pointer" }, children: [_jsx(LogIn, { size: 15 }), " ", signInLabel] })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { style: { padding: "0.5rem 0.75rem", borderBottom: "1px solid var(--skl-color-border)" }, children: [_jsx("div", { style: { fontWeight: 600, fontSize: "var(--skl-text-sm)", color: "var(--skl-color-text)" }, children: label }), user?.email && _jsx("div", { style: { fontSize: "var(--skl-text-xs)", color: "var(--skl-color-text-muted)" }, children: user.email })] }), visibleApps.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { style: switchHeading, children: "Switch app" }), visibleApps.map((a) => {
|
|
68
73
|
const isCurrent = a.slug === currentSlug;
|
|
69
|
-
|
|
74
|
+
// Per-app glyph when one exists; letter badge otherwise.
|
|
75
|
+
const glyph = appGlyphForSlug(a.slug);
|
|
76
|
+
const inner = (_jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [glyph ? _jsx(AppLogo, { app: glyph, size: 22 }) : _jsx(AppBadge, { name: a.name }), a.name] }));
|
|
70
77
|
// The app you're in: light-green highlight, not clickable.
|
|
71
78
|
return isCurrent ? (_jsx("div", { "aria-current": "page", style: { ...itemStyle, fontWeight: 600, background: "var(--skl-color-current-bg)", color: "var(--skl-color-current-text)", cursor: "default" }, children: inner }, a.slug)) : (_jsx("a", { href: a.url, role: "menuitem", style: itemStyle, children: inner }, a.slug));
|
|
72
79
|
})] })), _jsx("div", { style: divider }), accountItem, _jsx("div", { style: divider }), _jsxs("button", { role: "menuitem", onClick: onSignOut, style: { ...itemStyle, width: "100%", textAlign: "left", background: "none", border: "none", cursor: "pointer" }, children: [_jsx(LogOut, { size: 15 }), " Sign out"] })] })) }))] }));
|
package/dist/TopBar.js
CHANGED
|
@@ -82,6 +82,9 @@ export function TopBarIconButton({ tone = "dark", compact = false, style, childr
|
|
|
82
82
|
justifyContent: "center",
|
|
83
83
|
cursor: "pointer",
|
|
84
84
|
flex: "0 0 auto",
|
|
85
|
+
// Explicit padding:0 so a host app's global `button { padding }` can't
|
|
86
|
+
// collapse this fixed-size box (border-box) and shrink the icon.
|
|
87
|
+
padding: 0,
|
|
85
88
|
background: palette.background,
|
|
86
89
|
border: `1px solid ${palette.border}`,
|
|
87
90
|
color: palette.color,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { ProfileMenu } from "./ProfileMenu.js";
|
|
2
2
|
export type { ProfileMenuProps, ProfileMenuUser, ProfileMenuLinkArgs } from "./ProfileMenu.js";
|
|
3
3
|
export { AppBadge } from "./AppBadge.js";
|
|
4
|
-
export { AppLogo } from "./AppLogo.js";
|
|
4
|
+
export { AppLogo, APP_GLYPHS, appGlyphForSlug } from "./AppLogo.js";
|
|
5
5
|
export type { AppGlyph } from "./AppLogo.js";
|
|
6
6
|
export { TopBar, TopBarIconButton, DesktopActionBar } from "./TopBar.js";
|
|
7
7
|
export type { TopBarTone } from "./TopBar.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ProfileMenu } from "./ProfileMenu.js";
|
|
2
2
|
export { AppBadge } from "./AppBadge.js";
|
|
3
|
-
export { AppLogo } from "./AppLogo.js";
|
|
3
|
+
export { AppLogo, APP_GLYPHS, appGlyphForSlug } from "./AppLogo.js";
|
|
4
4
|
export { TopBar, TopBarIconButton, DesktopActionBar } from "./TopBar.js";
|
|
5
5
|
export { SidebarNav } from "./SidebarNav.js";
|
|
6
6
|
export { BottomNav } from "./BottomNav.js";
|
package/package.json
CHANGED
package/src/AppLogo.tsx
CHANGED
|
@@ -11,6 +11,28 @@ export type AppGlyph =
|
|
|
11
11
|
| "guide"
|
|
12
12
|
| "flow";
|
|
13
13
|
|
|
14
|
+
/** Every app that has a glyph, for slug→glyph resolution and fallbacks. */
|
|
15
|
+
export const APP_GLYPHS: readonly AppGlyph[] = [
|
|
16
|
+
"lists",
|
|
17
|
+
"racquetball",
|
|
18
|
+
"trips",
|
|
19
|
+
"gifts",
|
|
20
|
+
"reading",
|
|
21
|
+
"today",
|
|
22
|
+
"guide",
|
|
23
|
+
"flow",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a platform app slug (e.g. `"skipracquetball"`) to its {@link AppGlyph}
|
|
28
|
+
* by dropping the `skip` prefix, or `null` when no glyph exists for it (so a
|
|
29
|
+
* caller can fall back to a letter {@link AppBadge}). Case-insensitive.
|
|
30
|
+
*/
|
|
31
|
+
export function appGlyphForSlug(slug: string): AppGlyph | null {
|
|
32
|
+
const key = slug.replace(/^skip/i, "").toLowerCase();
|
|
33
|
+
return (APP_GLYPHS as readonly string[]).includes(key) ? (key as AppGlyph) : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
14
36
|
// Exact 24×24 glyph paths (design_handoff_app_glyphs — the finalized round that
|
|
15
37
|
// fixed racquetball, trips, and flow and added the guide mark). `color` only
|
|
16
38
|
// matters for filled sub-shapes (e.g. the racquetball ball), which are filled
|
package/src/ProfileMenu.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from "react";
|
|
2
2
|
import { CircleUser, LogIn, LogOut, Settings } from "lucide-react";
|
|
3
3
|
import { AppBadge } from "./AppBadge.js";
|
|
4
|
+
import { AppLogo, appGlyphForSlug } from "./AppLogo.js";
|
|
4
5
|
import { SKIPLEAGUE_ACCOUNT_URL, SKIPLEAGUE_APPS, type AppLink } from "./apps.js";
|
|
5
6
|
|
|
6
7
|
export interface ProfileMenuUser {
|
|
@@ -160,6 +161,10 @@ export function ProfileMenu({
|
|
|
160
161
|
display: "inline-flex",
|
|
161
162
|
alignItems: "center",
|
|
162
163
|
justifyContent: "center",
|
|
164
|
+
// Explicit padding:0 — a host app's global `button { padding }` would
|
|
165
|
+
// otherwise collapse this fixed 38×38 box's content area (border-box)
|
|
166
|
+
// and shrink the icon to a dot.
|
|
167
|
+
padding: 0,
|
|
163
168
|
width: 38,
|
|
164
169
|
height: 38,
|
|
165
170
|
borderRadius: "var(--skl-radius-control)",
|
|
@@ -202,9 +207,11 @@ export function ProfileMenu({
|
|
|
202
207
|
<div style={switchHeading}>Switch app</div>
|
|
203
208
|
{visibleApps.map((a) => {
|
|
204
209
|
const isCurrent = a.slug === currentSlug;
|
|
210
|
+
// Per-app glyph when one exists; letter badge otherwise.
|
|
211
|
+
const glyph = appGlyphForSlug(a.slug);
|
|
205
212
|
const inner = (
|
|
206
213
|
<span style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
|
|
207
|
-
<AppBadge name={a.name} />
|
|
214
|
+
{glyph ? <AppLogo app={glyph} size={22} /> : <AppBadge name={a.name} />}
|
|
208
215
|
{a.name}
|
|
209
216
|
</span>
|
|
210
217
|
);
|
package/src/TopBar.tsx
CHANGED
|
@@ -168,6 +168,9 @@ export function TopBarIconButton({
|
|
|
168
168
|
justifyContent: "center",
|
|
169
169
|
cursor: "pointer",
|
|
170
170
|
flex: "0 0 auto",
|
|
171
|
+
// Explicit padding:0 so a host app's global `button { padding }` can't
|
|
172
|
+
// collapse this fixed-size box (border-box) and shrink the icon.
|
|
173
|
+
padding: 0,
|
|
171
174
|
background: palette.background,
|
|
172
175
|
border: `1px solid ${palette.border}`,
|
|
173
176
|
color: palette.color,
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { ProfileMenu } from "./ProfileMenu.js";
|
|
2
2
|
export type { ProfileMenuProps, ProfileMenuUser, ProfileMenuLinkArgs } from "./ProfileMenu.js";
|
|
3
3
|
export { AppBadge } from "./AppBadge.js";
|
|
4
|
-
export { AppLogo } from "./AppLogo.js";
|
|
4
|
+
export { AppLogo, APP_GLYPHS, appGlyphForSlug } from "./AppLogo.js";
|
|
5
5
|
export type { AppGlyph } from "./AppLogo.js";
|
|
6
6
|
export { TopBar, TopBarIconButton, DesktopActionBar } from "./TopBar.js";
|
|
7
7
|
export type { TopBarTone } from "./TopBar.js";
|