@mr.dj2u/library-registry 0.0.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.
- package/LICENSE +21 -0
- package/README.md +42 -0
- package/THIRD_PARTY_NOTICES.md +90 -0
- package/assets/create-expo-app/sdk-56/assets/images/expo-badge-white.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/expo-badge.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/expo-logo.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/logo-glow.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/react-logo.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/react-logo@2x.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/react-logo@3x.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/tabIcons/explore.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/tabIcons/explore@2x.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/tabIcons/explore@3x.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/tabIcons/home.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/tabIcons/home@2x.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/tabIcons/home@3x.png +0 -0
- package/assets/create-expo-app/sdk-56/assets/images/tutorial-web.png +0 -0
- package/assets/create-expo-app/sdk-56/src/app/_layout.tsx +15 -0
- package/assets/create-expo-app/sdk-56/src/app/explore.tsx +180 -0
- package/assets/create-expo-app/sdk-56/src/app/index.tsx +98 -0
- package/assets/create-expo-app/sdk-56/src/components/animated-icon.module.css +6 -0
- package/assets/create-expo-app/sdk-56/src/components/animated-icon.tsx +132 -0
- package/assets/create-expo-app/sdk-56/src/components/animated-icon.web.tsx +108 -0
- package/assets/create-expo-app/sdk-56/src/components/app-tabs.tsx +32 -0
- package/assets/create-expo-app/sdk-56/src/components/app-tabs.web.tsx +115 -0
- package/assets/create-expo-app/sdk-56/src/components/external-link.tsx +25 -0
- package/assets/create-expo-app/sdk-56/src/components/hint-row.tsx +35 -0
- package/assets/create-expo-app/sdk-56/src/components/themed-text.tsx +73 -0
- package/assets/create-expo-app/sdk-56/src/components/themed-view.tsx +16 -0
- package/assets/create-expo-app/sdk-56/src/components/ui/collapsible.tsx +65 -0
- package/assets/create-expo-app/sdk-56/src/components/web-badge.tsx +43 -0
- package/assets/create-expo-app/sdk-56/src/constants/theme.ts +65 -0
- package/assets/create-expo-app/sdk-56/src/global.css +9 -0
- package/assets/create-expo-app/sdk-56/src/hooks/use-color-scheme.ts +1 -0
- package/assets/create-expo-app/sdk-56/src/hooks/use-color-scheme.web.ts +21 -0
- package/assets/create-expo-app/sdk-56/src/hooks/use-theme.ts +14 -0
- package/assets/create-expo-stack/2.21.3/base/components/BackButton.tsx +23 -0
- package/assets/create-expo-stack/2.21.3/base/components/Button.tsx +42 -0
- package/assets/create-expo-stack/2.21.3/base/components/Container.tsx +14 -0
- package/assets/create-expo-stack/2.21.3/base/components/EditScreenInfo.tsx +36 -0
- package/assets/create-expo-stack/2.21.3/base/components/HeaderButton.tsx +31 -0
- package/assets/create-expo-stack/2.21.3/base/components/ScreenContent.tsx +40 -0
- package/assets/create-expo-stack/2.21.3/base/components/TabBarIcon.tsx +15 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/ActivityIndicator.tsx +10 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Avatar.tsx +32 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Button.tsx +141 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/DatePicker/DatePicker.android.tsx +77 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/DatePicker/DatePicker.tsx +23 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/DatePicker/index.ts +1 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Icon/Icon.ios.tsx +55 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Icon/Icon.tsx +58 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Icon/index.ts +16 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Icon/types.ts +19 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Picker.tsx +42 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/ProgressIndicator.tsx +68 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Slider.tsx +28 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Text.tsx +55 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/ThemeToggle.tsx +33 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/components/nativewindui/Toggle.tsx +20 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/lib/cn.ts +6 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/lib/useColorScheme.tsx +21 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/lib/useHeaderSearchBar.tsx +33 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/theme/colors.ts +123 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/theme/index.ts +32 -0
- package/assets/create-expo-stack/2.21.3-mrdj.2/src/theme/with-opacity.ts +155 -0
- package/assets/mds/routes/drawer-tabs/data.tsx +1 -0
- package/assets/mds/routes/drawer-tabs/index.tsx +1 -0
- package/assets/mds/routes/drawer-tabs/nativewindui.tsx +1 -0
- package/assets/mds/routes/drawer-tabs/sdk-56.tsx +1 -0
- package/assets/mds/routes/drawer-tabs/stylist.tsx +1 -0
- package/assets/mds/scripts/stylist-sync-android.mjs +39 -0
- package/assets/mds/src/app/exposition/data.tsx +1 -0
- package/assets/mds/src/app/exposition/index.tsx +1 -0
- package/assets/mds/src/app/exposition/nativewindui.tsx +1 -0
- package/assets/mds/src/app/exposition/sdk-56.tsx +1 -0
- package/assets/mds/src/app/exposition/stylist-sync+api.ts +241 -0
- package/assets/mds/src/app/exposition/stylist.tsx +1 -0
- package/assets/mds/src/app/onboarding/account-setup.tsx +1 -0
- package/assets/mds/src/app/onboarding/agreement.tsx +1 -0
- package/assets/mds/src/app/onboarding/terms.tsx +1 -0
- package/assets/mds/src/app/onboarding.tsx +1 -0
- package/assets/mds/src/app/settings.tsx +1 -0
- package/assets/mds/src/components/exposition/index.ts +8 -0
- package/assets/mds/src/components/exposition/notice.tsx +3 -0
- package/assets/mds/src/components/exposition/package-card.tsx +76 -0
- package/assets/mds/src/components/swmansion/animated-pressable.tsx +54 -0
- package/assets/mds/src/components/swmansion/gesture-card.tsx +54 -0
- package/assets/mds/src/components/swmansion/keyboard-form.tsx +73 -0
- package/assets/mds/src/components/swmansion/screens-card.tsx +40 -0
- package/assets/mds/src/components/swmansion/software-mansion-logo.tsx +15 -0
- package/assets/mds/src/components/swmansion/svg-mark.tsx +16 -0
- package/assets/mds/src/data/mock-app.ts +21 -0
- package/assets/mds/src/features/exposition/data-screen.tsx +152 -0
- package/assets/mds/src/features/exposition/embedded-fonts.ts +72 -0
- package/assets/mds/src/features/exposition/expo-sdk-56-screen.tsx +709 -0
- package/assets/mds/src/features/exposition/exposition-screen.tsx +191 -0
- package/assets/mds/src/features/exposition/nativewindui-screen.tsx +125 -0
- package/assets/mds/src/features/exposition/stylist-screen.tsx +3456 -0
- package/assets/mds/src/features/onboarding/account-setup-screen.tsx +54 -0
- package/assets/mds/src/features/onboarding/agreement-screen.tsx +6 -0
- package/assets/mds/src/features/onboarding/components/legal-document-view.tsx +103 -0
- package/assets/mds/src/features/onboarding/legal-documents.ts +80 -0
- package/assets/mds/src/features/onboarding/onboarding-screen.tsx +167 -0
- package/assets/mds/src/features/onboarding/terms-screen.tsx +6 -0
- package/assets/mds/src/features/settings/settings-screen.tsx +57 -0
- package/assets/mds/src/services/local-data.native.ts +103 -0
- package/assets/mds/src/services/local-data.ts +38 -0
- package/assets/mds/src/theme/font-assets.ts +3 -0
- package/assets/mds/src/theme/provider.tsx +59 -0
- package/assets/mds/src/theme/tokens.ts +180 -0
- package/dist/catalog.d.ts +3 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +1110 -0
- package/dist/catalog.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +7 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +479 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +169 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +6 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +209 -0
- package/dist/validation.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { access, mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import defaultThemeTokens from '@/theme/tokens';
|
|
6
|
+
|
|
7
|
+
interface SyncResponse {
|
|
8
|
+
projectPath: string;
|
|
9
|
+
updatedFiles: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface StylistSyncRequestBody {
|
|
13
|
+
theme: unknown;
|
|
14
|
+
metadata?: {
|
|
15
|
+
writePolicy?: 'managed' | 'overwrite';
|
|
16
|
+
styleLibrary?:
|
|
17
|
+
| 'auto'
|
|
18
|
+
| 'uniwind'
|
|
19
|
+
| 'nativewind'
|
|
20
|
+
| 'nativewindui'
|
|
21
|
+
| 'unistyles'
|
|
22
|
+
| 'restyle'
|
|
23
|
+
| 'tamagui'
|
|
24
|
+
| 'stylesheet';
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function parseSyncResponse(stdout: string): SyncResponse {
|
|
29
|
+
const trimmed = stdout.trim();
|
|
30
|
+
if (!trimmed) {
|
|
31
|
+
throw new Error('Stylist sync returned empty output.');
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(trimmed) as SyncResponse;
|
|
35
|
+
} catch {
|
|
36
|
+
const match = trimmed.match(/\{[\s\S]*\}$/);
|
|
37
|
+
if (!match) {
|
|
38
|
+
throw new Error('Stylist sync returned non-JSON output.');
|
|
39
|
+
}
|
|
40
|
+
return JSON.parse(match[0]) as SyncResponse;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function POST(request: Request) {
|
|
45
|
+
try {
|
|
46
|
+
const payload = (await request.json()) as unknown;
|
|
47
|
+
const normalized = normalizeSyncPayload(payload);
|
|
48
|
+
const result = await runStylistSync(JSON.stringify(normalized.theme), normalized.metadata);
|
|
49
|
+
return Response.json(result);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return Response.json(
|
|
52
|
+
{ error: error instanceof Error ? error.message : 'Unknown stylist sync error' },
|
|
53
|
+
{ status: 400 }
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function GET() {
|
|
59
|
+
const configPath = path.resolve(process.cwd(), 'project', 'stylist.config.json');
|
|
60
|
+
const themePath = path.resolve(process.cwd(), 'project', 'theme.json');
|
|
61
|
+
const stylePath = path.resolve(process.cwd(), 'project', 'style.md');
|
|
62
|
+
|
|
63
|
+
const themeFromJson = await readThemeJson(themePath);
|
|
64
|
+
const themeFromStyle = await readThemeFromStyleMarkdown(stylePath);
|
|
65
|
+
const resolvedTheme = themeFromStyle ?? themeFromJson ?? defaultThemeTokens;
|
|
66
|
+
const themeSource = themeFromStyle ? 'style.md' : themeFromJson ? 'theme.json' : 'default';
|
|
67
|
+
const mismatchDetected =
|
|
68
|
+
Boolean(themeFromJson) &&
|
|
69
|
+
Boolean(themeFromStyle) &&
|
|
70
|
+
JSON.stringify(themeFromJson) !== JSON.stringify(themeFromStyle);
|
|
71
|
+
try {
|
|
72
|
+
const raw = await readFile(configPath, 'utf8');
|
|
73
|
+
const parsed = JSON.parse(raw) as { writePolicy?: string; styleLibrary?: string };
|
|
74
|
+
return Response.json({
|
|
75
|
+
hasConfig: true,
|
|
76
|
+
writePolicy: parsed.writePolicy ?? null,
|
|
77
|
+
styleLibrary: parsed.styleLibrary ?? null,
|
|
78
|
+
theme: resolvedTheme,
|
|
79
|
+
themeSource,
|
|
80
|
+
mismatchDetected,
|
|
81
|
+
});
|
|
82
|
+
} catch {
|
|
83
|
+
return Response.json({
|
|
84
|
+
hasConfig: false,
|
|
85
|
+
writePolicy: null,
|
|
86
|
+
styleLibrary: null,
|
|
87
|
+
theme: resolvedTheme,
|
|
88
|
+
themeSource,
|
|
89
|
+
mismatchDetected,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function normalizeSyncPayload(value: unknown): StylistSyncRequestBody {
|
|
95
|
+
if (!value || typeof value !== 'object') {
|
|
96
|
+
throw new Error('Invalid stylist payload.');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const asRecord = value as Record<string, unknown>;
|
|
100
|
+
if ('theme' in asRecord && asRecord.theme) {
|
|
101
|
+
return {
|
|
102
|
+
theme: asRecord.theme,
|
|
103
|
+
metadata:
|
|
104
|
+
asRecord.metadata && typeof asRecord.metadata === 'object'
|
|
105
|
+
? (asRecord.metadata as StylistSyncRequestBody['metadata'])
|
|
106
|
+
: undefined,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if ('metadata' in asRecord) {
|
|
111
|
+
throw new Error('Invalid stylist payload: missing theme.');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { theme: value };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function runStylistSync(
|
|
118
|
+
inputJson: string,
|
|
119
|
+
metadata?: StylistSyncRequestBody['metadata']
|
|
120
|
+
): Promise<SyncResponse> {
|
|
121
|
+
const tempDir = path.resolve(process.cwd(), '.expo', 'stylist-sync');
|
|
122
|
+
await mkdir(tempDir, { recursive: true });
|
|
123
|
+
const tempInputPath = path.join(
|
|
124
|
+
tempDir,
|
|
125
|
+
`theme-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
126
|
+
);
|
|
127
|
+
await writeFile(tempInputPath, inputJson, 'utf8');
|
|
128
|
+
|
|
129
|
+
const fileExists = async (filePath: string): Promise<boolean> => {
|
|
130
|
+
try {
|
|
131
|
+
await access(filePath);
|
|
132
|
+
return true;
|
|
133
|
+
} catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const runAttempt = async (
|
|
139
|
+
command: string,
|
|
140
|
+
args: string[],
|
|
141
|
+
env: NodeJS.ProcessEnv
|
|
142
|
+
): Promise<SyncResponse> => {
|
|
143
|
+
return await new Promise<SyncResponse>((resolve, reject) => {
|
|
144
|
+
const child = spawn(command, args, {
|
|
145
|
+
cwd: process.cwd(),
|
|
146
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
147
|
+
windowsHide: true,
|
|
148
|
+
env,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
let stdout = '';
|
|
152
|
+
let stderr = '';
|
|
153
|
+
child.stdout.on('data', (chunk) => {
|
|
154
|
+
stdout += String(chunk);
|
|
155
|
+
});
|
|
156
|
+
child.stderr.on('data', (chunk) => {
|
|
157
|
+
stderr += String(chunk);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
child.on('error', (error) => {
|
|
161
|
+
reject(error);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const timeout = setTimeout(() => {
|
|
165
|
+
child.kill();
|
|
166
|
+
reject(new Error('Stylist sync timed out after 120 seconds.'));
|
|
167
|
+
}, 120000);
|
|
168
|
+
|
|
169
|
+
child.on('close', (code) => {
|
|
170
|
+
clearTimeout(timeout);
|
|
171
|
+
if (code !== 0) {
|
|
172
|
+
reject(
|
|
173
|
+
new Error(stderr.trim() || `Stylist sync failed with exit code ${code ?? 'unknown'}.`)
|
|
174
|
+
);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
resolve(parseSyncResponse(stdout));
|
|
180
|
+
} catch (error) {
|
|
181
|
+
reject(
|
|
182
|
+
new Error(
|
|
183
|
+
`Failed to parse stylist sync output: ${error instanceof Error ? error.message : String(error)}${stderr.trim() ? ` | stderr: ${stderr.trim()}` : ''}`
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const scriptPath = path.resolve(process.cwd(), 'scripts', 'stylist-sync-android.mjs');
|
|
192
|
+
const env = {
|
|
193
|
+
...process.env,
|
|
194
|
+
MDS_STYLIST_INPUT_FILE: path.relative(process.cwd(), tempInputPath),
|
|
195
|
+
MDS_STYLIST_WRITE_POLICY: metadata?.writePolicy ?? 'managed',
|
|
196
|
+
MDS_STYLIST_STYLE_LIBRARY: metadata?.styleLibrary ?? 'auto',
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
if (!(await fileExists(scriptPath))) {
|
|
201
|
+
throw new Error('Stylist sync helper is missing. Run npm install, then retry.');
|
|
202
|
+
}
|
|
203
|
+
return await runAttempt(process.execPath, [scriptPath], env);
|
|
204
|
+
} finally {
|
|
205
|
+
try {
|
|
206
|
+
await unlink(tempInputPath);
|
|
207
|
+
} catch {
|
|
208
|
+
// no-op
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function readThemeJson(filePath: string): Promise<unknown | null> {
|
|
214
|
+
try {
|
|
215
|
+
const raw = await readFile(filePath, 'utf8');
|
|
216
|
+
return JSON.parse(raw) as unknown;
|
|
217
|
+
} catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function readThemeFromStyleMarkdown(filePath: string): Promise<unknown | null> {
|
|
223
|
+
try {
|
|
224
|
+
const raw = await readFile(filePath, 'utf8');
|
|
225
|
+
const startToken = '<!-- MDS_STYLIST_THEME_START -->';
|
|
226
|
+
const endToken = '<!-- MDS_STYLIST_THEME_END -->';
|
|
227
|
+
const startIndex = raw.indexOf(startToken);
|
|
228
|
+
const endIndex = raw.indexOf(endToken);
|
|
229
|
+
if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const block = raw.slice(startIndex, endIndex + endToken.length);
|
|
233
|
+
const match = block.match(/```json\s*([\s\S]*?)\s*```/i);
|
|
234
|
+
if (!match?.[1]) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
return JSON.parse(match[1]) as unknown;
|
|
238
|
+
} catch {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@/features/exposition/stylist-screen';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@/features/onboarding/account-setup-screen';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@/features/onboarding/agreement-screen';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@/features/onboarding/terms-screen';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@/features/onboarding/onboarding-screen';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@/features/settings/settings-screen';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { ExpositionNotice } from './notice';
|
|
2
|
+
export { PackageCard } from './package-card';
|
|
3
|
+
export { AnimatedPressable } from '../swmansion/animated-pressable';
|
|
4
|
+
export { GestureCard } from '../swmansion/gesture-card';
|
|
5
|
+
export { KeyboardForm } from '../swmansion/keyboard-form';
|
|
6
|
+
export { ScreensCard } from '../swmansion/screens-card';
|
|
7
|
+
export { SoftwareMansionLogo } from '../swmansion/software-mansion-logo';
|
|
8
|
+
export { SvgMark } from '../swmansion/svg-mark';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useAppTheme } from '../../theme/provider';
|
|
5
|
+
|
|
6
|
+
interface PackageCardProps {
|
|
7
|
+
title: string;
|
|
8
|
+
packageName: string;
|
|
9
|
+
body: string;
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function PackageCard({ title, packageName, body, children }: PackageCardProps) {
|
|
14
|
+
const theme = useAppTheme();
|
|
15
|
+
const colors = theme.activeColors;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<View
|
|
19
|
+
style={[
|
|
20
|
+
styles.card,
|
|
21
|
+
{
|
|
22
|
+
backgroundColor: colors.surface,
|
|
23
|
+
borderColor: colors.primary,
|
|
24
|
+
borderRadius: theme.layout.radius,
|
|
25
|
+
},
|
|
26
|
+
]}>
|
|
27
|
+
<Text style={[styles.packageName, { color: colors.text }]}>{packageName}</Text>
|
|
28
|
+
<Text
|
|
29
|
+
style={[
|
|
30
|
+
styles.title,
|
|
31
|
+
{
|
|
32
|
+
color: colors.text,
|
|
33
|
+
fontFamily: theme.typography.fontFamily,
|
|
34
|
+
fontWeight:
|
|
35
|
+
theme.typography.fontFamily === 'System' ||
|
|
36
|
+
theme.typography.fontFamily === 'monospace'
|
|
37
|
+
? '800'
|
|
38
|
+
: 'normal',
|
|
39
|
+
},
|
|
40
|
+
]}>
|
|
41
|
+
{title}
|
|
42
|
+
</Text>
|
|
43
|
+
<Text style={[styles.body, { color: colors.text }]}>{body}</Text>
|
|
44
|
+
{children ? <View style={styles.demo}>{children}</View> : null}
|
|
45
|
+
</View>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const styles = StyleSheet.create({
|
|
50
|
+
card: {
|
|
51
|
+
backgroundColor: '#ffffff',
|
|
52
|
+
borderColor: '#e5e7eb',
|
|
53
|
+
borderRadius: 12,
|
|
54
|
+
borderWidth: 1,
|
|
55
|
+
gap: 8,
|
|
56
|
+
padding: 16,
|
|
57
|
+
},
|
|
58
|
+
packageName: {
|
|
59
|
+
color: '#6b7280',
|
|
60
|
+
fontSize: 12,
|
|
61
|
+
fontWeight: '700',
|
|
62
|
+
},
|
|
63
|
+
title: {
|
|
64
|
+
color: '#111827',
|
|
65
|
+
fontSize: 17,
|
|
66
|
+
fontWeight: '800',
|
|
67
|
+
},
|
|
68
|
+
body: {
|
|
69
|
+
color: '#4b5563',
|
|
70
|
+
fontSize: 14,
|
|
71
|
+
lineHeight: 20,
|
|
72
|
+
},
|
|
73
|
+
demo: {
|
|
74
|
+
marginTop: 6,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Pressable, StyleSheet, Text } from 'react-native';
|
|
3
|
+
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
|
|
4
|
+
|
|
5
|
+
const AnimatedPressableBase = Animated.createAnimatedComponent(Pressable);
|
|
6
|
+
|
|
7
|
+
interface AnimatedPressableProps {
|
|
8
|
+
backgroundColor?: string;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
label?: string;
|
|
11
|
+
onPress?: () => void;
|
|
12
|
+
textColor?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function AnimatedPressable({
|
|
16
|
+
backgroundColor = '#111827',
|
|
17
|
+
children,
|
|
18
|
+
label = 'Reanimated press demo',
|
|
19
|
+
onPress,
|
|
20
|
+
textColor = '#ffffff',
|
|
21
|
+
}: AnimatedPressableProps) {
|
|
22
|
+
const pressed = useSharedValue(0);
|
|
23
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
24
|
+
transform: [{ scale: withTiming(pressed.value ? 0.97 : 1, { duration: 120 }) }],
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<AnimatedPressableBase
|
|
29
|
+
onPress={onPress}
|
|
30
|
+
onPressIn={() => {
|
|
31
|
+
pressed.value = 1;
|
|
32
|
+
}}
|
|
33
|
+
onPressOut={() => {
|
|
34
|
+
pressed.value = 0;
|
|
35
|
+
}}
|
|
36
|
+
style={[styles.button, { backgroundColor }, animatedStyle]}>
|
|
37
|
+
{children ?? <Text style={[styles.label, { color: textColor }]}>{label}</Text>}
|
|
38
|
+
</AnimatedPressableBase>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const styles = StyleSheet.create({
|
|
43
|
+
button: {
|
|
44
|
+
backgroundColor: '#111827',
|
|
45
|
+
borderRadius: 10,
|
|
46
|
+
paddingHorizontal: 16,
|
|
47
|
+
paddingVertical: 12,
|
|
48
|
+
},
|
|
49
|
+
label: {
|
|
50
|
+
fontSize: 15,
|
|
51
|
+
fontWeight: '700',
|
|
52
|
+
textAlign: 'center',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { StyleSheet, Text } from 'react-native';
|
|
2
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
3
|
+
import Animated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
|
|
4
|
+
|
|
5
|
+
interface GestureCardProps {
|
|
6
|
+
title: string;
|
|
7
|
+
body: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function GestureCard({ title, body }: GestureCardProps) {
|
|
11
|
+
const offset = useSharedValue(0);
|
|
12
|
+
const pan = Gesture.Pan()
|
|
13
|
+
.onChange((event) => {
|
|
14
|
+
offset.value = event.translationX;
|
|
15
|
+
})
|
|
16
|
+
.onFinalize(() => {
|
|
17
|
+
offset.value = withSpring(0);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const style = useAnimatedStyle(() => ({
|
|
21
|
+
transform: [{ translateX: offset.value }],
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<GestureDetector gesture={pan}>
|
|
26
|
+
<Animated.View style={[styles.card, style]}>
|
|
27
|
+
<Text style={styles.title}>{title}</Text>
|
|
28
|
+
<Text style={styles.body}>{body}</Text>
|
|
29
|
+
</Animated.View>
|
|
30
|
+
</GestureDetector>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const styles = StyleSheet.create({
|
|
35
|
+
card: {
|
|
36
|
+
backgroundColor: '#ffffff',
|
|
37
|
+
borderColor: '#e5e7eb',
|
|
38
|
+
borderRadius: 12,
|
|
39
|
+
borderWidth: 1,
|
|
40
|
+
padding: 16,
|
|
41
|
+
boxShadow: '0 6px 10px rgba(0, 0, 0, 0.08)',
|
|
42
|
+
},
|
|
43
|
+
title: {
|
|
44
|
+
color: '#111827',
|
|
45
|
+
fontSize: 16,
|
|
46
|
+
fontWeight: '700',
|
|
47
|
+
},
|
|
48
|
+
body: {
|
|
49
|
+
color: '#4b5563',
|
|
50
|
+
fontSize: 14,
|
|
51
|
+
lineHeight: 20,
|
|
52
|
+
marginTop: 8,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Keyboard, Platform, ScrollView, StyleSheet, TextInput } from 'react-native';
|
|
2
|
+
import { KeyboardAwareScrollView, KeyboardToolbar } from 'react-native-keyboard-controller';
|
|
3
|
+
|
|
4
|
+
export function KeyboardForm() {
|
|
5
|
+
if (Platform.OS === 'web') {
|
|
6
|
+
return (
|
|
7
|
+
<ScrollView contentContainerStyle={styles.form} style={styles.scroller}>
|
|
8
|
+
<TextInput
|
|
9
|
+
blurOnSubmit
|
|
10
|
+
onSubmitEditing={Keyboard.dismiss}
|
|
11
|
+
placeholder="Project note"
|
|
12
|
+
returnKeyType="done"
|
|
13
|
+
style={styles.input}
|
|
14
|
+
/>
|
|
15
|
+
<TextInput
|
|
16
|
+
blurOnSubmit
|
|
17
|
+
multiline
|
|
18
|
+
onSubmitEditing={Keyboard.dismiss}
|
|
19
|
+
placeholder="Details"
|
|
20
|
+
returnKeyType="done"
|
|
21
|
+
style={[styles.input, styles.multiline]}
|
|
22
|
+
/>
|
|
23
|
+
</ScrollView>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
<KeyboardAwareScrollView
|
|
29
|
+
bottomOffset={72}
|
|
30
|
+
contentContainerStyle={styles.form}
|
|
31
|
+
style={styles.scroller}>
|
|
32
|
+
<TextInput
|
|
33
|
+
blurOnSubmit
|
|
34
|
+
onSubmitEditing={Keyboard.dismiss}
|
|
35
|
+
placeholder="Project note"
|
|
36
|
+
returnKeyType="done"
|
|
37
|
+
style={styles.input}
|
|
38
|
+
/>
|
|
39
|
+
<TextInput
|
|
40
|
+
blurOnSubmit
|
|
41
|
+
multiline
|
|
42
|
+
onSubmitEditing={Keyboard.dismiss}
|
|
43
|
+
placeholder="Details"
|
|
44
|
+
returnKeyType="done"
|
|
45
|
+
style={[styles.input, styles.multiline]}
|
|
46
|
+
/>
|
|
47
|
+
</KeyboardAwareScrollView>
|
|
48
|
+
<KeyboardToolbar onDoneCallback={Keyboard.dismiss} />
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const styles = StyleSheet.create({
|
|
54
|
+
scroller: {
|
|
55
|
+
maxHeight: 220,
|
|
56
|
+
},
|
|
57
|
+
form: {
|
|
58
|
+
gap: 12,
|
|
59
|
+
paddingVertical: 8,
|
|
60
|
+
},
|
|
61
|
+
input: {
|
|
62
|
+
borderColor: '#d1d5db',
|
|
63
|
+
borderRadius: 10,
|
|
64
|
+
borderWidth: 1,
|
|
65
|
+
minHeight: 44,
|
|
66
|
+
paddingHorizontal: 12,
|
|
67
|
+
},
|
|
68
|
+
multiline: {
|
|
69
|
+
minHeight: 88,
|
|
70
|
+
paddingTop: 10,
|
|
71
|
+
textAlignVertical: 'top',
|
|
72
|
+
},
|
|
73
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
import { enableScreens } from 'react-native-screens';
|
|
4
|
+
|
|
5
|
+
export function ScreensCard() {
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
enableScreens(true);
|
|
8
|
+
}, []);
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<View style={styles.card}>
|
|
12
|
+
<Text style={styles.title}>Native Screens</Text>
|
|
13
|
+
<Text style={styles.body}>
|
|
14
|
+
react-native-screens is enabled so navigation can use native screen primitives for better
|
|
15
|
+
memory and lifecycle behavior.
|
|
16
|
+
</Text>
|
|
17
|
+
</View>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const styles = StyleSheet.create({
|
|
22
|
+
card: {
|
|
23
|
+
backgroundColor: '#eef2ff',
|
|
24
|
+
borderColor: '#c7d2fe',
|
|
25
|
+
borderRadius: 12,
|
|
26
|
+
borderWidth: 1,
|
|
27
|
+
padding: 16,
|
|
28
|
+
},
|
|
29
|
+
title: {
|
|
30
|
+
color: '#312e81',
|
|
31
|
+
fontSize: 16,
|
|
32
|
+
fontWeight: '700',
|
|
33
|
+
},
|
|
34
|
+
body: {
|
|
35
|
+
color: '#4338ca',
|
|
36
|
+
fontSize: 14,
|
|
37
|
+
lineHeight: 20,
|
|
38
|
+
marginTop: 8,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SvgXml } from 'react-native-svg';
|
|
2
|
+
|
|
3
|
+
const softwareMansionLogoXml = `<svg fill="currentColor" viewBox="0 0 149.79 80" xmlns="http://www.w3.org/2000/svg" width="150" height="80" preserveAspectRatio="xMidYMid meet"><path d="M24.281 79.063h124.58V24.356L125.513.937H.933v54.707z" fill="#fff"></path><path d="M0 .001h125.9l23.894 23.967V80h-125.9L.002 56.033V0zm1.867 3.198v52.057l21.48 21.545V24.744zm1.321-1.324 21.48 21.545h121.94l-21.48-21.545zm144.74 23.418H25.218v52.833h122.71z"></path><path d="M47.255 46.215c0 1.873-1.246 3.496-4.234 3.496-1.308 0-2.367-.312-3.3-.686v-2.623c.996.5 2.179.812 3.237.812.997 0 1.494-.312 1.494-.875 0-1.748-4.731-1.187-4.731-4.746 0-2.185 1.744-3.498 4.172-3.498.995 0 1.929.251 2.926.813v2.685c-1.308-.812-2.242-1.062-2.989-1.062-.872 0-1.37.313-1.37.874-.062 1.625 4.794 1 4.794 4.81z"></path><path d="M49.62 43.903c0-3.184 2.614-5.807 5.79-5.807 3.175 0 5.79 2.623 5.79 5.808 0 3.185-2.615 5.807-5.79 5.807-3.176-.062-5.79-2.622-5.79-5.807zm8.716 0c0-1.748-1.307-3.06-2.927-3.06-1.618 0-2.925 1.312-2.925 3.061 0 1.748 1.307 3.06 2.925 3.06 1.62 0 2.927-1.312 2.927-3.061z"></path><path d="M67.675 37.408v.937h3.674l-1.246 2.623h-2.366v8.493H65.06v-8.556h-1.867v-2.622h1.867v-1.061c0-3.373 1.744-5.059 4.483-5.059.685 0 1.307.125 1.868.25v2.623c-.498-.187-1.058-.25-1.62-.25-1.494 0-2.116 1-2.116 2.623z"></path><path d="M76.952 40.906v4.434c0 1.187.685 1.687 1.743 1.687.685 0 1.37-.188 1.93-.562v2.747c-.747.312-1.431.5-2.427.5-2.43 0-3.923-1.312-3.923-3.998v-4.746h-1.619v-2.622h1.62v-2.873l2.676-.687v3.56h3.674v2.622h-3.674z"></path><path d="m99.988 38.346-3.549 11.115h-2.677l-2.428-7.619-2.49 7.619h-2.678l-3.549-11.115h3.051l1.992 7.432 2.367-7.432h2.676l2.367 7.432 1.992-7.432z"></path><path d="M101.36 43.903c0-3.184 2.303-5.807 5.48-5.807 1.244 0 2.24.375 2.987 1v-.75h2.678v11.115h-2.616v-.874c-.747.687-1.805 1.124-3.112 1.124-3.052-.062-5.417-2.622-5.417-5.807zm8.717 0c0-1.748-1.308-3.06-2.927-3.06s-2.926 1.312-2.926 3.061c0 1.748 1.307 3.06 2.926 3.06 1.619 0 2.927-1.312 2.927-3.061z"></path><path d="M116.3 38.346h2.615v1.498c.81-1.498 2.303-1.748 3.611-1.748v3.184c-1.868-.5-3.548.562-3.548 2.936v5.183H116.3z"></path><path d="M130.99 47.089a9.627 9.627 0 0 0 3.549-.687l-1.37 2.81a7.296 7.296 0 0 1-2.677.5c-3.923 0-6.288-2.436-6.288-5.808 0-3.185 2.365-5.808 5.79-5.808 2.303 0 4.171 1.187 4.918 2.685v4.06h-7.844c.373 1.31 1.68 2.248 3.922 2.248zm-3.985-4.371h5.79c-.373-1.313-1.494-2.124-2.926-2.124-1.37 0-2.428.874-2.864 2.124z"></path><path d="M55.223 58.83v7.306h-2.677v-6.869c0-1.187-.872-1.873-1.743-1.873-.934 0-1.744.686-1.744 1.873v6.869h-2.676v-6.869c0-1.187-.872-1.873-1.744-1.873-.934 0-1.743.686-1.743 1.873v6.869H40.22V55.02h2.615v.812c.622-.75 1.432-1 2.49-1 1.183 0 2.18.5 2.864 1.437.871-1 1.992-1.436 3.362-1.436 2.054 0 3.673 1.623 3.673 3.996z"></path><path d="M58.025 60.579c0-3.186 2.304-5.808 5.478-5.808 1.246 0 2.243.374 2.989.999v-.75h2.677v11.115h-2.615v-.874c-.747.687-1.805 1.124-3.112 1.124-3.052 0-5.417-2.622-5.417-5.807zm8.717 0c0-1.75-1.308-3.061-2.927-3.061s-2.926 1.312-2.926 3.061c0 1.748 1.308 3.06 2.926 3.06s2.927-1.312 2.927-3.061z"></path><path d="M72.843 55.02h2.614v.812c.81-.812 1.868-1.062 2.927-1.062 2.304 0 4.17 1.748 4.17 4.122v7.18h-2.676v-6.556a2.103 2.103 0 0 0-2.117-2.123 2.102 2.102 0 0 0-2.116 2.123v6.62h-2.678V55.02h-.124z"></path><path d="M93.326 62.889c0 1.873-1.245 3.496-4.234 3.496-1.307 0-2.366-.312-3.299-.686v-2.623c.996.5 2.179.812 3.238.812.996 0 1.493-.312 1.493-.874 0-1.75-4.73-1.188-4.73-4.747 0-2.186 1.742-3.497 4.17-3.497.996 0 1.93.25 2.927.812v2.685c-1.308-.812-2.242-1.062-2.989-1.062-.872 0-1.37.312-1.37.874-.062 1.687 4.794 1.063 4.794 4.81z"></path><path d="M99.116 55.02v11.115h-2.677V55.02z"></path><path d="M101.92 60.579c0-3.186 2.615-5.808 5.79-5.808s5.79 2.622 5.79 5.807-2.615 5.807-5.79 5.807-5.79-2.622-5.79-5.807zm8.717 0c0-1.75-1.307-3.061-2.927-3.061-1.618 0-2.926 1.312-2.926 3.061 0 1.748 1.308 3.06 2.926 3.06 1.62 0 2.927-1.312 2.927-3.061z"></path><path d="M116.24 55.02h2.615v.812c.81-.812 1.868-1.062 2.927-1.062 2.303 0 4.17 1.748 4.17 4.122v7.18h-2.676v-6.556a2.103 2.103 0 0 0-2.118-2.123 2.103 2.103 0 0 0-2.116 2.123v6.62h-2.677V55.02h-.125z"></path><path d="M131.24 63.076v.437h-.933v2.623h-.499v-2.623h-.933v-.437z"></path><path d="m132.3 63.076.997 2.435.933-2.435h.623v3.06h-.498v-2.248l-.934 2.248h-.436l-.934-2.248v2.248h-.498v-3.061h.747z"></path></svg>`;
|
|
4
|
+
|
|
5
|
+
export function SoftwareMansionLogo({
|
|
6
|
+
width = 150,
|
|
7
|
+
height = 80,
|
|
8
|
+
}: {
|
|
9
|
+
width?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
}) {
|
|
12
|
+
return (
|
|
13
|
+
<SvgXml xml={softwareMansionLogoXml} width={width} height={height} accessibilityRole="image" />
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Svg, { Path } from 'react-native-svg';
|
|
2
|
+
|
|
3
|
+
export function SvgMark({ size = 44 }: { size?: number }) {
|
|
4
|
+
return (
|
|
5
|
+
<Svg width={size} height={size} viewBox="0 0 2048 2048" accessibilityRole="image">
|
|
6
|
+
<Path
|
|
7
|
+
fill="#5666ff"
|
|
8
|
+
d="m146.9 1305.8l-14.4 30q0 32.2 89.9 62.1 91 28.9 198.6 28.9 108.8 0 238.6-32.2 129.8-32.2 225.2-78.8 96.6-46.6 158.7-97.6 63.3-51.1 63.3-88.8 0-47.7-111-88.8-111-41-322.9-89.8-210.8-50-309.6-125.4-97.6-75.5-97.6-183.1 0-108.8 77.6-207.5 77.7-98.8 202-175.3 125.4-76.6 273-136.5 305.1-123.2 565.9-123.2 99.9 0 176.4 17.8 146.5 34.4 146.5 90.9 0 56.6-10 77.7-10 20-16.6 26.7-5.6 6.6-15.6 13.3-8.9 6.6-13.3 10-48.8 41-267.4 51-75.5 3.3-82.1 7.8-6.7 4.4-12.2 4.4-4.5 0-11.1-8.9-6.7-8.9-6.7-28.8 0-20 43.3-73.3-135.4 7.8-289.6 62.2-153.2 54.4-266.3 123.1-113.2 67.7-188.7 134.3-75.4 65.5-75.4 93.2 0 26.7 16.6 44.4 46.6 49.9 258.6 104.3 219.7 56.6 292.9 91 73.2 34.4 120.9 65.5 48.9 31 77.7 63.2 67.7 77.7 67.7 157.6 0 79.9-43.3 149.8-42.1 69.9-128.7 135.4-85.4 65.4-201.9 116.5-255.3 114.3-608.1 114.3-257.5 0-328.5-136.5-18.8-34.4-18.8-71 0-37.8 16.6-67.7 17.8-30 42.2-45.5 47.7-30 67.7-30 19.9 0 19.9 13.3z"
|
|
9
|
+
/>
|
|
10
|
+
<Path
|
|
11
|
+
fill="#f66d22"
|
|
12
|
+
d="m486.9 1709.8l-14.4 30q0 32.2 89.9 62.1 91 28.9 198.6 28.9 108.8 0 238.6-32.2 129.8-32.2 225.2-78.8 96.6-46.6 158.7-97.6 63.3-51.1 63.3-88.8 0-47.7-111-88.8-111-41-322.9-89.8-210.8-50-309.6-125.4-97.6-75.5-97.6-183.1 0-108.8 77.6-207.5 77.7-98.8 202-175.3 125.4-76.6 273-136.5 305.1-123.2 565.9-123.2 99.9 0 176.4 17.8 146.5 34.4 146.5 90.9 0 56.6-10 77.7-10 20-16.6 26.7-5.6 6.6-15.6 13.3-8.9 6.6-13.3 10-48.8 41-267.4 51-75.5 3.3-82.1 7.8-6.7 4.4-12.2 4.4-4.5 0-11.1-8.9-6.7-8.9-6.7-28.8 0-20 43.3-73.3-135.4 7.8-289.6 62.2-153.2 54.4-266.3 123.1-113.2 67.7-188.7 134.3-75.4 65.5-75.4 93.2 0 26.7 16.6 44.4 46.6 49.9 258.6 104.3 219.7 56.6 292.9 91 73.2 34.4 120.9 65.5 48.9 31 77.7 63.2 67.7 77.7 67.7 157.6 0 79.9-43.3 149.8-42.1 69.9-128.7 135.4-85.4 65.4-201.9 116.5-255.3 114.3-608.1 114.3-257.5 0-328.5-136.5-18.8-34.4-18.8-71 0-37.8 16.6-67.7 17.8-30 42.2-45.5 47.7-30 67.7-30 19.9 0 19.9 13.3z"
|
|
13
|
+
/>
|
|
14
|
+
</Svg>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface AppTask {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
status: 'todo' | 'doing' | 'done';
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface AppSnapshot {
|
|
8
|
+
name: string;
|
|
9
|
+
audience: string;
|
|
10
|
+
tasks: AppTask[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const appSnapshot: AppSnapshot = {
|
|
14
|
+
name: '[APP NAME]',
|
|
15
|
+
audience: '[TARGET AUDIENCE]',
|
|
16
|
+
tasks: [
|
|
17
|
+
{ id: 'task-1', title: 'Shape the first user flow', status: 'doing' },
|
|
18
|
+
{ id: 'task-2', title: 'Replace mock data with the real data layer', status: 'todo' },
|
|
19
|
+
{ id: 'task-3', title: 'Run mds doctor before pushing', status: 'todo' },
|
|
20
|
+
] satisfies AppTask[],
|
|
21
|
+
};
|