@tanstack/cta-ui 0.10.0-alpha.18

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 (42) hide show
  1. package/.cursorrules +7 -0
  2. package/LICENSE +21 -0
  3. package/app.config.js +22 -0
  4. package/components.json +21 -0
  5. package/lib/index.ts +22 -0
  6. package/lib-dist/index.d.ts +1 -0
  7. package/lib-dist/index.js +13 -0
  8. package/package.json +58 -0
  9. package/public/favicon.ico +0 -0
  10. package/public/logo192.png +0 -0
  11. package/public/logo512.png +0 -0
  12. package/public/manifest.json +25 -0
  13. package/public/robots.txt +3 -0
  14. package/src/api.ts +6 -0
  15. package/src/client.tsx +8 -0
  16. package/src/components/Header.tsx +13 -0
  17. package/src/components/applied-add-on.tsx +149 -0
  18. package/src/components/file-tree.tsx +77 -0
  19. package/src/components/file-viewer.tsx +59 -0
  20. package/src/components/ui/button.tsx +59 -0
  21. package/src/components/ui/checkbox.tsx +30 -0
  22. package/src/components/ui/dialog.tsx +133 -0
  23. package/src/components/ui/table.tsx +114 -0
  24. package/src/components/ui/tabs.tsx +64 -0
  25. package/src/components/ui/toggle-group.tsx +71 -0
  26. package/src/components/ui/toggle.tsx +47 -0
  27. package/src/components/ui/tree-view.tsx +492 -0
  28. package/src/integrations/tanstack-query/layout.tsx +5 -0
  29. package/src/integrations/tanstack-query/root-provider.tsx +15 -0
  30. package/src/lib/server-fns.ts +78 -0
  31. package/src/lib/utils.ts +6 -0
  32. package/src/logo.svg +44 -0
  33. package/src/routeTree.gen.ts +111 -0
  34. package/src/router.tsx +32 -0
  35. package/src/routes/__root.tsx +57 -0
  36. package/src/routes/api.demo-names.ts +11 -0
  37. package/src/routes/demo.tanstack-query.tsx +28 -0
  38. package/src/routes/index.tsx +222 -0
  39. package/src/ssr.tsx +12 -0
  40. package/src/styles.css +138 -0
  41. package/tsconfig.json +28 -0
  42. package/tsconfig.lib.json +17 -0
