@unicitylabs/sphere-ui 0.1.22 → 0.1.24
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/analytics/index.d.ts +6 -6
- package/dist/index.d.ts +48 -49
- package/dist/index.js +35 -0
- package/package.json +6 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
type DateRangePreset = '1d' | '7d' | '30d' | '90d';
|
|
@@ -25,7 +25,7 @@ declare const PRESET_LABELS: Record<DateRangePreset, string>;
|
|
|
25
25
|
* Emits a normalized DateRangeValue that maps 1:1 to the backend
|
|
26
26
|
* ?range=... query: presets pass the label, "custom" passes from+to.
|
|
27
27
|
*/
|
|
28
|
-
declare function DateRangePicker({ value, onChange, presets, className, }: DateRangePickerProps):
|
|
28
|
+
declare function DateRangePicker({ value, onChange, presets, className, }: DateRangePickerProps): react.JSX.Element;
|
|
29
29
|
|
|
30
30
|
interface TimeseriesSeries {
|
|
31
31
|
/** Key inside each data point (e.g. 'installs'). */
|
|
@@ -55,7 +55,7 @@ interface TimeseriesChartProps {
|
|
|
55
55
|
* etc. Encapsulates the Recharts wiring so both admin and developer
|
|
56
56
|
* views render charts identically.
|
|
57
57
|
*/
|
|
58
|
-
declare function TimeseriesChart({ data, series, variant, height, stacked, showLegend, showGrid, className, emptyState, }: TimeseriesChartProps):
|
|
58
|
+
declare function TimeseriesChart({ data, series, variant, height, stacked, showLegend, showGrid, className, emptyState, }: TimeseriesChartProps): react.JSX.Element;
|
|
59
59
|
|
|
60
60
|
interface KPICardProps {
|
|
61
61
|
/** Short uppercase label above the value. */
|
|
@@ -84,7 +84,7 @@ interface KPICardProps {
|
|
|
84
84
|
* Same shape as dev-portal's admin-card pattern so both frontends
|
|
85
85
|
* render KPIs identically.
|
|
86
86
|
*/
|
|
87
|
-
declare function KPICard({ label, value, icon, previousValue, hint, title, format, accentColor, className, }: KPICardProps):
|
|
87
|
+
declare function KPICard({ label, value, icon, previousValue, hint, title, format, accentColor, className, }: KPICardProps): react.JSX.Element;
|
|
88
88
|
|
|
89
89
|
interface TopEntity {
|
|
90
90
|
id: string;
|
|
@@ -116,7 +116,7 @@ interface TopEntitiesTableProps {
|
|
|
116
116
|
* Ranked list with a horizontal bar fill per row. Used for "top quests",
|
|
117
117
|
* "top installed projects", "top users", etc. — any cross-entity ranking.
|
|
118
118
|
*/
|
|
119
|
-
declare function TopEntitiesTable({ entities, title, valueLabel, secondaryLabel, hideBars, emptyState, accentColor, className, }: TopEntitiesTableProps):
|
|
119
|
+
declare function TopEntitiesTable({ entities, title, valueLabel, secondaryLabel, hideBars, emptyState, accentColor, className, }: TopEntitiesTableProps): react.JSX.Element;
|
|
120
120
|
|
|
121
121
|
interface AnalyticsSkeletonProps {
|
|
122
122
|
/** Rendered above the grid — usually the existing page header (title + DateRangePicker). */
|
|
@@ -137,6 +137,6 @@ interface AnalyticsSkeletonProps {
|
|
|
137
137
|
* `header` they render in the real state so the date-range picker
|
|
138
138
|
* stays interactive while data loads.
|
|
139
139
|
*/
|
|
140
|
-
declare function AnalyticsSkeleton({ header, showKpiRows, showCharts, showBottomTables, className, }: AnalyticsSkeletonProps):
|
|
140
|
+
declare function AnalyticsSkeleton({ header, showKpiRows, showCharts, showBottomTables, className, }: AnalyticsSkeletonProps): react.JSX.Element;
|
|
141
141
|
|
|
142
142
|
export { AnalyticsSkeleton, type AnalyticsSkeletonProps, type DateRangeLabel, DateRangePicker, type DateRangePickerProps, type DateRangePreset, type DateRangeValue, KPICard, type KPICardProps, TimeseriesChart, type TimeseriesChartProps, type TimeseriesSeries, TopEntitiesTable, type TopEntitiesTableProps, type TopEntity, PRESET_LABELS as dateRangePresetLabels };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
1
|
import * as react from 'react';
|
|
3
2
|
import { ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes, MouseEvent, Ref } from 'react';
|
|
4
3
|
import { ColumnDef } from '@tanstack/react-table';
|
|
@@ -17,7 +16,7 @@ interface DashboardLayoutProps {
|
|
|
17
16
|
* Dashboard shell with sidebar + main content area.
|
|
18
17
|
* Used by sphere-backoffice and sphere-dev-portal.
|
|
19
18
|
*/
|
|
20
|
-
declare function DashboardLayout({ logo, nav, footer, children }: DashboardLayoutProps):
|
|
19
|
+
declare function DashboardLayout({ logo, nav, footer, children }: DashboardLayoutProps): react.JSX.Element;
|
|
21
20
|
|
|
22
21
|
interface AppLogoProps {
|
|
23
22
|
/** Short code displayed in the icon (e.g. "SQ", "SD") */
|
|
@@ -33,7 +32,7 @@ interface AppLogoProps {
|
|
|
33
32
|
* App logo for dashboard sidebar.
|
|
34
33
|
* Orange icon + Anton title + Geist subtitle.
|
|
35
34
|
*/
|
|
36
|
-
declare function AppLogo({ icon, title, subtitle, onClick }: AppLogoProps):
|
|
35
|
+
declare function AppLogo({ icon, title, subtitle, onClick }: AppLogoProps): react.JSX.Element;
|
|
37
36
|
|
|
38
37
|
interface NavItem {
|
|
39
38
|
to: string;
|
|
@@ -60,7 +59,7 @@ interface SidebarNavProps {
|
|
|
60
59
|
* Sidebar navigation with grouped items, icons, and badges.
|
|
61
60
|
* Matches the admin panel sidebar style exactly.
|
|
62
61
|
*/
|
|
63
|
-
declare function SidebarNav({ groups, currentPath, onNavigate }: SidebarNavProps):
|
|
62
|
+
declare function SidebarNav({ groups, currentPath, onNavigate }: SidebarNavProps): react.JSX.Element;
|
|
64
63
|
|
|
65
64
|
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
66
65
|
error?: boolean;
|
|
@@ -89,12 +88,12 @@ interface FieldProps {
|
|
|
89
88
|
className?: string;
|
|
90
89
|
children: ReactNode;
|
|
91
90
|
}
|
|
92
|
-
declare function Field({ label, required, error, hint, className, children }: FieldProps):
|
|
91
|
+
declare function Field({ label, required, error, hint, className, children }: FieldProps): react.JSX.Element;
|
|
93
92
|
interface SectionProps {
|
|
94
93
|
title: string;
|
|
95
94
|
children: ReactNode;
|
|
96
95
|
}
|
|
97
|
-
declare function Section({ title, children }: SectionProps):
|
|
96
|
+
declare function Section({ title, children }: SectionProps): react.JSX.Element;
|
|
98
97
|
|
|
99
98
|
interface FormModalProps {
|
|
100
99
|
title: string;
|
|
@@ -121,21 +120,21 @@ interface StatusBadgeProps {
|
|
|
121
120
|
status: string;
|
|
122
121
|
className?: string;
|
|
123
122
|
}
|
|
124
|
-
declare function StatusBadge({ status, className }: StatusBadgeProps):
|
|
123
|
+
declare function StatusBadge({ status, className }: StatusBadgeProps): react.JSX.Element;
|
|
125
124
|
|
|
126
125
|
interface SearchInputProps {
|
|
127
126
|
value: string;
|
|
128
127
|
onChange: (value: string) => void;
|
|
129
128
|
placeholder?: string;
|
|
130
129
|
}
|
|
131
|
-
declare function SearchInput({ value, onChange, placeholder }: SearchInputProps):
|
|
130
|
+
declare function SearchInput({ value, onChange, placeholder }: SearchInputProps): react.JSX.Element;
|
|
132
131
|
|
|
133
132
|
interface EmptyStateProps {
|
|
134
133
|
title: string;
|
|
135
134
|
description?: string;
|
|
136
135
|
action?: ReactNode;
|
|
137
136
|
}
|
|
138
|
-
declare function EmptyState({ title, description, action }: EmptyStateProps):
|
|
137
|
+
declare function EmptyState({ title, description, action }: EmptyStateProps): react.JSX.Element;
|
|
139
138
|
|
|
140
139
|
interface SkeletonProps {
|
|
141
140
|
width?: string;
|
|
@@ -143,7 +142,7 @@ interface SkeletonProps {
|
|
|
143
142
|
radius?: string;
|
|
144
143
|
className?: string;
|
|
145
144
|
}
|
|
146
|
-
declare function Skeleton({ width, height, radius, className, }: SkeletonProps):
|
|
145
|
+
declare function Skeleton({ width, height, radius, className, }: SkeletonProps): react.JSX.Element;
|
|
147
146
|
|
|
148
147
|
interface SkeletonTextProps {
|
|
149
148
|
lines?: number;
|
|
@@ -151,14 +150,14 @@ interface SkeletonTextProps {
|
|
|
151
150
|
gap?: string;
|
|
152
151
|
className?: string;
|
|
153
152
|
}
|
|
154
|
-
declare function SkeletonText({ lines, lineHeight, gap, className, }: SkeletonTextProps):
|
|
153
|
+
declare function SkeletonText({ lines, lineHeight, gap, className, }: SkeletonTextProps): react.JSX.Element;
|
|
155
154
|
|
|
156
155
|
type SkeletonCircleSize = 'sm' | 'md' | 'lg' | (string & {});
|
|
157
156
|
interface SkeletonCircleProps {
|
|
158
157
|
size?: SkeletonCircleSize;
|
|
159
158
|
className?: string;
|
|
160
159
|
}
|
|
161
|
-
declare function SkeletonCircle({ size, className }: SkeletonCircleProps):
|
|
160
|
+
declare function SkeletonCircle({ size, className }: SkeletonCircleProps): react.JSX.Element;
|
|
162
161
|
|
|
163
162
|
interface SelectOption {
|
|
164
163
|
value: string;
|
|
@@ -172,7 +171,7 @@ interface CustomSelectProps {
|
|
|
172
171
|
className?: string;
|
|
173
172
|
size?: 'sm' | 'md';
|
|
174
173
|
}
|
|
175
|
-
declare function CustomSelect({ options, value, onChange, placeholder, className, size, }: CustomSelectProps):
|
|
174
|
+
declare function CustomSelect({ options, value, onChange, placeholder, className, size, }: CustomSelectProps): react.JSX.Element;
|
|
176
175
|
|
|
177
176
|
interface PageShellProps {
|
|
178
177
|
title: string;
|
|
@@ -181,7 +180,7 @@ interface PageShellProps {
|
|
|
181
180
|
maxWidth?: string;
|
|
182
181
|
children: ReactNode;
|
|
183
182
|
}
|
|
184
|
-
declare function PageShell({ title, subtitle, action, maxWidth, children }: PageShellProps):
|
|
183
|
+
declare function PageShell({ title, subtitle, action, maxWidth, children }: PageShellProps): react.JSX.Element;
|
|
185
184
|
|
|
186
185
|
interface DataTableProps<T> {
|
|
187
186
|
columns: ColumnDef<T, unknown>[];
|
|
@@ -192,21 +191,21 @@ interface DataTableProps<T> {
|
|
|
192
191
|
enableSearch?: boolean;
|
|
193
192
|
onRowClick?: (row: T) => void;
|
|
194
193
|
}
|
|
195
|
-
declare function DataTable<T>({ columns, data, isLoading, emptyMessage, searchPlaceholder, enableSearch, onRowClick, }: DataTableProps<T>):
|
|
194
|
+
declare function DataTable<T>({ columns, data, isLoading, emptyMessage, searchPlaceholder, enableSearch, onRowClick, }: DataTableProps<T>): react.JSX.Element;
|
|
196
195
|
|
|
197
196
|
interface AlertBannerProps {
|
|
198
197
|
type: 'warning' | 'info';
|
|
199
198
|
title: string;
|
|
200
199
|
children: ReactNode;
|
|
201
200
|
}
|
|
202
|
-
declare function AlertBanner({ type, title, children }: AlertBannerProps):
|
|
201
|
+
declare function AlertBanner({ type, title, children }: AlertBannerProps): react.JSX.Element;
|
|
203
202
|
|
|
204
203
|
interface AddressDisplayProps {
|
|
205
204
|
address: string;
|
|
206
205
|
nametag?: string | null;
|
|
207
206
|
truncate?: boolean;
|
|
208
207
|
}
|
|
209
|
-
declare function AddressDisplay({ address, nametag, truncate }: AddressDisplayProps):
|
|
208
|
+
declare function AddressDisplay({ address, nametag, truncate }: AddressDisplayProps): react.JSX.Element;
|
|
210
209
|
|
|
211
210
|
interface JsonPanelProps<T> {
|
|
212
211
|
/** Current form state to display as JSON */
|
|
@@ -218,11 +217,11 @@ interface JsonPanelProps<T> {
|
|
|
218
217
|
/** Panel title */
|
|
219
218
|
title?: string;
|
|
220
219
|
}
|
|
221
|
-
declare function JsonPanel<T extends Record<string, unknown>>({ value, onChange, excludeKeys, title, }: JsonPanelProps<T>):
|
|
220
|
+
declare function JsonPanel<T extends Record<string, unknown>>({ value, onChange, excludeKeys, title, }: JsonPanelProps<T>): react.JSX.Element;
|
|
222
221
|
declare function JsonToggleButton({ active, onClick }: {
|
|
223
222
|
active: boolean;
|
|
224
223
|
onClick: () => void;
|
|
225
|
-
}):
|
|
224
|
+
}): react.JSX.Element;
|
|
226
225
|
|
|
227
226
|
declare function tagColor(tag: string): {
|
|
228
227
|
bg: string;
|
|
@@ -234,7 +233,7 @@ declare function ChainInput({ chains, suggestions, onChange, size }: {
|
|
|
234
233
|
suggestions: string[];
|
|
235
234
|
onChange: (chains: Record<string, number>) => void;
|
|
236
235
|
size?: 'sm' | 'md';
|
|
237
|
-
}):
|
|
236
|
+
}): react.JSX.Element;
|
|
238
237
|
|
|
239
238
|
interface MemoCondition {
|
|
240
239
|
key: string;
|
|
@@ -245,7 +244,7 @@ interface MemoCondition {
|
|
|
245
244
|
declare function MemoConditionsEditor({ conditions, onChange }: {
|
|
246
245
|
conditions: MemoCondition[];
|
|
247
246
|
onChange: (conditions: MemoCondition[]) => void;
|
|
248
|
-
}):
|
|
247
|
+
}): react.JSX.Element;
|
|
249
248
|
|
|
250
249
|
/**
|
|
251
250
|
* Consistent SVG icon set for the admin panel.
|
|
@@ -256,27 +255,27 @@ interface IconProps {
|
|
|
256
255
|
className?: string;
|
|
257
256
|
style?: React.CSSProperties;
|
|
258
257
|
}
|
|
259
|
-
declare const IconBack: (p: IconProps) =>
|
|
260
|
-
declare const IconUndo: (p: IconProps) =>
|
|
261
|
-
declare const IconQuests: (p: IconProps) =>
|
|
262
|
-
declare const IconTracks: (p: IconProps) =>
|
|
263
|
-
declare const IconSettings: (p: IconProps) =>
|
|
264
|
-
declare const IconChain: (p: IconProps) =>
|
|
265
|
-
declare const IconPlus: (p: IconProps) =>
|
|
266
|
-
declare const IconEdit: (p: IconProps) =>
|
|
267
|
-
declare const IconTrash: (p: IconProps) =>
|
|
268
|
-
declare const IconX: (p: IconProps) =>
|
|
269
|
-
declare const IconCheck: (p: IconProps) =>
|
|
270
|
-
declare const IconSearch: (p: IconProps) =>
|
|
271
|
-
declare const IconChevronUp: (p: IconProps) =>
|
|
272
|
-
declare const IconChevronDown: (p: IconProps) =>
|
|
273
|
-
declare const IconChevronsDown: (p: IconProps) =>
|
|
274
|
-
declare const IconChevronsRight: (p: IconProps) =>
|
|
275
|
-
declare const IconArrowRight: (p: IconProps) =>
|
|
276
|
-
declare const IconPlay: (p: IconProps) =>
|
|
277
|
-
declare const IconStar: (p: IconProps) =>
|
|
278
|
-
declare const IconDiamond: (p: IconProps) =>
|
|
279
|
-
declare const IconCircle: (p: IconProps) =>
|
|
258
|
+
declare const IconBack: (p: IconProps) => react.JSX.Element;
|
|
259
|
+
declare const IconUndo: (p: IconProps) => react.JSX.Element;
|
|
260
|
+
declare const IconQuests: (p: IconProps) => react.JSX.Element;
|
|
261
|
+
declare const IconTracks: (p: IconProps) => react.JSX.Element;
|
|
262
|
+
declare const IconSettings: (p: IconProps) => react.JSX.Element;
|
|
263
|
+
declare const IconChain: (p: IconProps) => react.JSX.Element;
|
|
264
|
+
declare const IconPlus: (p: IconProps) => react.JSX.Element;
|
|
265
|
+
declare const IconEdit: (p: IconProps) => react.JSX.Element;
|
|
266
|
+
declare const IconTrash: (p: IconProps) => react.JSX.Element;
|
|
267
|
+
declare const IconX: (p: IconProps) => react.JSX.Element;
|
|
268
|
+
declare const IconCheck: (p: IconProps) => react.JSX.Element;
|
|
269
|
+
declare const IconSearch: (p: IconProps) => react.JSX.Element;
|
|
270
|
+
declare const IconChevronUp: (p: IconProps) => react.JSX.Element;
|
|
271
|
+
declare const IconChevronDown: (p: IconProps) => react.JSX.Element;
|
|
272
|
+
declare const IconChevronsDown: (p: IconProps) => react.JSX.Element;
|
|
273
|
+
declare const IconChevronsRight: (p: IconProps) => react.JSX.Element;
|
|
274
|
+
declare const IconArrowRight: (p: IconProps) => react.JSX.Element;
|
|
275
|
+
declare const IconPlay: (p: IconProps) => react.JSX.Element;
|
|
276
|
+
declare const IconStar: (p: IconProps) => react.JSX.Element;
|
|
277
|
+
declare const IconDiamond: (p: IconProps) => react.JSX.Element;
|
|
278
|
+
declare const IconCircle: (p: IconProps) => react.JSX.Element;
|
|
280
279
|
|
|
281
280
|
type MediaKind = 'logo' | 'banner' | 'screenshot' | 'image' | 'background';
|
|
282
281
|
type MediaMime = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/svg+xml';
|
|
@@ -322,7 +321,7 @@ interface MediaUploaderProps {
|
|
|
322
321
|
deferUpload?: boolean;
|
|
323
322
|
onFileSelected?: (file: File | null) => void;
|
|
324
323
|
}
|
|
325
|
-
declare function MediaUploader({ kind, ownerType, ownerId, value, onChange, uploadFn, label, deferUpload, onFileSelected, }: MediaUploaderProps):
|
|
324
|
+
declare function MediaUploader({ kind, ownerType, ownerId, value, onChange, uploadFn, label, deferUpload, onFileSelected, }: MediaUploaderProps): react.JSX.Element;
|
|
326
325
|
|
|
327
326
|
interface MediaItem {
|
|
328
327
|
type: 'screenshot' | 'video';
|
|
@@ -336,7 +335,7 @@ interface MediaGalleryProps {
|
|
|
336
335
|
uploadFn: MediaUploadFn;
|
|
337
336
|
max?: number;
|
|
338
337
|
}
|
|
339
|
-
declare function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max }: MediaGalleryProps):
|
|
338
|
+
declare function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max }: MediaGalleryProps): react.JSX.Element;
|
|
340
339
|
|
|
341
340
|
interface MarketplaceProjectCardProps {
|
|
342
341
|
name: string;
|
|
@@ -365,7 +364,7 @@ interface MarketplaceProjectCardProps {
|
|
|
365
364
|
*
|
|
366
365
|
* No `<Link>` dependency — wrap externally if router navigation is needed.
|
|
367
366
|
*/
|
|
368
|
-
declare function MarketplaceProjectCard({ name, tagline, logoUrl, bannerUrl, accentColor, category, users, quests, positivePercent, ratingCount, installState, onInstallClick, onClick, }: MarketplaceProjectCardProps):
|
|
367
|
+
declare function MarketplaceProjectCard({ name, tagline, logoUrl, bannerUrl, accentColor, category, users, quests, positivePercent, ratingCount, installState, onInstallClick, onClick, }: MarketplaceProjectCardProps): react.JSX.Element;
|
|
369
368
|
|
|
370
369
|
interface FeaturedProjectCardProps {
|
|
371
370
|
name: string;
|
|
@@ -386,7 +385,7 @@ interface FeaturedProjectCardProps {
|
|
|
386
385
|
* Wide hero-style card used in marketplace featured rails.
|
|
387
386
|
* No `<Link>` dependency — wrap externally if router navigation is needed.
|
|
388
387
|
*/
|
|
389
|
-
declare function FeaturedProjectCard({ name, tagline, logoUrl, bannerUrl, accentColor, users, quests, positivePercent, ratingCount, onClick, }: FeaturedProjectCardProps):
|
|
388
|
+
declare function FeaturedProjectCard({ name, tagline, logoUrl, bannerUrl, accentColor, users, quests, positivePercent, ratingCount, onClick, }: FeaturedProjectCardProps): react.JSX.Element;
|
|
390
389
|
|
|
391
390
|
/** Loose typing — dnd-kit listeners/attributes don't fit React's HTMLButtonAttributes due to motion.button overrides. */
|
|
392
391
|
type ButtonExtraProps = {
|
|
@@ -419,7 +418,7 @@ interface InstalledProjectIconProps {
|
|
|
419
418
|
* primary action, `onContextMenu` for right-click, and
|
|
420
419
|
* `topRightAction` to overlay a small action button on the tile.
|
|
421
420
|
*/
|
|
422
|
-
declare function InstalledProjectIcon({ name, logoUrl, accentColor, onClick, onContextMenu, topRightAction, showLabel, buttonRef, buttonProps, }: InstalledProjectIconProps):
|
|
421
|
+
declare function InstalledProjectIcon({ name, logoUrl, accentColor, onClick, onContextMenu, topRightAction, showLabel, buttonRef, buttonProps, }: InstalledProjectIconProps): react.JSX.Element;
|
|
423
422
|
|
|
424
423
|
type ProjectLogoSize = 'sm' | 'md' | 'lg';
|
|
425
424
|
interface ProjectLogoProps {
|
|
@@ -443,7 +442,7 @@ interface ProjectLogoProps {
|
|
|
443
442
|
* cards, install previews) so the icon looks the same regardless of
|
|
444
443
|
* surrounding chrome.
|
|
445
444
|
*/
|
|
446
|
-
declare function ProjectLogo({ name, logoUrl, accentColor, size, className, children, }: ProjectLogoProps):
|
|
445
|
+
declare function ProjectLogo({ name, logoUrl, accentColor, size, className, children, }: ProjectLogoProps): react.JSX.Element;
|
|
447
446
|
|
|
448
447
|
interface QuestPreviewSummary {
|
|
449
448
|
slug: string;
|
|
@@ -490,7 +489,7 @@ interface ProjectPagePreviewProps {
|
|
|
490
489
|
* Used by dev-portal & backoffice as a live preview while editing a project.
|
|
491
490
|
* No router / hooks / data fetching — every value comes via props.
|
|
492
491
|
*/
|
|
493
|
-
declare function ProjectPagePreview({ name, tagline, description, logoUrl, bannerUrl, accentColor, category, websiteUrl, discordUrl, twitterUrl, media, users, activeQuests, positivePercent, ratingCount, quests, achievements, tags, }: ProjectPagePreviewProps):
|
|
492
|
+
declare function ProjectPagePreview({ name, tagline, description, logoUrl, bannerUrl, accentColor, category, websiteUrl, discordUrl, twitterUrl, media, users, activeQuests, positivePercent, ratingCount, quests, achievements, tags, }: ProjectPagePreviewProps): react.JSX.Element;
|
|
494
493
|
|
|
495
494
|
declare const MEDIA_LIMITS: Record<MediaKind, MediaLimit>;
|
|
496
495
|
declare function isMimeAllowed(kind: MediaKind, mime: string): mime is MediaMime;
|
package/dist/index.js
CHANGED
|
@@ -1411,6 +1411,17 @@ import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs18 } from "react/jsx-r
|
|
|
1411
1411
|
function formatExtensions(mimes) {
|
|
1412
1412
|
return mimes.map((m) => m.split("/")[1].toUpperCase()).join(", ");
|
|
1413
1413
|
}
|
|
1414
|
+
async function readImageSize(file) {
|
|
1415
|
+
if (typeof createImageBitmap !== "function") return null;
|
|
1416
|
+
try {
|
|
1417
|
+
const bitmap = await createImageBitmap(file);
|
|
1418
|
+
const size = { width: bitmap.width, height: bitmap.height };
|
|
1419
|
+
bitmap.close?.();
|
|
1420
|
+
return size;
|
|
1421
|
+
} catch {
|
|
1422
|
+
return null;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1414
1425
|
function MediaUploader({
|
|
1415
1426
|
kind,
|
|
1416
1427
|
ownerType,
|
|
@@ -1453,6 +1464,30 @@ function MediaUploader({
|
|
|
1453
1464
|
});
|
|
1454
1465
|
return;
|
|
1455
1466
|
}
|
|
1467
|
+
if (file.type !== "image/svg+xml") {
|
|
1468
|
+
const size = await readImageSize(file);
|
|
1469
|
+
if (size) {
|
|
1470
|
+
const { width, height } = size;
|
|
1471
|
+
if (limit.maxWidth && width > limit.maxWidth || limit.maxHeight && height > limit.maxHeight) {
|
|
1472
|
+
setState({
|
|
1473
|
+
phase: "error",
|
|
1474
|
+
message: `Image too large (max ${limit.maxWidth}\xD7${limit.maxHeight}px \u2014 this is ${width}\xD7${height})`
|
|
1475
|
+
});
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
if (limit.aspectRatio) {
|
|
1479
|
+
const ratio = width / height;
|
|
1480
|
+
const tolerance = limit.aspectTolerance ?? 0;
|
|
1481
|
+
if (Math.abs(ratio - limit.aspectRatio) > limit.aspectRatio * tolerance) {
|
|
1482
|
+
setState({
|
|
1483
|
+
phase: "error",
|
|
1484
|
+
message: `Wrong aspect ratio (need ~${limit.aspectRatio}:1 \u2014 this is ${ratio.toFixed(2)}:1)`
|
|
1485
|
+
});
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1456
1491
|
if (deferUpload) {
|
|
1457
1492
|
if (previewRef.current) URL.revokeObjectURL(previewRef.current);
|
|
1458
1493
|
previewRef.current = URL.createObjectURL(file);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unicitylabs/sphere-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -43,16 +43,18 @@
|
|
|
43
43
|
"test": "vitest",
|
|
44
44
|
"test:run": "vitest run"
|
|
45
45
|
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"framer-motion": "^11.18.2",
|
|
48
|
+
"lucide-react": ">=0.400.0",
|
|
49
|
+
"react-dropzone": "^14.4.1"
|
|
50
|
+
},
|
|
46
51
|
"peerDependencies": {
|
|
47
52
|
"@dnd-kit/core": "^6.0.0",
|
|
48
53
|
"@dnd-kit/sortable": "^8.0.0 || ^10.0.0",
|
|
49
54
|
"@tanstack/react-query": "^5.0.0",
|
|
50
55
|
"@tanstack/react-table": "^8.0.0",
|
|
51
|
-
"framer-motion": "^11.18.2",
|
|
52
|
-
"lucide-react": ">=0.400.0",
|
|
53
56
|
"react": "^19.0.0",
|
|
54
57
|
"react-dom": "^19.0.0",
|
|
55
|
-
"react-dropzone": "^14.4.1",
|
|
56
58
|
"recharts": "^3.0.0"
|
|
57
59
|
},
|
|
58
60
|
"peerDependenciesMeta": {
|