@develemit/commerce-admin 0.0.0-stage → 0.3.0

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.
Files changed (58) hide show
  1. package/README.md +136 -2
  2. package/dist/client/admin-client.d.ts +31 -0
  3. package/dist/client/errors.d.ts +41 -0
  4. package/dist/client/index.d.ts +3 -0
  5. package/dist/client/index.js +1 -0
  6. package/dist/client/map-error.d.ts +2 -0
  7. package/dist/client/transport.d.ts +19 -0
  8. package/dist/client-n_IYb4iK.js +146 -0
  9. package/dist/client-n_IYb4iK.js.map +1 -0
  10. package/dist/components/admin-layout/admin-layout.d.ts +13 -0
  11. package/dist/components/admin-table/admin-table.d.ts +13 -0
  12. package/dist/components/confirm-dialog/confirm-dialog.d.ts +12 -0
  13. package/dist/components/error-message/error-message.d.ts +5 -0
  14. package/dist/components/money/money.d.ts +5 -0
  15. package/dist/components/notice/notice.d.ts +9 -0
  16. package/dist/components/status-badge/status-badge.d.ts +3 -0
  17. package/dist/index.d.ts +24 -0
  18. package/dist/index.js +2346 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/lib/image-labels.d.ts +24 -0
  21. package/dist/lib/image-rules.d.ts +4 -0
  22. package/dist/lib/money-input.d.ts +2 -0
  23. package/dist/lib/order-action-labels.d.ts +28 -0
  24. package/dist/lib/order-labels.d.ts +66 -0
  25. package/dist/lib/product-filter.d.ts +6 -0
  26. package/dist/lib/product-form.d.ts +29 -0
  27. package/dist/lib/product-labels.d.ts +52 -0
  28. package/dist/lib/provider.d.ts +73 -0
  29. package/dist/lib/refund-rules.d.ts +7 -0
  30. package/dist/lib/shipping-labels.d.ts +33 -0
  31. package/dist/lib/shipping-rates.d.ts +31 -0
  32. package/dist/lib/use-admin-mutation.d.ts +7 -0
  33. package/dist/lib/use-admin-query.d.ts +7 -0
  34. package/dist/lib/use-debounced.d.ts +1 -0
  35. package/dist/lib/use-image-upload.d.ts +18 -0
  36. package/dist/lib/use-order-pages.d.ts +17 -0
  37. package/dist/lib/use-product-pages.d.ts +30 -0
  38. package/dist/styles.css +405 -0
  39. package/dist/views/orders/admin-order-detail.d.ts +10 -0
  40. package/dist/views/orders/admin-order-list.d.ts +1 -0
  41. package/dist/views/orders/order-actions.d.ts +7 -0
  42. package/dist/views/orders/order-fulfillment.d.ts +4 -0
  43. package/dist/views/orders/order-items.d.ts +4 -0
  44. package/dist/views/orders/order-refunds.d.ts +4 -0
  45. package/dist/views/orders/refund-dialog.d.ts +8 -0
  46. package/dist/views/orders/resolve-button.d.ts +7 -0
  47. package/dist/views/orders/ship-form.d.ts +7 -0
  48. package/dist/views/orders/test-helpers.d.ts +3 -0
  49. package/dist/views/products/admin-product-editor.d.ts +9 -0
  50. package/dist/views/products/admin-product-images.d.ts +6 -0
  51. package/dist/views/products/admin-product-list.d.ts +1 -0
  52. package/dist/views/products/image-tile.d.ts +14 -0
  53. package/dist/views/products/product-fields.d.ts +12 -0
  54. package/dist/views/products/test-helpers.d.ts +6 -0
  55. package/dist/views/products/upload-picker.d.ts +7 -0
  56. package/dist/views/shipping/admin-shipping-rates.d.ts +4 -0
  57. package/dist/views/shipping/shipping-rate-row.d.ts +15 -0
  58. package/package.json +44 -3