@@ -0,0 +1,492 @@
1
+ import React from 'react'
2
+ import * as AccordionPrimitive from '@radix-ui/react-accordion'
3
+ import { ChevronRight } from 'lucide-react'
4
+ import { cva } from 'class-variance-authority'
5
+ import { cn } from '@/lib/utils'
6
+
7
+ const treeVariants = cva(
8
+ 'group hover:before:opacity-100 before:absolute before:rounded-lg before:left-0 px-2 before:w-full before:opacity-0 before:bg-accent/70 before:h-[2rem] before:-z-10',
9
+ )
10
+
11
+ const selectedTreeVariants = cva(
12
+ 'before:opacity-100 before:bg-accent/70 text-accent-foreground',
13
+ )
14
+
15
+ const dragOverVariants = cva(
16
+ 'before:opacity-100 before:bg-primary/20 text-primary-foreground',
17
+ )
18
+
19
+ interface TreeDataItem {
20
+ id: string
21
+ name: string
22
+ icon?: any
23
+ selectedIcon?: any
24
+ openIcon?: any
25
+ children?: TreeDataItem[]
26
+ actions?: React.ReactNode
27
+ onClick?: () => void
28
+ draggable?: boolean
29
+ droppable?: boolean
30
+ className?: string
31
+ }
32
+
33
+ type TreeProps = React.HTMLAttributes<HTMLDivElement> & {
34
+ data: TreeDataItem[] | TreeDataItem
35
+ initialSelectedItemId?: string
36
+ onSelectChange?: (item: TreeDataItem | undefined) => void
37
+ expandAll?: boolean
38
+ defaultNodeIcon?: any
39
+ defaultLeafIcon?: any
40
+ onDocumentDrag?: (sourceItem: TreeDataItem, targetItem: TreeDataItem) => void
41
+ }
42
+
43
+ const TreeView = React.forwardRef<HTMLDivElement, TreeProps>(
44
+ (
45
+ {
46
+ data,
47
+ initialSelectedItemId,
48
+ onSelectChange,
49
+ expandAll,
50
+ defaultLeafIcon,
51
+ defaultNodeIcon,
52
+ className,
53
+ onDocumentDrag,
54
+ ...props
55
+ },
56
+ ref,
57
+ ) => {
58
+ const [selectedItemId, setSelectedItemId] = React.useState<
59
+ string | undefined
60
+ >(initialSelectedItemId)
61
+
62
+ const [draggedItem, setDraggedItem] = React.useState<TreeDataItem | null>(
63
+ null,
64
+ )
65
+
66
+ const handleSelectChange = React.useCallback(
67
+ (item: TreeDataItem | undefined) => {
68
+ setSelectedItemId(item?.id)
69
+ if (onSelectChange) {
70
+ onSelectChange(item)
71
+ }
72
+ },
73
+ [onSelectChange],
74
+ )
75
+
76
+ const handleDragStart = React.useCallback((item: TreeDataItem) => {
77
+ setDraggedItem(item)
78
+ }, [])
79
+
80
+ const handleDrop = React.useCallback(
81
+ (targetItem: TreeDataItem) => {
82
+ if (draggedItem && onDocumentDrag && draggedItem.id !== targetItem.id) {
83
+ onDocumentDrag(draggedItem, targetItem)
84
+ }
85
+ setDraggedItem(null)
86
+ },
87
+ [draggedItem, onDocumentDrag],
88
+ )
89
+
90
+ const expandedItemIds = React.useMemo(() => {
91
+ if (!initialSelectedItemId) {
92
+ return [] as string[]
93
+ }
94
+
95
+ const ids: string[] = []
96
+
97
+ function walkTreeItems(
98
+ items: TreeDataItem[] | TreeDataItem,
99
+ targetId: string,
100
+ ) {
101
+ if (items instanceof Array) {
102
+ for (let i = 0; i < items.length; i++) {
103
+ ids.push(items[i]!.id)
104
+ if (walkTreeItems(items[i]!, targetId) && !expandAll) {
105
+ return true
106
+ }
107
+ if (!expandAll) ids.pop()
108
+ }
109
+ } else if (!expandAll && items.id === targetId) {
110
+ return true
111
+ } else if (items.children) {
112
+ return walkTreeItems(items.children, targetId)
113
+ }
114
+ }
115
+
116
+ walkTreeItems(data, initialSelectedItemId)
117
+ return ids
118
+ }, [data, expandAll, initialSelectedItemId])
119
+
120
+ return (
121
+ <div className={cn('overflow-hidden relative p-2', className)}>
122
+ <TreeItem
123
+ data={data}
124
+ ref={ref}
125
+ selectedItemId={selectedItemId}
126
+ handleSelectChange={handleSelectChange}
127
+ expandedItemIds={expandedItemIds}
128
+ defaultLeafIcon={defaultLeafIcon}
129
+ defaultNodeIcon={defaultNodeIcon}
130
+ handleDragStart={handleDragStart}
131
+ handleDrop={handleDrop}
132
+ draggedItem={draggedItem}
133
+ {...props}
134
+ />
135
+ <div
136
+ className="w-full h-[48px]"
137
+ onDrop={(e) => {
138
+ handleDrop({ id: '', name: 'parent_div' })
139
+ }}
140
+ ></div>
141
+ </div>
142
+ )
143
+ },
144
+ )
145
+ TreeView.displayName = 'TreeView'
146
+
147
+ type TreeItemProps = TreeProps & {
148
+ selectedItemId?: string
149
+ handleSelectChange: (item: TreeDataItem | undefined) => void
150
+ expandedItemIds: string[]
151
+ defaultNodeIcon?: any
152
+ defaultLeafIcon?: any
153
+ handleDragStart?: (item: TreeDataItem) => void
154
+ handleDrop?: (item: TreeDataItem) => void
155
+ draggedItem: TreeDataItem | null
156
+ }
157
+
158
+ const TreeItem = React.forwardRef<HTMLDivElement, TreeItemProps>(
159
+ (
160
+ {
161
+ className,
162
+ data,
163
+ selectedItemId,
164
+ handleSelectChange,
165
+ expandedItemIds,
166
+ defaultNodeIcon,
167
+ defaultLeafIcon,
168
+ handleDragStart,
169
+ handleDrop,
170
+ draggedItem,
171
+ ...props
172
+ },
173
+ ref,
174
+ ) => {
175
+ if (!(data instanceof Array)) {
176
+ data = [data]
177
+ }
178
+ return (
179
+ <div ref={ref} role="tree" className={className} {...props}>
180
+ <ul>
181
+ {data.map((item) => (
182
+ <li key={item.id}>
183
+ {item.children ? (
184
+ <TreeNode
185
+ item={item}
186
+ selectedItemId={selectedItemId}
187
+ expandedItemIds={expandedItemIds}
188
+ handleSelectChange={handleSelectChange}
189
+ defaultNodeIcon={defaultNodeIcon}
190
+ defaultLeafIcon={defaultLeafIcon}
191
+ handleDragStart={handleDragStart}
192
+ handleDrop={handleDrop}
193
+ draggedItem={draggedItem}
194
+ />
195
+ ) : (
196
+ <TreeLeaf
197
+ item={item}
198
+ selectedItemId={selectedItemId}
199
+ handleSelectChange={handleSelectChange}
200
+ defaultLeafIcon={defaultLeafIcon}
201
+ handleDragStart={handleDragStart}
202
+ handleDrop={handleDrop}
203
+ draggedItem={draggedItem}
204
+ className={item.className}
205
+ />
206
+ )}
207
+ </li>
208
+ ))}
209
+ </ul>
210
+ </div>
211
+ )
212
+ },
213
+ )
214
+ TreeItem.displayName = 'TreeItem'
215
+
216
+ const TreeNode = ({
217
+ item,
218
+ handleSelectChange,
219
+ expandedItemIds,
220
+ selectedItemId,
221
+ defaultNodeIcon,
222
+ defaultLeafIcon,
223
+ handleDragStart,
224
+ handleDrop,
225
+ draggedItem,
226
+ }: {
227
+ item: TreeDataItem
228
+ handleSelectChange: (item: TreeDataItem | undefined) => void
229
+ expandedItemIds: string[]
230
+ selectedItemId?: string
231
+ defaultNodeIcon?: any
232
+ defaultLeafIcon?: any
233
+ handleDragStart?: (item: TreeDataItem) => void
234
+ handleDrop?: (item: TreeDataItem) => void
235
+ draggedItem: TreeDataItem | null
236
+ }) => {
237
+ const [value, setValue] = React.useState(
238
+ expandedItemIds.includes(item.id) ? [item.id] : [],
239
+ )
240
+ const [isDragOver, setIsDragOver] = React.useState(false)
241
+
242
+ const onDragStart = (e: React.DragEvent) => {
243
+ if (!item.draggable) {
244
+ e.preventDefault()
245
+ return
246
+ }
247
+ e.dataTransfer.setData('text/plain', item.id)
248
+ handleDragStart?.(item)
249
+ }
250
+
251
+ const onDragOver = (e: React.DragEvent) => {
252
+ if (item.droppable !== false && draggedItem && draggedItem.id !== item.id) {
253
+ e.preventDefault()
254
+ setIsDragOver(true)
255
+ }
256
+ }
257
+
258
+ const onDragLeave = () => {
259
+ setIsDragOver(false)
260
+ }
261
+
262
+ const onDrop = (e: React.DragEvent) => {
263
+ e.preventDefault()
264
+ setIsDragOver(false)
265
+ handleDrop?.(item)
266
+ }
267
+
268
+ return (
269
+ <AccordionPrimitive.Root
270
+ type="multiple"
271
+ value={value}
272
+ onValueChange={(s) => setValue(s)}
273
+ >
274
+ <AccordionPrimitive.Item value={item.id}>
275
+ <AccordionTrigger
276
+ className={cn(
277
+ treeVariants(),
278
+ selectedItemId === item.id && selectedTreeVariants(),
279
+ isDragOver && dragOverVariants(),
280
+ )}
281
+ onClick={() => {
282
+ handleSelectChange(item)
283
+ item.onClick?.()
284
+ }}
285
+ draggable={!!item.draggable}
286
+ onDragStart={onDragStart}
287
+ onDragOver={onDragOver}
288
+ onDragLeave={onDragLeave}
289
+ onDrop={onDrop}
290
+ >
291
+ <TreeIcon
292
+ item={item}
293
+ isSelected={selectedItemId === item.id}
294
+ isOpen={value.includes(item.id)}
295
+ default={defaultNodeIcon}
296
+ />
297
+ <span className="text-sm truncate">{item.name}</span>
298
+ <TreeActions isSelected={selectedItemId === item.id}>
299
+ {item.actions}
300
+ </TreeActions>
301
+ </AccordionTrigger>
302
+ <AccordionContent className="ml-4 pl-1 border-l">
303
+ <TreeItem
304
+ data={item.children ? item.children : item}
305
+ selectedItemId={selectedItemId}
306
+ handleSelectChange={handleSelectChange}
307
+ expandedItemIds={expandedItemIds}
308
+ defaultLeafIcon={defaultLeafIcon}
309
+ defaultNodeIcon={defaultNodeIcon}
310
+ handleDragStart={handleDragStart}
311
+ handleDrop={handleDrop}
312
+ draggedItem={draggedItem}
313
+ />
314
+ </AccordionContent>
315
+ </AccordionPrimitive.Item>
316
+ </AccordionPrimitive.Root>
317
+ )
318
+ }
319
+
320
+ const TreeLeaf = React.forwardRef<
321
+ HTMLDivElement,
322
+ React.HTMLAttributes<HTMLDivElement> & {
323
+ item: TreeDataItem
324
+ selectedItemId?: string
325
+ handleSelectChange: (item: TreeDataItem | undefined) => void
326
+ defaultLeafIcon?: any
327
+ handleDragStart?: (item: TreeDataItem) => void
328
+ handleDrop?: (item: TreeDataItem) => void
329
+ draggedItem: TreeDataItem | null
330
+ }
331
+ >(
332
+ (
333
+ {
334
+ className,
335
+ item,
336
+ selectedItemId,
337
+ handleSelectChange,
338
+ defaultLeafIcon,
339
+ handleDragStart,
340
+ handleDrop,
341
+ draggedItem,
342
+ ...props
343
+ },
344
+ ref,
345
+ ) => {
346
+ const [isDragOver, setIsDragOver] = React.useState(false)
347
+
348
+ const onDragStart = (e: React.DragEvent) => {
349
+ if (!item.draggable) {
350
+ e.preventDefault()
351
+ return
352
+ }
353
+ e.dataTransfer.setData('text/plain', item.id)
354
+ handleDragStart?.(item)
355
+ }
356
+
357
+ const onDragOver = (e: React.DragEvent) => {
358
+ if (
359
+ item.droppable !== false &&
360
+ draggedItem &&
361
+ draggedItem.id !== item.id
362
+ ) {
363
+ e.preventDefault()
364
+ setIsDragOver(true)
365
+ }
366
+ }
367
+
368
+ const onDragLeave = () => {
369
+ setIsDragOver(false)
370
+ }
371
+
372
+ const onDrop = (e: React.DragEvent) => {
373
+ e.preventDefault()
374
+ setIsDragOver(false)
375
+ handleDrop?.(item)
376
+ }
377
+
378
+ return (
379
+ <div
380
+ ref={ref}
381
+ className={cn(
382
+ 'ml-5 flex text-left items-center py-2 cursor-pointer before:right-1',
383
+ treeVariants(),
384
+ className,
385
+ selectedItemId === item.id && selectedTreeVariants(),
386
+ isDragOver && dragOverVariants(),
387
+ )}
388
+ onClick={() => {
389
+ handleSelectChange(item)
390
+ item.onClick?.()
391
+ }}
392
+ draggable={!!item.draggable}
393
+ onDragStart={onDragStart}
394
+ onDragOver={onDragOver}
395
+ onDragLeave={onDragLeave}
396
+ onDrop={onDrop}
397
+ {...props}
398
+ >
399
+ <TreeIcon
400
+ item={item}
401
+ isSelected={selectedItemId === item.id}
402
+ default={defaultLeafIcon}
403
+ />
404
+ <span className="flex-grow text-sm truncate">{item.name}</span>
405
+ <TreeActions isSelected={selectedItemId === item.id}>
406
+ {item.actions}
407
+ </TreeActions>
408
+ </div>
409
+ )
410
+ },
411
+ )
412
+ TreeLeaf.displayName = 'TreeLeaf'
413
+
414
+ const AccordionTrigger = React.forwardRef<
415
+ React.ElementRef<typeof AccordionPrimitive.Trigger>,
416
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
417
+ >(({ className, children, ...props }, ref) => (
418
+ <AccordionPrimitive.Header>
419
+ <AccordionPrimitive.Trigger
420
+ ref={ref}
421
+ className={cn(
422
+ 'flex flex-1 w-full items-center py-2 transition-all first:[&[data-state=open]>svg]:rotate-90',
423
+ className,
424
+ )}
425
+ {...props}
426
+ >
427
+ <ChevronRight className="h-4 w-4 shrink-0 transition-transform duration-200 text-accent-foreground/50 mr-1" />
428
+ {children}
429
+ </AccordionPrimitive.Trigger>
430
+ </AccordionPrimitive.Header>
431
+ ))
432
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
433
+
434
+ const AccordionContent = React.forwardRef<
435
+ React.ElementRef<typeof AccordionPrimitive.Content>,
436
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
437
+ >(({ className, children, ...props }, ref) => (
438
+ <AccordionPrimitive.Content
439
+ ref={ref}
440
+ className={cn(
441
+ 'overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',
442
+ className,
443
+ )}
444
+ {...props}
445
+ >
446
+ <div className="pb-1 pt-0">{children}</div>
447
+ </AccordionPrimitive.Content>
448
+ ))
449
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName
450
+
451
+ const TreeIcon = ({
452
+ item,
453
+ isOpen,
454
+ isSelected,
455
+ default: defaultIcon,
456
+ }: {
457
+ item: TreeDataItem
458
+ isOpen?: boolean
459
+ isSelected?: boolean
460
+ default?: any
461
+ }) => {
462
+ let Icon = defaultIcon
463
+ if (isSelected && item.selectedIcon) {
464
+ Icon = item.selectedIcon
465
+ } else if (isOpen && item.openIcon) {
466
+ Icon = item.openIcon
467
+ } else if (item.icon) {
468
+ Icon = item.icon
469
+ }
470
+ return Icon ? <Icon className="h-4 w-4 shrink-0 mr-2" /> : <></>
471
+ }
472
+
473
+ const TreeActions = ({
474
+ children,
475
+ isSelected,
476
+ }: {
477
+ children: React.ReactNode
478
+ isSelected: boolean
479
+ }) => {
480
+ return (
481
+ <div
482
+ className={cn(
483
+ isSelected ? 'block' : 'hidden',
484
+ 'absolute right-3 group-hover:block',
485
+ )}
486
+ >
487
+ {children}
488
+ </div>
489
+ )
490
+ }
491
+
492
+ export { TreeView, type TreeDataItem }
@@ -0,0 +1,5 @@
1
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
2
+
3
+ export default function LayoutAddition() {
4
+ return <ReactQueryDevtools buttonPosition="bottom-right" />
5
+ }
@@ -0,0 +1,15 @@
1
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
2
+
3
+ const queryClient = new QueryClient()
4
+
5
+ export function getContext() {
6
+ return {
7
+ queryClient,
8
+ }
9
+ }
10
+
11
+ export function Provider({ children }: { children: React.ReactNode }) {
12
+ return (
13
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
14
+ )
15
+ }
@@ -0,0 +1,78 @@
1
+ import { createServerFn } from '@tanstack/react-start'
2
+ import { readFileSync } from 'node:fs'
3
+ import { basename, resolve } from 'node:path'
4
+
5
+ import { getAllAddOns, createMemoryEnvironment } from '@tanstack/cta-engine'
6
+ import { createAppOptionsFromPersisted } from '@tanstack/cta-custom-add-on'
7
+
8
+ import { createApp } from '@tanstack/cta-engine'
9
+
10
+ import type { AddOn, Mode, PersistedOptions } from '@tanstack/cta-engine'
11
+
12
+ export const getAddons = createServerFn({
13
+ method: 'GET',
14
+ })
15
+ .validator((data: unknown) => {
16
+ return data as { platform: string; mode: Mode }
17
+ })
18
+ .handler(({ data: { platform, mode } }) => {
19
+ return getAllAddOns(platform, mode)
20
+ })
21
+
22
+ export const getAddonInfo = createServerFn({
23
+ method: 'GET',
24
+ }).handler(async () => {
25
+ const addOnInfo = readFileSync(
26
+ resolve(process.env.PROJECT_PATH, 'add-on.json'),
27
+ )
28
+ return JSON.parse(addOnInfo.toString())
29
+ })
30
+
31
+ export const getOriginalOptions = createServerFn({
32
+ method: 'GET',
33
+ }).handler(async () => {
34
+ const addOnInfo = readFileSync(resolve(process.env.PROJECT_PATH, '.cta.json'))
35
+ return JSON.parse(addOnInfo.toString()) as PersistedOptions
36
+ })
37
+
38
+ export const runCreateApp = createServerFn({
39
+ method: 'POST',
40
+ })
41
+ .validator((data: unknown) => {
42
+ return data as { withAddOn: boolean; options: PersistedOptions }
43
+ })
44
+ .handler(
45
+ async ({
46
+ data: { withAddOn, options: persistedOptions },
47
+ }: {
48
+ data: { withAddOn: boolean; options: PersistedOptions }
49
+ }) => {
50
+ const { output, environment } = createMemoryEnvironment()
51
+ const options = await createAppOptionsFromPersisted(persistedOptions)
52
+ options.chosenAddOns = withAddOn
53
+ ? [...options.chosenAddOns, (await getAddonInfo()) as AddOn]
54
+ : [...options.chosenAddOns]
55
+ await createApp(
56
+ {
57
+ ...options,
58
+ },
59
+ {
60
+ silent: true,
61
+ environment,
62
+ cwd: process.env.PROJECT_PATH,
63
+ },
64
+ )
65
+
66
+ output.files = Object.keys(output.files).reduce<Record<string, string>>(
67
+ (acc, file) => {
68
+ if (basename(file) !== '.cta.json') {
69
+ acc[file] = output.files[file]
70
+ }
71
+ return acc
72
+ },
73
+ {},
74
+ )
75
+
76
+ return output
77
+ },
78
+ )
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
package/src/logo.svg ADDED
@@ -0,0 +1,44 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg id="Layer_1"
3
+ xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 841.9 595.3">
4
+ <!-- Generator: Adobe Illustrator 29.3.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 146) -->
5
+ <defs>
6
+ <style>
7
+ .st0 {
8
+ fill: #9ae7fc;
9
+ }
10
+
11
+ .st1 {
12
+ fill: #61dafb;
13
+ }
14
+ </style>
15
+ </defs>
16
+ <g>
17
+ <path class="st1" d="M666.3,296.5c0-32.5-40.7-63.3-103.1-82.4,14.4-63.6,8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6,0,8.3.9,11.4,2.6,13.6,7.8,19.5,37.5,14.9,75.7-1.1,9.4-2.9,19.3-5.1,29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50,32.6-30.3,63.2-46.9,84-46.9v-22.3c-27.5,0-63.5,19.6-99.9,53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7,0,51.4,16.5,84,46.6-14,14.7-28,31.4-41.3,49.9-22.6,2.4-44,6.1-63.6,11-2.3-10-4-19.7-5.2-29-4.7-38.2,1.1-67.9,14.6-75.8,3-1.8,6.9-2.6,11.5-2.6v-22.3c-8.4,0-16,1.8-22.6,5.6-28.1,16.2-34.4,66.7-19.9,130.1-62.2,19.2-102.7,49.9-102.7,82.3s40.7,63.3,103.1,82.4c-14.4,63.6-8,114.2,20.2,130.4,6.5,3.8,14.1,5.6,22.5,5.6,27.5,0,63.5-19.6,99.9-53.6,36.4,33.8,72.4,53.2,99.9,53.2,8.4,0,16-1.8,22.6-5.6,28.1-16.2,34.4-66.7,19.9-130.1,62-19.1,102.5-49.9,102.5-82.3zm-130.2-66.7c-3.7,12.9-8.3,26.2-13.5,39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4,14.2,2.1,27.9,4.7,41,7.9zm-45.8,106.5c-7.8,13.5-15.8,26.3-24.1,38.2-14.9,1.3-30,2-45.2,2s-30.2-.7-45-1.9c-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8,6.2-13.4,13.2-26.8,20.7-39.9,7.8-13.5,15.8-26.3,24.1-38.2,14.9-1.3,30-2,45.2-2s30.2.7,45,1.9c8.3,11.9,16.4,24.6,24.2,38,7.6,13.1,14.5,26.4,20.8,39.8-6.3,13.4-13.2,26.8-20.7,39.9zm32.3-13c5.4,13.4,10,26.8,13.8,39.8-13.1,3.2-26.9,5.9-41.2,8,4.9-7.7,9.8-15.6,14.4-23.7,4.6-8,8.9-16.1,13-24.1zm-101.4,106.7c-9.3-9.6-18.6-20.3-27.8-32,9,.4,18.2.7,27.5.7s18.7-.2,27.8-.7c-9,11.7-18.3,22.4-27.5,32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9,3.7-12.9,8.3-26.2,13.5-39.5,4.1,8,8.4,16,13.1,24s9.5,15.8,14.4,23.4zm73.9-208.1c9.3,9.6,18.6,20.3,27.8,32-9-.4-18.2-.7-27.5-.7s-18.7.2-27.8.7c9-11.7,18.3-22.4,27.5-32zm-74,58.9c-4.9,7.7-9.8,15.6-14.4,23.7-4.6,8-8.9,16-13,24-5.4-13.4-10-26.8-13.8-39.8,13.1-3.1,26.9-5.8,41.2-7.9zm-90.5,125.2c-35.4-15.1-58.3-34.9-58.3-50.6s22.9-35.6,58.3-50.6c8.6-3.7,18-7,27.7-10.1,5.7,19.6,13.2,40,22.5,60.9-9.2,20.8-16.6,41.1-22.2,60.6-9.9-3.1-19.3-6.5-28-10.2zm53.8,142.9c-13.6-7.8-19.5-37.5-14.9-75.7,1.1-9.4,2.9-19.3,5.1-29.4,19.6,4.8,41,8.5,63.5,10.9,13.5,18.5,27.5,35.3,41.6,50-32.6,30.3-63.2,46.9-84,46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7,38.2-1.1,67.9-14.6,75.8-3,1.8-6.9,2.6-11.5,2.6-20.7,0-51.4-16.5-84-46.6,14-14.7,28-31.4,41.3-49.9,22.6-2.4,44-6.1,63.6-11,2.3,10.1,4.1,19.8,5.2,29.1zm38.5-66.7c-8.6,3.7-18,7-27.7,10.1-5.7-19.6-13.2-40-22.5-60.9,9.2-20.8,16.6-41.1,22.2-60.6,9.9,3.1,19.3,6.5,28.1,10.2,35.4,15.1,58.3,34.9,58.3,50.6,0,15.7-23,35.6-58.4,50.6zm-264.9-268.7z"/>
18
+ <circle class="st1" cx="420.9" cy="296.5" r="45.7"/>
19
+ <path class="st1" d="M520.5,78.1"/>
20
+ </g>
21
+ <circle class="st0" cx="420.8" cy="296.6" r="43"/>
22
+ <path class="st1" d="M466.1,296.6c0,25-20.2,45.2-45.2,45.2s-45.2-20.2-45.2-45.2,20.2-45.2,45.2-45.2,45.2,20.2,45.2,45.2ZM386,295.6v-6.3c0-1.1,1.2-5.1,1.8-6.2,1-1.9,2.9-3.5,4.6-4.7l-3.4-3.4c4-3.6,9.4-3.7,13.7-.7,1.9-4.7,6.6-7.1,11.6-6.7l-.8,4.2c5.9.2,13.1,4.1,13.1,10.8s0,.5-.7.7c-1.7.3-3.4-.4-5-.6s-1.2-.4-1.2.3,2.5,4.1,3,5.5,1,3.5.8,5.3c-5.6-.8-10.5-3.2-14.8-6.7.3,2.6,4.1,21.7,5.3,21.9s.8-.6,1-1.1,1.3-6.3,1.3-6.7c0-1-1.7-1.8-2.2-2.8-1.2-2.7,1.3-4.7,3.7-3.3s5.2,6.2,7.5,7.3,13,1.4,14.8,3.3-2.9,4.6-1.5,7.6c6.7-2.6,13.5-3.3,20.6-2.5,3.1-9.7,3.1-20.3-.9-29.8-7.3,0-14.7-3.6-17.2-10.8-2.5-7.2-.7-8.6-1.3-9.3-.8-1-6.3.6-7.4-1.5s.3-1.1-.2-1.4-1.9-.6-2.6-.8c-26-6.4-51.3,15.7-49.7,42.1,0,1.6,1.6,10.3,2.4,11.1s4.8,0,6.3,0,3.7.3,5,.5c2.9.4,7.2,2.4,9.4,2.5s2.4-.8,2.7-2.4c.4-2.6.5-7.4.5-10.1s-1-7.8-1.3-11.6c-.9-.2-.7,0-.9.5-.7,1.3-1.1,3.2-1.9,4.8s-5.2,8.7-5.7,9-.7-.5-.8-.8c-1.6-3.5-2-7.9-1.9-11.8-.9-1-5.4,4.9-6.7,5.3l-.8-.4v-.3h-.2ZM455.6,276.4c1.1-1.2-6-8.9-7.2-10-3-2.7-5.4-4.5-3.5,1.4s5.7,7.8,10.6,8.5h.1ZM410.9,270.1c-.4-.5-6.1,2.9-5.5,4.6,1.9-1.3,5.9-1.7,5.5-4.6ZM400.4,276.4c-.3-2.4-6.3-2.7-7.2-1s1.6,1.4,1.9,1.4c1.8.3,3.5-.6,5.2-.4h.1ZM411.3,276.8c3.8,1.3,6.6,3.6,10.9,3.7s0-3-1.2-3.9c-2.2-1.7-5.1-2.4-7.8-2.4s-1.6-.3-1.4.4c2.8.6,7.3.7,8.4,3.8-2.3-.3-3.9-1.6-6.2-2s-2.5-.5-2.6.3h0ZM420.6,290.3c-.8-5.1-5.7-10.8-10.9-11.6s-1.3-.4-.8.5,4.7,3.2,5.7,4,4.5,4.2,2.1,3.8-8.4-7.8-9.4-6.7c.2.9,1.1,1.9,1.7,2.7,3,3.8,6.9,6.8,11.8,7.4h-.2ZM395.3,279.8c-5,1.1-6.9,6.3-6.7,11,.7.8,5-3.8,5.4-4.5s2.7-4.6,1.1-4-2.9,4.4-4.2,4.6.2-2.1.4-2.5c1.1-1.6,2.9-3.1,4-4.6h0ZM400.4,281.5c-.4-.5-2,1.3-2.3,1.7-2.9,3.9-2.6,10.2-1.5,14.8.8.2.8-.3,1.2-.7,3-3.8,5.5-10.5,4.5-15.4-2.1,3.1-3.1,7.3-3.6,11h-1.3c0-4,1.9-7.7,3-11.4h0ZM426.9,305.9c0-1.7-1.7-1.4-2.5-1.9s-1.3-1.9-3-1.4c1.3,2.1,3,3.2,5.5,3.4h0ZM417.2,308.5c7.6.7,5.5-1.9,1.4-5.5-1.3-.3-1.5,4.5-1.4,5.5ZM437,309.7c-3.5-.3-7.8-2-11.2-2.1s-1.3,0-1.9.7c4,1.3,8.4,1.7,12.1,4l1-2.5h0ZM420.5,312.8c-7.3,0-15.1,3.7-20.4,8.8s-4.8,5.3-4.8,6.2c0,1.8,8.6,6.2,10.5,6.8,12.1,4.8,27.5,3.5,38.2-4.2s3.1-2.7,0-6.2c-5.7-6.6-14.7-11.4-23.4-11.3h-.1ZM398.7,316.9c-1.4-1.4-5-1.9-7-2.1s-5.3-.3-6.9.6l13.9,1.4h0ZM456.9,314.8h-7.4c-.9,0-4.9,1.1-6,1.6s-.8.6,0,.5c2.4,0,5.1-1,7.6-1.3s3.5.2,5.1,0,1.3-.3.6-.8h0Z"/>
23
+ <path class="st0" d="M386,295.6l.8.4c1.3-.3,5.8-6.2,6.7-5.3,0,3.9.3,8.3,1.9,11.8s0,1.2.8.8,5.1-7.8,5.7-9,1.3-3.5,1.9-4.8,0-.7.9-.5c.3,3.8,1.2,7.8,1.3,11.6s0,7.5-.5,10.1-1.1,2.4-2.7,2.4-6.5-2.1-9.4-2.5-3.7-.5-5-.5-5.4,1.1-6.3,0-2.2-9.5-2.4-11.1c-1.5-26.4,23.7-48.5,49.7-42.1s2.2.4,2.6.8,0,1,.2,1.4c1.1,2,6.5.5,7.4,1.5s.4,6.9,1.3,9.3c2.5,7.2,10,10.9,17.2,10.8,4,9.4,4,20.1.9,29.8-7.2-.7-13.9,0-20.6,2.5-1.3-3.1,4.1-5.1,1.5-7.6s-11.8-1.9-14.8-3.3-5.4-6.1-7.5-7.3-4.9.6-3.7,3.3,2.1,1.8,2.2,2.8-1,6.2-1.3,6.7-.3,1.3-1,1.1c-1.1-.3-5-19.3-5.3-21.9,4.3,3.5,9.2,5.9,14.8,6.7.2-1.9-.3-3.5-.8-5.3s-3-5.1-3-5.5c0-.8.9-.3,1.2-.3,1.6,0,3.3.8,5,.6s.7.3.7-.7c0-6.6-7.2-10.6-13.1-10.8l.8-4.2c-5.1-.3-9.6,2-11.6,6.7-4.3-3-9.8-3-13.7.7l3.4,3.4c-1.8,1.3-3.5,2.8-4.6,4.7s-1.8,5.1-1.8,6.2v6.6h.2ZM431.6,265c7.8,2.1,8.7-3.5.2-1.3l-.2,1.3ZM432.4,270.9c.3.6,6.4-.4,5.8-2.3s-4.6.6-5.7.6l-.2,1.7h.1ZM434.5,276c.8,1.2,5.7-1.8,5.5-2.7-.4-1.9-6.6,1.2-5.5,2.7ZM442.9,276.4c-.9-.9-5,2.8-4.6,4,.6,2.4,5.7-3,4.6-4ZM445.1,279.9c-.3.2-3.1,4.6-1.5,5s3.5-3.4,3.5-4-1.3-1.3-2-.9h0ZM448.9,287.4c2.1.8,3.8-5.1,2.3-5.5-1.9-.6-2.6,5.1-2.3,5.5ZM457.3,288.6c.5-1.7,1.1-4.7-1-5.5-1,.3-.6,3.9-.6,4.8l.3.5,1.3.2h0Z"/>
24
+ <path class="st0" d="M455.6,276.4c-5-.8-9.1-3.6-10.6-8.5s.5-4,3.5-1.4,8.3,8.7,7.2,10h-.1Z"/>
25
+ <path class="st0" d="M420.6,290.3c-4.9-.6-8.9-3.6-11.8-7.4s-1.5-1.8-1.7-2.7c1-1,8.5,6.6,9.4,6.7,2.4.4-1.8-3.5-2.1-3.8-1-.8-5.4-3.5-5.7-4-.4-.8.5-.5.8-.5,5.2.8,10.1,6.6,10.9,11.6h.2Z"/>
26
+ <path class="st0" d="M400.4,281.5c-1.1,3.7-3,7.3-3,11.4h1.3c.5-3.7,1.5-7.8,3.6-11,1,4.8-1.5,11.6-4.5,15.4s-.4.8-1.2.7c-1.1-4.5-1.3-10.8,1.5-14.8s1.9-2.2,2.3-1.7h0Z"/>
27
+ <path class="st0" d="M411.3,276.8c0-.8,2.1-.4,2.6-.3,2.4.4,4,1.7,6.2,2-1.2-3.1-5.7-3.2-8.4-3.8,0-.8.9-.4,1.4-.4,2.8,0,5.6.7,7.8,2.4,2.2,1.7,4,4,1.2,3.9-4.3,0-7.1-2.4-10.9-3.7h0Z"/>
28
+ <path class="st0" d="M395.3,279.8c-1.1,1.6-3,3-4,4.6s-1.9,2.8-.4,2.5,2.8-4,4.2-4.6-.9,3.6-1.1,4c-.4.7-4.7,5.2-5.4,4.5-.2-4.6,1.8-9.9,6.7-11h0Z"/>
29
+ <path class="st0" d="M437,309.7l-1,2.5c-3.6-2.3-8-2.8-12.1-4,.5-.7,1.1-.7,1.9-.7,3.4,0,7.8,1.8,11.2,2.1h0Z"/>
30
+ <path class="st0" d="M417.2,308.5c0-1,0-5.8,1.4-5.5,4,3.5,6.1,6.2-1.4,5.5Z"/>
31
+ <path class="st0" d="M400.4,276.4c-1.8-.3-3.5.7-5.2.4s-2.3-.8-1.9-1.4c.8-1.6,6.9-1.4,7.2,1h-.1Z"/>
32
+ <path class="st0" d="M410.9,270.1c.4,3-3.6,3.3-5.5,4.6-.6-1.8,5-5.1,5.5-4.6Z"/>
33
+ <path class="st0" d="M426.9,305.9c-2.5-.2-4.1-1.3-5.5-3.4,1.7-.4,2,.8,3,1.4s2.6.3,2.5,1.9h0Z"/>
34
+ <path class="st1" d="M432.4,270.9l.2-1.7c1.1,0,5.1-2.2,5.7-.6s-5.5,2.9-5.8,2.3h-.1Z"/>
35
+ <path class="st1" d="M431.6,265l.2-1.3c8.4-2.1,7.7,3.4-.2,1.3Z"/>
36
+ <path class="st1" d="M434.5,276c-1.1-1.5,5.1-4.6,5.5-2.7s-4.6,4-5.5,2.7Z"/>
37
+ <path class="st1" d="M442.9,276.4c1.1,1.1-4,6.4-4.6,4s3.7-4.9,4.6-4Z"/>
38
+ <path class="st1" d="M445.1,279.9c.7-.4,2.1,0,2,.9s-2.4,4.4-3.5,4,1.3-4.8,1.5-5h0Z"/>
39
+ <path class="st1" d="M448.9,287.4c-.3-.3.4-6.1,2.3-5.5,1.4.4-.2,6.2-2.3,5.5Z"/>
40
+ <path class="st1" d="M457.3,288.6l-1.3-.2-.3-.5c0-.9-.4-4.6.6-4.8,2.1.8,1.5,3.8,1,5.5h0Z"/>
41
+ <path class="st0" d="M420.5,312.8c8.9,0,17.9,4.7,23.4,11.3,5.6,6.6,3.8,3.5,0,6.2-10.7,7.7-26.1,9-38.2,4.2-1.9-.8-10.5-5.1-10.5-6.8s4-5.3,4.8-6.2c5.3-5,13.1-8.6,20.4-8.8h.1Z"/>
42
+ <path class="st0" d="M398.7,316.9l-13.9-1.4c1.7-1,5-.8,6.9-.6s5.6.7,7,2.1h0Z"/>
43
+ <path class="st0" d="M456.9,314.8c.7.5,0,.8-.6.8-1.6.2-3.5-.2-5.1,0-2.4.3-5.2,1.2-7.6,1.3s-1.1,0,0-.5,5.1-1.6,6-1.6h7.4,0Z"/>
44
+ </svg>