@mohasinac/appkit 3.4.5 → 3.4.6
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/features/homepage/components/HeroCarousel.js +2 -2
- package/dist/features/media/upload/MediaUploadField.js +1 -7
- package/dist/features/site-settings/components/ThemeManagerView.js +25 -1
- package/dist/styles.css +10 -10
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Typography.js +8 -3
- package/dist/ui/components/Typography.style.css +9 -9
- package/package.json +1 -1
|
@@ -115,7 +115,7 @@ function CarouselCardRenderer({ card, isMobile, push, }) {
|
|
|
115
115
|
gridRow: String(gridPos.gridRow),
|
|
116
116
|
gridColumn: String(gridPos.gridColumn),
|
|
117
117
|
minHeight: isMobile ? 100 : 140,
|
|
118
|
-
}, children: [_jsx(CardBackground, { bg: card.background }), !card.isButtonOnly && (_jsxs(_Fragment, { children: [_jsx(Scrim, { direction: "bottom-up", intensity: "strong", className: POSITION_FILL }), _jsxs(Stack, { justify: "end", className: `${POSITION_FILL} md:p-[1.5rem] ${textAlignClass}`, padding: "xs", children: [card.content?.eyebrow && (_jsx(Text, { color: "inverse", shadow: "sm", className: "text-[10px] !/70 mb-0.5 tracking-wider", mdSize: "xs", transform: "uppercase", children: card.content.eyebrow })), card.content?.subtitle && (_jsx(Text, { color: "inverse", shadow: "sm", className: "hidden md:block !/90 mb-0.5 md:mb-2", mdSize: "sm", size: "xs", children: card.content.subtitle })), card.content?.title && (_jsx(Heading, { level: 2, className: `text-[11px] mb-0.5 md:mb-3`, truncate: 2, weight: "bold", shadow: "md", mdSize: "2xl", lgSize: "3xl", style: { color: card.content.textColor ?? "white" }, children: card.content.title })), card.content?.description && (_jsx(Text, { color: "inverse", shadow: "sm", className: `text-[10px] md:text-[0.875rem] !/80 mb-1 md:mb-4`, truncate: true, children: card.content.description })), (card.buttons?.length ?? 0) > 0 && (_jsx(Row, { wrap: true, gap: "xs", className: "md:gap-[
|
|
118
|
+
}, children: [_jsx(CardBackground, { bg: card.background }), !card.isButtonOnly && (_jsxs(_Fragment, { children: [_jsx(Scrim, { direction: "bottom-up", intensity: "strong", className: POSITION_FILL }), _jsxs(Stack, { justify: "end", className: `${POSITION_FILL} md:p-[1.5rem] ${textAlignClass}`, padding: "xs", children: [card.content?.eyebrow && (_jsx(Text, { color: "inverse", shadow: "sm", className: "text-[10px] !/70 mb-0.5 tracking-wider", mdSize: "xs", transform: "uppercase", children: card.content.eyebrow })), card.content?.subtitle && (_jsx(Text, { color: "inverse", shadow: "sm", className: "hidden md:block !/90 mb-0.5 md:mb-2", mdSize: "sm", size: "xs", children: card.content.subtitle })), card.content?.title && (_jsx(Heading, { level: 2, className: `text-[11px] mb-0.5 md:mb-3`, truncate: 2, weight: "bold", shadow: "md", mdSize: "2xl", lgSize: "3xl", style: { color: card.content.textColor ?? "white" }, children: card.content.title })), card.content?.description && (_jsx(Text, { color: "inverse", shadow: "sm", className: `text-[10px] md:text-[0.875rem] !/80 mb-1 md:mb-4`, truncate: true, children: card.content.description })), (card.buttons?.length ?? 0) > 0 && (_jsx(Row, { wrap: true, gap: "xs", className: "md:gap-[var(--appkit-space-2)]", children: (card.buttons ?? []).map((btn, i) => {
|
|
119
119
|
const variant = btn.variant === "link" || btn.variant === "ghost"
|
|
120
120
|
? "ghost"
|
|
121
121
|
: btn.variant;
|
|
@@ -184,7 +184,7 @@ export function HeroCarousel({ initialSlides, push } = {}) {
|
|
|
184
184
|
return (_jsxs(Section, { ref: sectionRef, className: `relative w-full ${heightClass} overflow-hidden`, "aria-roledescription": "carousel", "aria-label": "Hero carousel", onKeyDown: handleKeyDown, onMouseEnter: () => setIsPaused(true), onMouseLeave: () => setIsPaused(false), onFocus: () => setIsPaused(true), onBlur: () => setIsPaused(false), tabIndex: 0, children: [_jsx(Div, { "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: `Slide ${currentSlide + 1} of ${slides.length}` }), _jsx(Div, { className: POSITION_FILL, children: _jsx(Div, { layout: "flex", ref: slidesRef, onScroll: handleSlidesScroll, className: "h-full overflow-x-auto scroll-smooth snap-x snap-mandatory [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", style: { gap: 0 }, children: slides.map((slide, slideIndex) => {
|
|
185
185
|
const slideHeightClass = getSlideHeightClass(slide.settings?.height);
|
|
186
186
|
const hasCards = slide.cards && slide.cards.length > 0;
|
|
187
|
-
return (_jsxs(Div, { className: `snap-start flex-none w-full relative self-stretch bg-neutral-900 ${slideHeightClass}`, children: [_jsx(Div, { className: POSITION_FILL, children: _jsx(SlideBackground, { bg: slide.background, legacy: slide.media, mobileLegacy: slide.mobileMedia, isMobile: isMobile, priority: slideIndex === 0 }) }), slide.overlay && (_jsxs(Div, { className: `${POSITION_FILL} ${FLEX_CENTER} [flex-direction:column] text-center md:px-[4rem] lg:px-[8rem]`, padding: "x-lg", children: [slide.overlay.subtitle && (_jsx(Text, { color: "inverse", shadow: "sm", className: "stagger-1 !/80 mb-1 md:mb-2 tracking-widest", mdSize: "sm", size: "xs", transform: "uppercase", children: slide.overlay.subtitle })), slide.overlay.title && (_jsx(Heading, { color: "inverse", level: 1, className: "stagger-2 font-display ! mb-2 md:mb-4", size: "4xl", shadow: "2xl", mdSize: "6xl", lgSize: "8xl", children: slide.overlay.title })), slide.overlay.description && (_jsx(Text, { color: "inverse", shadow: "sm", className: "stagger-3 !/90 mb-4 md:mb-8 max-w-2xl mx-auto", mdSize: "lg", lgSize: "xl", size: "sm", children: slide.overlay.description })), slide.overlay.button && (_jsx(Div, { className: "stagger-4", children: _jsx(Button, { variant: slide.overlay.button.variant, size: "sm", onClick: makeButtonClickHandler(slide.overlay.button.link, slide.overlay.button.openInNewTab, push), children: slide.overlay.button.text }) }))] })), hasCards && (_jsx(Div, { className: `${POSITION_FILL} grid gap-[
|
|
187
|
+
return (_jsxs(Div, { className: `snap-start flex-none w-full relative self-stretch bg-neutral-900 ${slideHeightClass}`, children: [_jsx(Div, { className: POSITION_FILL, children: _jsx(SlideBackground, { bg: slide.background, legacy: slide.media, mobileLegacy: slide.mobileMedia, isMobile: isMobile, priority: slideIndex === 0 }) }), slide.overlay && (_jsxs(Div, { className: `${POSITION_FILL} ${FLEX_CENTER} [flex-direction:column] text-center md:px-[4rem] lg:px-[8rem]`, padding: "x-lg", children: [slide.overlay.subtitle && (_jsx(Text, { color: "inverse", shadow: "sm", className: "stagger-1 !/80 mb-1 md:mb-2 tracking-widest", mdSize: "sm", size: "xs", transform: "uppercase", children: slide.overlay.subtitle })), slide.overlay.title && (_jsx(Heading, { color: "inverse", level: 1, className: "stagger-2 font-display ! mb-2 md:mb-4", size: "4xl", shadow: "2xl", mdSize: "6xl", lgSize: "8xl", children: slide.overlay.title })), slide.overlay.description && (_jsx(Text, { color: "inverse", shadow: "sm", className: "stagger-3 !/90 mb-4 md:mb-8 max-w-2xl mx-auto", mdSize: "lg", lgSize: "xl", size: "sm", children: slide.overlay.description })), slide.overlay.button && (_jsx(Div, { className: "stagger-4", children: _jsx(Button, { variant: slide.overlay.button.variant, size: "sm", onClick: makeButtonClickHandler(slide.overlay.button.link, slide.overlay.button.openInNewTab, push), children: slide.overlay.button.text }) }))] })), hasCards && (_jsx(Div, { className: `${POSITION_FILL} grid gap-[var(--appkit-space-2)] md:gap-[var(--appkit-space-4)] md:p-[var(--appkit-space-8)]`, padding: "md", style: {
|
|
188
188
|
gridTemplateRows: "repeat(2, 1fr)",
|
|
189
189
|
gridTemplateColumns: isMobile ? "1fr" : "repeat(3, 1fr)",
|
|
190
190
|
alignContent: "center",
|
|
@@ -18,12 +18,6 @@ import CameraCapture from "./CameraCapture";
|
|
|
18
18
|
import { extractVideoPosterFrame, posterBlobAsFile } from "./video-poster";
|
|
19
19
|
import { inferMediaTypeFromMime } from "../types/index";
|
|
20
20
|
import { normalizeError } from "../../../errors/normalize";
|
|
21
|
-
const __P = {
|
|
22
|
-
p3: "p-3",
|
|
23
|
-
};
|
|
24
|
-
const __O = {
|
|
25
|
-
hidden: "overflow-hidden",
|
|
26
|
-
};
|
|
27
21
|
const CLS_PDF_BADGE = "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-error-surface text-error dark:bg-error-surface dark:text-error";
|
|
28
22
|
const CLS_PDF_NAME = "text-sm font-medium text-info underline break-all dark:text-info";
|
|
29
23
|
const CLS_PDF_LINK = "text-sm underline break-all text-info dark:text-info";
|
|
@@ -85,7 +79,7 @@ function ExternalUrlTabPanel({ extInput, setExtInput, extError, setExtError, onA
|
|
|
85
79
|
return (_jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "sm", children: [_jsx("input", { type: "url", value: extInput, onChange: (e) => { setExtInput(e.target.value); setExtError(""); }, placeholder: "https://example.com/image.jpg", className: "appkit-input flex-1" }), _jsx(Button, { type: "button", variant: "primary", size: "sm", onClick: onApply, children: "Apply" })] }), extError && _jsx(Alert, { variant: "error", children: extError }), _jsx(Text, { size: "xs", variant: "secondary", children: "External URLs are stored as-is and are not watermarked." })] }));
|
|
86
80
|
}
|
|
87
81
|
function MediaPreviewPanel({ value, label, disabled, enableTrim, enableThumbnail, onEditVideo, onRemove, tUpload, tMediaEditor, }) {
|
|
88
|
-
return (_jsxs(Div, {
|
|
82
|
+
return (_jsxs(Div, { padding: "sm", rounded: "lg", surface: "muted", border: "default", children: [isVideo(value) ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Div, { className: "relative aspect-video", overflow: "hidden", rounded: "lg", children: _jsx(MediaVideo, { src: value, alt: label, controls: true, objectFit: "contain" }) }), _jsx(Text, { size: "xs", variant: "secondary", children: "Video uploaded successfully. Large videos may take longer to process." })] })) : isImage(value) ? (_jsx(Div, { className: "relative aspect-video", overflow: "hidden", rounded: "lg", children: _jsx(MediaImage, { src: value, alt: label, size: "card", objectFit: "contain" }) })) : isPdf(value) ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Div, { className: "relative w-full", overflow: "hidden", rounded: "lg", border: "default", style: { height: 280 }, children: _jsx("iframe", { src: value, title: filenameFromUrl(value), className: "w-full h-full border-0" }) }), _jsxs(Row, { gap: "md", align: "center", children: [_jsx(Div, { "aria-hidden": true, className: CLS_PDF_BADGE, children: _jsx(Span, { size: "xs", weight: "bold", children: "PDF" }) }), _jsx(Anchor, { href: value, className: CLS_PDF_NAME, children: filenameFromUrl(value) })] })] })) : (_jsx(Anchor, { href: value, className: CLS_PDF_LINK, children: filenameFromUrl(value) })), !disabled && (_jsxs(Row, { wrap: true, gap: "sm", className: "mt-2", children: [isVideo(value) && (enableTrim || enableThumbnail) && (_jsx(Button, { type: "button", onClick: () => onEditVideo(value), variant: "secondary", size: "sm", children: tMediaEditor("editVideo") })), _jsx(Button, { type: "button", onClick: onRemove, variant: "danger", size: "sm", children: tUpload("remove") })] }))] }));
|
|
89
83
|
}
|
|
90
84
|
export function MediaUploadField({ label, value, onChange, onChangeField, onUpload,
|
|
91
85
|
// SB-UNI-Z5 2026-05-13 — `kind` derives accept/maxSizeMB when not set
|
|
@@ -20,6 +20,30 @@ const MODE_OPTIONS = [
|
|
|
20
20
|
{ label: "Light", value: "light" },
|
|
21
21
|
{ label: "Dark", value: "dark" },
|
|
22
22
|
];
|
|
23
|
+
/** Groups `REQUIRED_THEME_TOKENS` into labeled subsections so the editor doesn't read as one undifferentiated grid of ~68 inputs. */
|
|
24
|
+
const TOKEN_GROUPS = [
|
|
25
|
+
{ label: "Primary", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-color-primary")) },
|
|
26
|
+
{ label: "Secondary", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-color-secondary")) },
|
|
27
|
+
{
|
|
28
|
+
label: "Surface & border",
|
|
29
|
+
keys: REQUIRED_THEME_TOKENS.filter((k) => ["appkit-color-bg", "appkit-color-surface", "appkit-color-surface-elevated", "appkit-color-surface-input", "appkit-color-border", "appkit-color-border-subtle"].includes(k)),
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: "Text",
|
|
33
|
+
keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-color-text")),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: "Status",
|
|
37
|
+
keys: REQUIRED_THEME_TOKENS.filter((k) => ["appkit-color-success", "appkit-color-success-surface", "appkit-color-warning", "appkit-color-warning-surface", "appkit-color-error", "appkit-color-error-surface", "appkit-color-info", "appkit-color-info-surface"].includes(k)),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
label: "Focus & glow",
|
|
41
|
+
keys: REQUIRED_THEME_TOKENS.filter((k) => k === "appkit-color-focus-ring" || k.startsWith("appkit-shadow-glow")),
|
|
42
|
+
},
|
|
43
|
+
{ label: "Fonts", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-font-")) },
|
|
44
|
+
{ label: "Spacing scale", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-space-")) },
|
|
45
|
+
{ label: "Font-size scale", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-text-")) },
|
|
46
|
+
];
|
|
23
47
|
function isBuiltInId(id) {
|
|
24
48
|
return BUILT_IN_THEMES.some((t) => t.id === id);
|
|
25
49
|
}
|
|
@@ -70,7 +94,7 @@ function ThemeEditor({ draft, readOnly, onChange, onSave, onCancel, }) {
|
|
|
70
94
|
gradients: { ...draft.gradients, [key]: value },
|
|
71
95
|
});
|
|
72
96
|
}, [draft, onChange]);
|
|
73
|
-
return (_jsx(Section, { padding: "md", surface: "card", border: "default", rounded: "lg", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "end", justify: "between", gap: "md", wrap: true, children: [_jsxs(Stack, { gap: "sm", children: [_jsx(Input, { label: "Name", value: draft.name, onChange: (event) => onChange({ ...draft, name: event.target.value }), disabled: readOnly }), _jsx(Input, { label: "Id (slug)", value: draft.id, onChange: (event) => onChange({ ...draft, id: slugify(event.target.value) }), disabled: readOnly || draft.builtIn === true })] }), _jsx(Select, { label: "Mode", options: MODE_OPTIONS, value: draft.mode, onValueChange: (next) => onChange({ ...draft, mode: next }), disabled: readOnly })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "CSS variable tokens" }), _jsxs(Text, { size: "xs", color: "muted", children: ["Each key is written as ", _jsx("code", { children: "--key" }), " on ", _jsx("code", { children: "<html>" }), " ", "when this theme is active. Empty values fall back to the active mode\u2019s built-in theme."] }), _jsx(Grid, { cols: 2, gap: "sm", children:
|
|
97
|
+
return (_jsx(Section, { padding: "md", surface: "card", border: "default", rounded: "lg", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "end", justify: "between", gap: "md", wrap: true, children: [_jsxs(Stack, { gap: "sm", children: [_jsx(Input, { label: "Name", value: draft.name, onChange: (event) => onChange({ ...draft, name: event.target.value }), disabled: readOnly }), _jsx(Input, { label: "Id (slug)", value: draft.id, onChange: (event) => onChange({ ...draft, id: slugify(event.target.value) }), disabled: readOnly || draft.builtIn === true })] }), _jsx(Select, { label: "Mode", options: MODE_OPTIONS, value: draft.mode, onValueChange: (next) => onChange({ ...draft, mode: next }), disabled: readOnly })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "CSS variable tokens" }), _jsxs(Text, { size: "xs", color: "muted", children: ["Each key is written as ", _jsx("code", { children: "--key" }), " on ", _jsx("code", { children: "<html>" }), " ", "when this theme is active. Empty values fall back to the active mode\u2019s built-in theme."] }), TOKEN_GROUPS.map((group) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", children: group.label }), _jsx(Grid, { cols: 2, gap: "sm", children: group.keys.map((key) => (_jsx(Input, { label: key, value: draft.tokens[key] ?? "", onChange: (event) => updateToken(key, event.target.value), disabled: readOnly, placeholder: "inherits from built-in" }, key))) })] }, group.label)))] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Gradients" }), _jsxs(Text, { size: "xs", color: "muted", children: ["Each gradient is a complete CSS expression \u2014 vary direction, stops, opacity, and easing per theme. Tokens flow through", " ", _jsxs("code", { children: ["--appkit-gradient-", "<key>"] }), "."] }), _jsx(Stack, { gap: "sm", children: REQUIRED_GRADIENT_KEYS.map((key) => (_jsx(Textarea, { label: key, rows: 2, value: draft.gradients[key] ?? "", onChange: (event) => updateGradient(key, event.target.value), disabled: readOnly, placeholder: "linear-gradient(...)" }, key))) })] }), _jsxs(Row, { gap: "sm", justify: "end", children: [_jsx(Button, { variant: "ghost", onClick: onCancel, children: "Cancel" }), !readOnly ? (_jsx(Button, { variant: "primary", onClick: onSave, children: "Save theme" })) : null] })] }) }));
|
|
74
98
|
}
|
|
75
99
|
export function ThemeManagerView({ value, onChange, previewOrigin = "/", }) {
|
|
76
100
|
const [editingId, setEditingId] = useState(null);
|