@@ -0,0 +1,52 @@
1
+ import { ImageLabels } from './image-labels';
2
+ export type ProductFilter = 'all' | 'live' | 'sold' | 'draft' | 'archived';
3
+ export interface ProductLabels {
4
+ title: string;
5
+ newProduct: string;
6
+ searchLabel: string;
7
+ searchPlaceholder: string;
8
+ filters: Record<ProductFilter, string>;
9
+ empty: Record<ProductFilter, string>;
10
+ noMatches: string;
11
+ loadMore: string;
12
+ columns: {
13
+ image: string;
14
+ name: string;
15
+ price: string;
16
+ status: string;
17
+ quantity: string;
18
+ actions: string;
19
+ };
20
+ noImage: string;
21
+ viewInShop: string;
22
+ markSold: string;
23
+ archive: string;
24
+ markSoldTitle: string;
25
+ markSoldBody: string;
26
+ archiveTitle: string;
27
+ archiveBody: string;
28
+ updated: string;
29
+ createTitle: string;
30
+ editTitle: string;
31
+ saved: string;
32
+ fields: {
33
+ name: string;
34
+ category: string;
35
+ description: string;
36
+ materials: string;
37
+ dimensions: string;
38
+ price: string;
39
+ quantity: string;
40
+ status: string;
41
+ featured: string;
42
+ };
43
+ images: ImageLabels;
44
+ statusHelp: string;
45
+ priceHelp: string;
46
+ validation: {
47
+ required: string;
48
+ price: string;
49
+ quantity: string;
50
+ };
51
+ }
52
+ export declare const defaultProductLabels: ProductLabels;
@@ -0,0 +1,73 @@
1
+ import { AdminClient } from '../client';
2
+ import { ReactNode } from 'react';
3
+ import { OrderLabels } from './order-labels';
4
+ import { ShippingLabels } from './shipping-labels';
5
+ import { ProductLabels } from './product-labels';
6
+ export interface LinkProps {
7
+ href: string;
8
+ children: ReactNode;
9
+ className?: string;
10
+ }
11
+ export interface AdminImageProps {
12
+ src: string;
13
+ alt: string;
14
+ sizes?: string;
15
+ className?: string;
16
+ priority?: boolean;
17
+ }
18
+ export type AdminErrorKey = 'unauthorized' | 'notFound' | 'invalidInput' | 'invalidOrderState' | 'insufficientStock' | 'refundExceedsBalance' | 'refundGateway' | 'refundOutcomeUnknown' | 'imageInvalid' | 'imageTooLarge' | 'generic';
19
+ export interface AdminLabels {
20
+ loading: string;
21
+ empty: string;
22
+ save: string;
23
+ cancel: string;
24
+ confirm: string;
25
+ dismiss: string;
26
+ navLabel: string;
27
+ nav: {
28
+ products: string;
29
+ orders: string;
30
+ shippingRates: string;
31
+ };
32
+ statuses: Record<string, string>;
33
+ errors: Record<AdminErrorKey, string>;
34
+ products: ProductLabels;
35
+ orders: OrderLabels;
36
+ shipping: ShippingLabels;
37
+ }
38
+ export interface AdminConfig {
39
+ renderLink: (props: LinkProps) => ReactNode;
40
+ renderImage: (props: AdminImageProps) => ReactNode;
41
+ locale: string;
42
+ currency: string;
43
+ hrefs: {
44
+ products: string;
45
+ product: (id: string) => string;
46
+ newProduct: string;
47
+ orders: string;
48
+ order: (id: string) => string;
49
+ shippingRates: string;
50
+ storefrontProduct?: (slug: string) => string;
51
+ };
52
+ client: AdminClient | null;
53
+ labels: AdminLabels;
54
+ }
55
+ type DeepPartial<T> = {
56
+ [K in keyof T]?: T[K] extends object ? Partial<T[K]> : T[K];
57
+ };
58
+ export interface AdminProviderProps extends Partial<Omit<AdminConfig, 'hrefs' | 'labels'>> {
59
+ hrefs?: Partial<AdminConfig['hrefs']>;
60
+ labels?: Partial<Omit<AdminLabels, 'nav' | 'statuses' | 'errors' | 'products' | 'orders' | 'shipping'> & {
61
+ nav: Partial<AdminLabels['nav']>;
62
+ statuses: Partial<AdminLabels['statuses']>;
63
+ errors: Partial<AdminLabels['errors']>;
64
+ products: DeepPartial<ProductLabels>;
65
+ orders: DeepPartial<OrderLabels>;
66
+ shipping: Partial<ShippingLabels>;
67
+ }>;
68
+ children: ReactNode;
69
+ }
70
+ export declare function AdminProvider({ children, hrefs, labels, ...overrides }: AdminProviderProps): import('react').JSX.Element;
71
+ export declare function useAdmin(): AdminConfig;
72
+ export declare function useAdminClient(): AdminClient;
73
+ export {};
@@ -0,0 +1,7 @@
1
+ import { AdminOrderDetail } from '@develemit/commerce-contracts';
2
+ export declare function pendingRefundCents(order: AdminOrderDetail): number;
3
+ export declare function remainingRefundCents(order: AdminOrderDetail): number;
4
+ export declare function hasPendingRefund(order: AdminOrderDetail): boolean;
5
+ export declare function canRestock(order: AdminOrderDetail, amountCents: number | null): boolean;
6
+ export declare function canShip(order: AdminOrderDetail): boolean;
7
+ export declare function canRefund(order: AdminOrderDetail): boolean;
@@ -0,0 +1,33 @@
1
+ export interface ShippingLabels {
2
+ title: string;
3
+ loading: string;
4
+ empty: string;
5
+ add: string;
6
+ save: string;
7
+ saved: string;
8
+ label: string;
9
+ amount: string;
10
+ currency: string;
11
+ mixedCurrency: string;
12
+ minDays: string;
13
+ maxDays: string;
14
+ active: string;
15
+ rowName: string;
16
+ moveEarlier: string;
17
+ moveLater: string;
18
+ remove: string;
19
+ removeTitle: string;
20
+ removeBody: string;
21
+ newRateLabel: string;
22
+ removalWarning: string;
23
+ unsaved: string;
24
+ noActive: string;
25
+ labelRequired: string;
26
+ labelDuplicate: string;
27
+ amountInvalid: string;
28
+ currencyInvalid: string;
29
+ daysInvalid: string;
30
+ daysOrder: string;
31
+ rowInvalid: string;
32
+ }
33
+ export declare const defaultShippingLabels: ShippingLabels;
@@ -0,0 +1,31 @@
1
+ import { ShippingRate, ShippingRateInput } from '@develemit/commerce-contracts';
2
+ import { ShippingLabels } from './shipping-labels';
3
+ export interface RateDraft {
4
+ key: string;
5
+ label: string;
6
+ amount: string;
7
+ currency: string;
8
+ minDays: string;
9
+ maxDays: string;
10
+ active: boolean;
11
+ }
12
+ export interface RateErrors {
13
+ label?: string;
14
+ amount?: string;
15
+ minDays?: string;
16
+ maxDays?: string;
17
+ currency?: string;
18
+ row?: string;
19
+ }
20
+ export interface DraftCheck {
21
+ rates: ShippingRateInput[];
22
+ rowErrors: Record<string, RateErrors>;
23
+ noActive: boolean;
24
+ valid: boolean;
25
+ }
26
+ export declare const newKey: () => string;
27
+ export declare function toDrafts(rates: ShippingRate[]): RateDraft[];
28
+ export declare function blankDraft(currency: string, label: string): RateDraft;
29
+ export declare const snapshot: (drafts: RateDraft[]) => string;
30
+ export declare function checkDrafts(drafts: RateDraft[], copy: ShippingLabels): DraftCheck;
31
+ export declare function serverRowErrors(issues: unknown[], drafts: RateDraft[], copy: ShippingLabels): Record<string, RateErrors>;
@@ -0,0 +1,7 @@
1
+ export interface AdminMutation<A extends unknown[], R> {
2
+ run: (...args: A) => Promise<R | undefined>;
3
+ pending: boolean;
4
+ error: unknown;
5
+ reset: () => void;
6
+ }
7
+ export declare function useAdminMutation<A extends unknown[], R>(fn: (...args: A) => Promise<R>): AdminMutation<A, R>;
@@ -0,0 +1,7 @@
1
+ export interface AdminQuery<T> {
2
+ data: T | undefined;
3
+ error: unknown;
4
+ loading: boolean;
5
+ reload: () => void;
6
+ }
7
+ export declare function useAdminQuery<T>(key: readonly unknown[], fn: (signal: AbortSignal) => Promise<T>): AdminQuery<T>;
@@ -0,0 +1 @@
1
+ export declare function useDebounced<T>(value: T, delayMs: number): T;
@@ -0,0 +1,18 @@
1
+ import { AdminProduct } from '@develemit/commerce-contracts';
2
+ export interface UploadEntry {
3
+ id: number;
4
+ name: string;
5
+ status: 'queued' | 'uploading' | 'error';
6
+ reason?: string;
7
+ error?: unknown;
8
+ }
9
+ interface Options {
10
+ productId: string;
11
+ onUploaded: (product: AdminProduct) => void;
12
+ }
13
+ export declare function useImageUpload({ productId, onUploaded }: Options): {
14
+ entries: UploadEntry[];
15
+ upload: (files: File[], alt: string) => void;
16
+ dismiss: (id: number) => void;
17
+ };
18
+ export {};
@@ -0,0 +1,17 @@
1
+ import { AdminOrderQuery } from '../client/admin-client';
2
+ export declare function useOrderPages(query: Omit<AdminOrderQuery, 'cursor'>): {
3
+ items: {
4
+ id: string;
5
+ status: "pending" | "paid" | "shipped" | "cancelled" | "expired" | "needs_attention" | "refunded";
6
+ email: string | null;
7
+ totalCents: number;
8
+ currency: string;
9
+ itemCount: number;
10
+ createdAt: string;
11
+ }[];
12
+ loading: boolean;
13
+ error: unknown;
14
+ hasMore: boolean;
15
+ loadingMore: boolean;
16
+ loadMore: () => void;
17
+ };
@@ -0,0 +1,30 @@
1
+ import { AdminProductQuery } from '../client/admin-client';
2
+ export declare function useProductPages(query: Omit<AdminProductQuery, 'cursor'>): {
3
+ items: {
4
+ id: string;
5
+ slug: string;
6
+ name: string;
7
+ description: string;
8
+ materials: string | null;
9
+ dimensions: string | null;
10
+ priceCents: number;
11
+ currency: string;
12
+ category: string;
13
+ quantity: number;
14
+ status: "draft" | "active" | "archived";
15
+ featured: boolean;
16
+ images: {
17
+ id: string;
18
+ url: string;
19
+ alt: string;
20
+ position: number;
21
+ }[];
22
+ }[];
23
+ loaded: boolean;
24
+ loading: boolean;
25
+ error: unknown;
26
+ hasMore: boolean;
27
+ loadingMore: boolean;
28
+ reload: () => void;
29
+ loadMore: () => void;
30
+ };
@@ -0,0 +1,405 @@
1
+ .sfa-root {
2
+ color: var(--sf-color-fg, #1a1a1a);
3
+ background: var(--sf-color-bg, #ffffff);
4
+ font-family: var(--sf-font-body, system-ui, sans-serif);
5
+ }
6
+ .sfa-panel {
7
+ border: 1px solid var(--sf-color-border, #e0e0e0);
8
+ border-radius: var(--sf-radius, 4px);
9
+ background: var(--sf-color-surface, #f6f6f6);
10
+ padding: calc(var(--sf-space-unit, 0.25rem) * 4);
11
+ }
12
+ .sfa-btn {
13
+ min-width: 44px;
14
+ min-height: 44px;
15
+ padding: 0 calc(var(--sf-space-unit, 0.25rem) * 4);
16
+ font: inherit;
17
+ font-size: 1rem;
18
+ border: 1px solid var(--sf-color-border, #e0e0e0);
19
+ border-radius: var(--sf-radius, 4px);
20
+ background: var(--sf-color-bg, #ffffff);
21
+ color: inherit;
22
+ cursor: pointer;
23
+ }
24
+ .sfa-btn--primary {
25
+ background: var(--sf-color-accent, #1a1a1a);
26
+ color: var(--sf-color-accent-fg, #ffffff);
27
+ }
28
+ .sfa-btn--danger {
29
+ background: var(--sf-color-danger, #b00020);
30
+ color: #ffffff;
31
+ }
32
+ .sfa-layout {
33
+ display: flex;
34
+ flex-direction: column;
35
+ min-height: 100vh;
36
+ }
37
+ .sfa-nav ul {
38
+ display: flex;
39
+ flex-wrap: wrap;
40
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
41
+ margin: 0;
42
+ padding: calc(var(--sf-space-unit, 0.25rem) * 2);
43
+ list-style: none;
44
+ }
45
+ .sfa-nav__link {
46
+ display: inline-flex;
47
+ align-items: center;
48
+ min-height: 44px;
49
+ padding: 0 calc(var(--sf-space-unit, 0.25rem) * 3);
50
+ }
51
+ /* Bare inline links measure ~22px; hosts cannot restyle kit internals. */
52
+ .sfa-link--tap {
53
+ display: inline-flex;
54
+ align-items: center;
55
+ min-height: 44px;
56
+ padding: 0 calc(var(--sf-space-unit, 0.25rem) * 2);
57
+ }
58
+ .sfa-layout__content {
59
+ flex: 1;
60
+ padding: calc(var(--sf-space-unit, 0.25rem) * 4);
61
+ }
62
+ .sfa-badge {
63
+ display: inline-block;
64
+ padding: 2px 10px;
65
+ border-radius: 999px;
66
+ background: var(--sf-color-surface, #f6f6f6);
67
+ border: 1px solid var(--sf-color-border, #e0e0e0);
68
+ font-size: 0.875rem;
69
+ }
70
+ .sfa-badge--needs-attention {
71
+ border-color: var(--sf-color-danger, #b00020);
72
+ }
73
+ .sfa-table {
74
+ width: 100%;
75
+ border-collapse: collapse;
76
+ }
77
+ .sfa-table th,
78
+ .sfa-table td {
79
+ padding: calc(var(--sf-space-unit, 0.25rem) * 2);
80
+ text-align: left;
81
+ border-bottom: 1px solid var(--sf-color-border, #e0e0e0);
82
+ }
83
+ @media (max-width: 640px) {
84
+ .sfa-table--stacked thead {
85
+ position: absolute;
86
+ width: 1px;
87
+ height: 1px;
88
+ overflow: hidden;
89
+ clip: rect(0 0 0 0);
90
+ }
91
+ .sfa-table--stacked,
92
+ .sfa-table--stacked tbody,
93
+ .sfa-table--stacked tr,
94
+ .sfa-table--stacked td {
95
+ display: block;
96
+ }
97
+ .sfa-table--stacked tr {
98
+ margin-bottom: calc(var(--sf-space-unit, 0.25rem) * 3);
99
+ border: 1px solid var(--sf-color-border, #e0e0e0);
100
+ border-radius: var(--sf-radius, 4px);
101
+ }
102
+ .sfa-table--stacked td::before {
103
+ content: attr(data-label);
104
+ display: block;
105
+ font-size: 0.75rem;
106
+ opacity: 0.7;
107
+ }
108
+ }
109
+ .sfa-notice {
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: space-between;
113
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
114
+ padding: calc(var(--sf-space-unit, 0.25rem) * 3);
115
+ border: 1px solid var(--sf-color-border, #e0e0e0);
116
+ border-radius: var(--sf-radius, 4px);
117
+ }
118
+ .sfa-notice--error {
119
+ border-color: var(--sf-color-danger, #b00020);
120
+ }
121
+ .sfa-notice--toast {
122
+ position: fixed;
123
+ left: 50%;
124
+ transform: translateX(-50%);
125
+ bottom: calc(env(safe-area-inset-bottom, 0px) + 16px);
126
+ background: var(--sf-color-bg, #ffffff);
127
+ z-index: 60;
128
+ }
129
+ .sfa-dialog-backdrop {
130
+ position: fixed;
131
+ inset: 0;
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ background: rgba(0, 0, 0, 0.5);
136
+ z-index: 50;
137
+ }
138
+ .sfa-dialog {
139
+ width: min(92vw, 28rem);
140
+ padding: calc(var(--sf-space-unit, 0.25rem) * 5);
141
+ background: var(--sf-color-bg, #ffffff);
142
+ border-radius: var(--sf-radius, 4px);
143
+ }
144
+ .sfa-dialog__actions {
145
+ display: flex;
146
+ justify-content: flex-end;
147
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
148
+ margin-top: calc(var(--sf-space-unit, 0.25rem) * 4);
149
+ }
150
+ .sfa-root input,
151
+ .sfa-root select,
152
+ .sfa-root textarea {
153
+ font-size: 1rem;
154
+ min-height: 44px;
155
+ }
156
+ .sfa-filter-group {
157
+ display: flex;
158
+ flex-wrap: nowrap;
159
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
160
+ min-width: 0;
161
+ max-width: 100%;
162
+ box-sizing: border-box;
163
+ padding: 3px;
164
+ overflow-x: auto;
165
+ overscroll-behavior-x: contain;
166
+ scrollbar-width: none;
167
+ }
168
+ .sfa-filter-group::-webkit-scrollbar {
169
+ display: none;
170
+ }
171
+ .sfa-filter-group .sfa-filter {
172
+ flex-shrink: 0;
173
+ white-space: nowrap;
174
+ }
175
+ .sfa-products__header {
176
+ display: flex;
177
+ flex-wrap: wrap;
178
+ align-items: center;
179
+ justify-content: space-between;
180
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
181
+ }
182
+ .sfa-products__toolbar {
183
+ display: flex;
184
+ flex-wrap: wrap;
185
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
186
+ margin: calc(var(--sf-space-unit, 0.25rem) * 4) 0;
187
+ }
188
+ .sfa-filter[aria-pressed='true'] {
189
+ background: var(--sf-color-accent, #1a1a1a);
190
+ color: var(--sf-color-accent-fg, #ffffff);
191
+ }
192
+ .sfa-thumb {
193
+ display: inline-flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+ width: 48px;
197
+ height: 48px;
198
+ object-fit: cover;
199
+ border-radius: var(--sf-radius, 4px);
200
+ background: var(--sf-color-surface, #f6f6f6);
201
+ font-size: 0.625rem;
202
+ text-align: center;
203
+ }
204
+ .sfa-row-actions {
205
+ display: flex;
206
+ flex-wrap: wrap;
207
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
208
+ }
209
+ .sfa-row-actions a.sfa-btn {
210
+ display: inline-flex;
211
+ align-items: center;
212
+ text-decoration: none;
213
+ }
214
+ .sfa-form {
215
+ display: flex;
216
+ flex-direction: column;
217
+ gap: calc(var(--sf-space-unit, 0.25rem) * 4);
218
+ max-width: 40rem;
219
+ }
220
+ .sfa-field {
221
+ display: flex;
222
+ flex-direction: column;
223
+ gap: calc(var(--sf-space-unit, 0.25rem) * 1);
224
+ }
225
+ .sfa-field__label {
226
+ font-weight: 600;
227
+ }
228
+ .sfa-field__help {
229
+ margin: 0;
230
+ font-size: 0.875rem;
231
+ opacity: 0.75;
232
+ }
233
+ .sfa-field__error {
234
+ margin: 0;
235
+ font-size: 0.875rem;
236
+ color: var(--sf-color-danger, #b00020);
237
+ }
238
+ .sfa-field [aria-invalid='true'] {
239
+ border-color: var(--sf-color-danger, #b00020);
240
+ }
241
+ .sfa-check {
242
+ display: flex;
243
+ align-items: center;
244
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
245
+ min-height: 44px;
246
+ }
247
+ .sfa-check input {
248
+ width: 24px;
249
+ height: 24px;
250
+ min-height: 24px;
251
+ }
252
+ .sfa-sr-only {
253
+ position: absolute;
254
+ width: 1px;
255
+ height: 1px;
256
+ overflow: hidden;
257
+ clip: rect(0 0 0 0);
258
+ white-space: nowrap;
259
+ }
260
+ .sfa-image-picker {
261
+ display: flex;
262
+ flex-wrap: wrap;
263
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
264
+ }
265
+ .sfa-image-picker__btn {
266
+ position: relative;
267
+ display: inline-flex;
268
+ align-items: center;
269
+ cursor: pointer;
270
+ }
271
+ .sfa-image-picker__btn:focus-within {
272
+ outline: 2px solid var(--sf-color-accent, #1a1a1a);
273
+ outline-offset: 2px;
274
+ }
275
+ .sfa-image-grid {
276
+ display: grid;
277
+ grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
278
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
279
+ margin: 0;
280
+ padding: 0;
281
+ list-style: none;
282
+ }
283
+ .sfa-image-tile {
284
+ position: relative;
285
+ display: flex;
286
+ flex-direction: column;
287
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
288
+ min-width: 120px;
289
+ padding: calc(var(--sf-space-unit, 0.25rem) * 2);
290
+ border: 1px solid var(--sf-color-border, #e0e0e0);
291
+ border-radius: var(--sf-radius, 4px);
292
+ }
293
+ .sfa-image-tile[aria-busy='true'] {
294
+ opacity: 0.7;
295
+ }
296
+ .sfa-image-tile__img {
297
+ width: 100%;
298
+ aspect-ratio: 1;
299
+ object-fit: cover;
300
+ }
301
+ .sfa-image-tile__cover {
302
+ position: absolute;
303
+ top: calc(var(--sf-space-unit, 0.25rem) * 3);
304
+ left: calc(var(--sf-space-unit, 0.25rem) * 3);
305
+ padding: 0 calc(var(--sf-space-unit, 0.25rem) * 2);
306
+ border-radius: var(--sf-radius, 4px);
307
+ background: var(--sf-color-accent, #1a1a1a);
308
+ color: var(--sf-color-accent-fg, #ffffff);
309
+ font-size: 0.75rem;
310
+ }
311
+ .sfa-image-tile__actions {
312
+ display: flex;
313
+ flex-direction: column;
314
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
315
+ }
316
+ .sfa-spinner {
317
+ font-size: 0.875rem;
318
+ }
319
+ .sfa-spinner::before {
320
+ content: '';
321
+ display: inline-block;
322
+ width: 1em;
323
+ height: 1em;
324
+ margin-right: 0.5em;
325
+ vertical-align: -0.125em;
326
+ border: 2px solid currentColor;
327
+ border-top-color: transparent;
328
+ border-radius: 50%;
329
+ animation: sfa-spin 0.8s linear infinite;
330
+ }
331
+ @keyframes sfa-spin {
332
+ to {
333
+ transform: rotate(360deg);
334
+ }
335
+ }
336
+ @media (prefers-reduced-motion: reduce) {
337
+ .sfa-spinner::before {
338
+ animation: none;
339
+ }
340
+ }
341
+ .sfa-orders__toolbar {
342
+ display: flex;
343
+ flex-wrap: wrap;
344
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
345
+ margin: calc(var(--sf-space-unit, 0.25rem) * 4) 0;
346
+ }
347
+ .sfa-orders__more {
348
+ margin-top: calc(var(--sf-space-unit, 0.25rem) * 4);
349
+ }
350
+ .sfa-order__header {
351
+ display: flex;
352
+ flex-wrap: wrap;
353
+ align-items: center;
354
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
355
+ }
356
+ .sfa-order__section {
357
+ margin-top: calc(var(--sf-space-unit, 0.25rem) * 6);
358
+ }
359
+ .sfa-order__totals {
360
+ display: grid;
361
+ grid-template-columns: auto auto;
362
+ justify-content: end;
363
+ gap: calc(var(--sf-space-unit, 0.25rem) * 1)
364
+ calc(var(--sf-space-unit, 0.25rem) * 4);
365
+ margin-top: calc(var(--sf-space-unit, 0.25rem) * 3);
366
+ }
367
+ .sfa-order__address {
368
+ font-style: normal;
369
+ }
370
+ .sfa-order__refund--pending {
371
+ font-style: italic;
372
+ }
373
+ .sfa-order__actions,
374
+ .sfa-order__action {
375
+ display: grid;
376
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
377
+ justify-items: start;
378
+ }
379
+ .sfa-rates {
380
+ list-style: none;
381
+ margin: calc(var(--sf-space-unit, 0.25rem) * 4) 0;
382
+ padding: 0;
383
+ display: grid;
384
+ gap: calc(var(--sf-space-unit, 0.25rem) * 4);
385
+ }
386
+ .sfa-rate {
387
+ display: grid;
388
+ grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
389
+ gap: calc(var(--sf-space-unit, 0.25rem) * 3);
390
+ align-items: end;
391
+ padding: calc(var(--sf-space-unit, 0.25rem) * 4);
392
+ border: 1px solid var(--sf-color-border, #d4d4d4);
393
+ border-radius: var(--sf-radius, 4px);
394
+ }
395
+ .sfa-rate__active {
396
+ display: flex;
397
+ align-items: center;
398
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
399
+ }
400
+ .sfa-rate__actions,
401
+ .sfa-shipping__actions {
402
+ display: flex;
403
+ flex-wrap: wrap;
404
+ gap: calc(var(--sf-space-unit, 0.25rem) * 2);
405
+ }
@@ -0,0 +1,10 @@
1
+ import { ReactNode } from 'react';
2
+ import { AdminOrderDetail as OrderDetail } from '@develemit/commerce-contracts';
3
+ export interface AdminOrderDetailProps {
4
+ orderId: string;
5
+ actions?: (ctx: {
6
+ order: OrderDetail;
7
+ reload: () => void;
8
+ }) => ReactNode;
9
+ }
10
+ export declare function AdminOrderDetail({ orderId, actions }: AdminOrderDetailProps): import('react').JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function AdminOrderList(): import('react').JSX.Element;