@proulr/sdui-components 0.1.0 → 0.1.2

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.
@@ -0,0 +1,1217 @@
1
+ import { StyleSheet, View } from 'react-native';
2
+ import { m3Colors } from '../theme/proulr-theme';
3
+
4
+ export type AppChromeGlyphProps = {
5
+ color?: string;
6
+ size?: number;
7
+ };
8
+
9
+ function strokeFor(size: number) {
10
+ return Math.max(1.8, size * 0.075);
11
+ }
12
+
13
+ export function AppChromeSearchGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
14
+ const stroke = strokeFor(size);
15
+ const lens = size * 0.48;
16
+ return (
17
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
18
+ <View
19
+ style={{
20
+ width: lens,
21
+ height: lens,
22
+ borderRadius: lens / 2,
23
+ borderWidth: stroke,
24
+ borderColor: color,
25
+ }}
26
+ />
27
+ <View
28
+ style={{
29
+ position: 'absolute',
30
+ width: size * 0.26,
31
+ height: stroke,
32
+ borderRadius: 1,
33
+ backgroundColor: color,
34
+ transform: [{ rotate: '45deg' }],
35
+ bottom: size * 0.14,
36
+ right: size * 0.12,
37
+ }}
38
+ />
39
+ </View>
40
+ );
41
+ }
42
+
43
+ export function AppChromeHuntGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
44
+ const stroke = strokeFor(size);
45
+ const ring = size * 0.82;
46
+ return (
47
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
48
+ <View
49
+ style={{
50
+ width: ring,
51
+ height: ring,
52
+ borderRadius: ring / 2,
53
+ borderWidth: stroke,
54
+ borderColor: color,
55
+ alignItems: 'center',
56
+ justifyContent: 'center',
57
+ }}
58
+ >
59
+ <View
60
+ style={{
61
+ width: ring * 0.3,
62
+ height: ring * 0.3,
63
+ borderRadius: ring * 0.15,
64
+ backgroundColor: color,
65
+ }}
66
+ />
67
+ </View>
68
+ <View style={[styles.crosshair, { width: size * 0.92, height: stroke, backgroundColor: color }]} />
69
+ <View style={[styles.crosshair, { width: stroke, height: size * 0.92, backgroundColor: color }]} />
70
+ </View>
71
+ );
72
+ }
73
+
74
+ export function AppChromeBackGlyph({ color = m3Colors.onSurface, size = 24 }: AppChromeGlyphProps) {
75
+ const stroke = strokeFor(size) + 0.2;
76
+ return (
77
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
78
+ <View
79
+ style={{
80
+ width: size * 0.36,
81
+ height: size * 0.36,
82
+ borderLeftWidth: stroke,
83
+ borderBottomWidth: stroke,
84
+ borderColor: color,
85
+ transform: [{ rotate: '45deg' }],
86
+ marginLeft: size * 0.1,
87
+ }}
88
+ />
89
+ </View>
90
+ );
91
+ }
92
+
93
+ export function AppChromeOverflowGlyph({ color = m3Colors.onSurface, size = 24 }: AppChromeGlyphProps) {
94
+ const dot = size * 0.13;
95
+ return (
96
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center', gap: dot * 0.75 }}>
97
+ <View style={{ width: dot, height: dot, borderRadius: dot / 2, backgroundColor: color }} />
98
+ <View style={{ width: dot, height: dot, borderRadius: dot / 2, backgroundColor: color }} />
99
+ <View style={{ width: dot, height: dot, borderRadius: dot / 2, backgroundColor: color }} />
100
+ </View>
101
+ );
102
+ }
103
+
104
+ export function AppChromeLocationGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
105
+ const stroke = strokeFor(size);
106
+ const head = size * 0.42;
107
+ return (
108
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
109
+ <View
110
+ style={{
111
+ width: head,
112
+ height: head,
113
+ borderRadius: head / 2,
114
+ borderWidth: stroke,
115
+ borderColor: color,
116
+ alignItems: 'center',
117
+ justifyContent: 'center',
118
+ position: 'absolute',
119
+ top: size * 0.06,
120
+ }}
121
+ >
122
+ <View
123
+ style={{
124
+ width: head * 0.34,
125
+ height: head * 0.34,
126
+ borderRadius: head * 0.17,
127
+ backgroundColor: color,
128
+ }}
129
+ />
130
+ </View>
131
+ <View
132
+ style={{
133
+ position: 'absolute',
134
+ bottom: size * 0.04,
135
+ width: 0,
136
+ height: 0,
137
+ borderLeftWidth: head * 0.52,
138
+ borderRightWidth: head * 0.52,
139
+ borderTopWidth: size * 0.3,
140
+ borderLeftColor: 'transparent',
141
+ borderRightColor: 'transparent',
142
+ borderTopColor: color,
143
+ }}
144
+ />
145
+ </View>
146
+ );
147
+ }
148
+
149
+ export function AppChromeMicGlyph({ color = m3Colors.onPrimary, size = 24 }: AppChromeGlyphProps) {
150
+ const stroke = strokeFor(size);
151
+ const capsuleW = size * 0.38;
152
+ const capsuleH = size * 0.56;
153
+ return (
154
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
155
+ <View
156
+ style={{
157
+ width: capsuleW,
158
+ height: capsuleH,
159
+ borderRadius: capsuleW / 2,
160
+ borderWidth: stroke,
161
+ borderColor: color,
162
+ }}
163
+ />
164
+ <View style={{ width: size * 0.48, height: stroke, backgroundColor: color, marginTop: 2 }} />
165
+ <View style={{ width: stroke, height: size * 0.16, backgroundColor: color }} />
166
+ </View>
167
+ );
168
+ }
169
+
170
+ export function AppChromeSendGlyph({ color = m3Colors.onPrimary, size = 24 }: AppChromeGlyphProps) {
171
+ return (
172
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
173
+ <View
174
+ style={{
175
+ width: 0,
176
+ height: 0,
177
+ borderTopWidth: size * 0.24,
178
+ borderBottomWidth: size * 0.24,
179
+ borderLeftWidth: size * 0.38,
180
+ borderTopColor: 'transparent',
181
+ borderBottomColor: 'transparent',
182
+ borderLeftColor: color,
183
+ marginLeft: size * 0.1,
184
+ }}
185
+ />
186
+ </View>
187
+ );
188
+ }
189
+
190
+ export function AppChromeChatGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
191
+ const stroke = strokeFor(size);
192
+ const bubbleW = size * 0.86;
193
+ const bubbleH = size * 0.62;
194
+ return (
195
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
196
+ <View
197
+ style={{
198
+ width: bubbleW,
199
+ height: bubbleH,
200
+ borderRadius: size * 0.16,
201
+ borderWidth: stroke,
202
+ borderColor: color,
203
+ }}
204
+ />
205
+ <View
206
+ style={{
207
+ position: 'absolute',
208
+ bottom: size * 0.1,
209
+ left: size * 0.18,
210
+ width: size * 0.16,
211
+ height: size * 0.16,
212
+ borderBottomWidth: stroke,
213
+ borderLeftWidth: stroke,
214
+ borderColor: color,
215
+ transform: [{ rotate: '-45deg' }],
216
+ }}
217
+ />
218
+ </View>
219
+ );
220
+ }
221
+
222
+ export function AppChromeCloseGlyph({ color = m3Colors.onSurface, size = 20 }: AppChromeGlyphProps) {
223
+ const stroke = strokeFor(size);
224
+ const bar = size * 0.68;
225
+ return (
226
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
227
+ <View style={[styles.diag, { width: bar, height: stroke, backgroundColor: color, transform: [{ rotate: '45deg' }] }]} />
228
+ <View style={[styles.diag, { width: bar, height: stroke, backgroundColor: color, transform: [{ rotate: '-45deg' }] }]} />
229
+ </View>
230
+ );
231
+ }
232
+
233
+ export function AppChromeChevronDownGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
234
+ const stroke = strokeFor(size);
235
+ return (
236
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
237
+ <View
238
+ style={{
239
+ width: size * 0.36,
240
+ height: size * 0.36,
241
+ borderRightWidth: stroke,
242
+ borderBottomWidth: stroke,
243
+ borderColor: color,
244
+ transform: [{ rotate: '45deg' }],
245
+ marginTop: -size * 0.06,
246
+ }}
247
+ />
248
+ </View>
249
+ );
250
+ }
251
+
252
+ export function AppChromeChevronRightGlyph({ color = m3Colors.onSurfaceVariant, size = 20 }: AppChromeGlyphProps) {
253
+ const stroke = strokeFor(size);
254
+ return (
255
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
256
+ <View
257
+ style={{
258
+ width: size * 0.36,
259
+ height: size * 0.36,
260
+ borderRightWidth: stroke,
261
+ borderBottomWidth: stroke,
262
+ borderColor: color,
263
+ transform: [{ rotate: '-45deg' }],
264
+ marginLeft: -size * 0.06,
265
+ }}
266
+ />
267
+ </View>
268
+ );
269
+ }
270
+
271
+ export function AppChromeFlipCameraGlyph({ color = m3Colors.onPrimary, size = 24 }: AppChromeGlyphProps) {
272
+ const stroke = strokeFor(size);
273
+ const ring = size * 0.78;
274
+ return (
275
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
276
+ <View
277
+ style={{
278
+ width: ring,
279
+ height: ring,
280
+ borderRadius: ring / 2,
281
+ borderWidth: stroke,
282
+ borderColor: color,
283
+ borderTopColor: 'transparent',
284
+ transform: [{ rotate: '45deg' }],
285
+ }}
286
+ />
287
+ <View
288
+ style={{
289
+ position: 'absolute',
290
+ top: size * 0.1,
291
+ right: size * 0.12,
292
+ width: 0,
293
+ height: 0,
294
+ borderTopWidth: size * 0.11,
295
+ borderBottomWidth: size * 0.11,
296
+ borderLeftWidth: size * 0.13,
297
+ borderTopColor: 'transparent',
298
+ borderBottomColor: 'transparent',
299
+ borderLeftColor: color,
300
+ transform: [{ rotate: '-30deg' }],
301
+ }}
302
+ />
303
+ </View>
304
+ );
305
+ }
306
+
307
+ /** Flash — estalo / sinal de interesse (centro + 4 raios longos + 4 curtos). */
308
+ export function AppChromeFlashGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
309
+ const core = size * 0.22;
310
+ const mainRayW = Math.max(2.6, size * 0.12);
311
+ const mainRayLen = size * 0.42;
312
+ const diagRayW = Math.max(2, size * 0.09);
313
+ const diagRayLen = size * 0.28;
314
+ const mainAngles = [0, 90, 180, 270];
315
+ const diagAngles = [45, 135, 225, 315];
316
+
317
+ const rayStyle = (rayW: number, rayLen: number, angle: number) => ({
318
+ position: 'absolute' as const,
319
+ width: rayW,
320
+ height: rayLen,
321
+ borderRadius: rayW / 2,
322
+ backgroundColor: color,
323
+ left: size / 2 - rayW / 2,
324
+ top: size / 2 - rayLen / 2,
325
+ transform: [{ rotate: `${angle}deg` }, { translateY: -size * 0.28 }],
326
+ });
327
+
328
+ return (
329
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
330
+ {mainAngles.map((angle) => (
331
+ <View key={`m-${angle}`} style={rayStyle(mainRayW, mainRayLen, angle)} />
332
+ ))}
333
+ {diagAngles.map((angle) => (
334
+ <View key={`d-${angle}`} style={rayStyle(diagRayW, diagRayLen, angle)} />
335
+ ))}
336
+ <View
337
+ style={{
338
+ width: core,
339
+ height: core,
340
+ borderRadius: core / 2,
341
+ backgroundColor: color,
342
+ }}
343
+ />
344
+ </View>
345
+ );
346
+ }
347
+
348
+ export function AppChromeTabDiscoverGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
349
+ return <AppChromeHuntGlyph color={color} size={size} />;
350
+ }
351
+
352
+ /** Vibes — play em círculo (feed de vídeo / mídia). */
353
+ export function AppChromeTabVibesGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
354
+ const stroke = strokeFor(size);
355
+ const ring = size * 0.84;
356
+ return (
357
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
358
+ <View
359
+ style={{
360
+ width: ring,
361
+ height: ring,
362
+ borderRadius: ring / 2,
363
+ borderWidth: stroke,
364
+ borderColor: color,
365
+ alignItems: 'center',
366
+ justifyContent: 'center',
367
+ }}
368
+ >
369
+ <View
370
+ style={{
371
+ width: 0,
372
+ height: 0,
373
+ borderTopWidth: size * 0.14,
374
+ borderBottomWidth: size * 0.14,
375
+ borderLeftWidth: size * 0.22,
376
+ borderTopColor: 'transparent',
377
+ borderBottomColor: 'transparent',
378
+ borderLeftColor: color,
379
+ marginLeft: size * 0.05,
380
+ }}
381
+ />
382
+ </View>
383
+ </View>
384
+ );
385
+ }
386
+
387
+ export function AppChromeTabFlashGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
388
+ return <AppChromeFlashGlyph color={color} size={size} />;
389
+ }
390
+
391
+ export function AppChromeTabChatGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
392
+ return <AppChromeChatGlyph color={color} size={size} />;
393
+ }
394
+
395
+ /** Configurações — sliders horizontais (não confundir com alvo de caçar). */
396
+ export function AppChromeSettingsGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
397
+ const stroke = strokeFor(size);
398
+ const trackW = size * 0.72;
399
+ const knob = size * 0.14;
400
+ const rows = [
401
+ { top: size * 0.22, knobLeft: size * 0.14 },
402
+ { top: size * 0.44, knobLeft: size * 0.42 },
403
+ { top: size * 0.66, knobLeft: size * 0.24 },
404
+ ];
405
+ return (
406
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
407
+ {rows.map((row) => (
408
+ <View
409
+ key={row.top}
410
+ style={{
411
+ position: 'absolute',
412
+ top: row.top,
413
+ width: trackW,
414
+ height: stroke,
415
+ backgroundColor: color,
416
+ borderRadius: 1,
417
+ opacity: 0.45,
418
+ }}
419
+ />
420
+ ))}
421
+ {rows.map((row) => (
422
+ <View
423
+ key={`knob-${row.top}`}
424
+ style={{
425
+ position: 'absolute',
426
+ top: row.top - knob / 2 + stroke / 2,
427
+ left: row.knobLeft,
428
+ width: knob,
429
+ height: knob,
430
+ borderRadius: knob / 2,
431
+ borderWidth: stroke,
432
+ borderColor: color,
433
+ backgroundColor: color,
434
+ }}
435
+ />
436
+ ))}
437
+ </View>
438
+ );
439
+ }
440
+
441
+ export function AppChromeBoostGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
442
+ const stroke = strokeFor(size);
443
+ const bodyW = size * 0.34;
444
+ const bodyH = size * 0.46;
445
+ return (
446
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
447
+ <View
448
+ style={{
449
+ position: 'absolute',
450
+ top: size * 0.1,
451
+ width: 0,
452
+ height: 0,
453
+ borderLeftWidth: size * 0.12,
454
+ borderRightWidth: size * 0.12,
455
+ borderBottomWidth: size * 0.18,
456
+ borderLeftColor: 'transparent',
457
+ borderRightColor: 'transparent',
458
+ borderBottomColor: color,
459
+ }}
460
+ />
461
+ <View
462
+ style={{
463
+ position: 'absolute',
464
+ top: size * 0.26,
465
+ width: bodyW,
466
+ height: bodyH,
467
+ borderRadius: size * 0.06,
468
+ borderWidth: stroke,
469
+ borderColor: color,
470
+ alignItems: 'center',
471
+ justifyContent: 'center',
472
+ }}
473
+ >
474
+ <View
475
+ style={{
476
+ width: bodyW * 0.38,
477
+ height: bodyW * 0.38,
478
+ borderRadius: bodyW * 0.19,
479
+ borderWidth: stroke * 0.8,
480
+ borderColor: color,
481
+ }}
482
+ />
483
+ </View>
484
+ <View
485
+ style={{
486
+ position: 'absolute',
487
+ bottom: size * 0.14,
488
+ left: size * 0.28,
489
+ width: size * 0.16,
490
+ height: size * 0.12,
491
+ borderBottomWidth: stroke,
492
+ borderLeftWidth: stroke,
493
+ borderColor: color,
494
+ transform: [{ rotate: '-35deg' }],
495
+ }}
496
+ />
497
+ <View
498
+ style={{
499
+ position: 'absolute',
500
+ bottom: size * 0.14,
501
+ right: size * 0.28,
502
+ width: size * 0.16,
503
+ height: size * 0.12,
504
+ borderBottomWidth: stroke,
505
+ borderRightWidth: stroke,
506
+ borderColor: color,
507
+ transform: [{ rotate: '35deg' }],
508
+ }}
509
+ />
510
+ </View>
511
+ );
512
+ }
513
+
514
+ export function AppChromeFireGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
515
+ const stroke = strokeFor(size);
516
+ const w = size * 0.5;
517
+ const h = size * 0.7;
518
+ return (
519
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
520
+ <View
521
+ style={{
522
+ width: w,
523
+ height: h,
524
+ borderTopLeftRadius: w * 0.55,
525
+ borderTopRightRadius: w * 0.55,
526
+ borderBottomLeftRadius: w * 0.22,
527
+ borderBottomRightRadius: w * 0.22,
528
+ borderWidth: stroke,
529
+ borderColor: color,
530
+ }}
531
+ />
532
+ <View
533
+ style={{
534
+ position: 'absolute',
535
+ bottom: size * 0.18,
536
+ width: w * 0.34,
537
+ height: h * 0.46,
538
+ borderTopLeftRadius: w * 0.22,
539
+ borderTopRightRadius: w * 0.22,
540
+ borderBottomLeftRadius: w * 0.12,
541
+ borderBottomRightRadius: w * 0.12,
542
+ backgroundColor: color,
543
+ }}
544
+ />
545
+ </View>
546
+ );
547
+ }
548
+
549
+ /** Editar perfil — só lápis (corpo + ponta). */
550
+ export function AppChromeEditGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
551
+ const bodyW = Math.max(3, size * 0.17);
552
+ const bodyH = size * 0.64;
553
+ return (
554
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
555
+ <View
556
+ style={{
557
+ width: bodyW,
558
+ height: bodyH,
559
+ borderRadius: bodyW / 2,
560
+ backgroundColor: color,
561
+ transform: [{ rotate: '-45deg' }],
562
+ }}
563
+ />
564
+ <View
565
+ style={{
566
+ position: 'absolute',
567
+ bottom: size * 0.17,
568
+ left: size * 0.17,
569
+ width: 0,
570
+ height: 0,
571
+ borderLeftWidth: bodyW * 0.95,
572
+ borderRightWidth: bodyW * 0.95,
573
+ borderTopWidth: size * 0.13,
574
+ borderLeftColor: 'transparent',
575
+ borderRightColor: 'transparent',
576
+ borderTopColor: color,
577
+ transform: [{ rotate: '-45deg' }],
578
+ }}
579
+ />
580
+ </View>
581
+ );
582
+ }
583
+
584
+ /** Story — anel com ponto central (criar story). */
585
+ export function AppChromeStoryGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
586
+ const stroke = strokeFor(size);
587
+ const ring = size * 0.82;
588
+ return (
589
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
590
+ <View
591
+ style={{
592
+ width: ring,
593
+ height: ring,
594
+ borderRadius: ring / 2,
595
+ borderWidth: stroke,
596
+ borderColor: color,
597
+ alignItems: 'center',
598
+ justifyContent: 'center',
599
+ }}
600
+ >
601
+ <View
602
+ style={{
603
+ width: ring * 0.34,
604
+ height: ring * 0.34,
605
+ borderRadius: ring * 0.17,
606
+ backgroundColor: color,
607
+ }}
608
+ />
609
+ </View>
610
+ </View>
611
+ );
612
+ }
613
+
614
+ export function AppChromeStoryMusicGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
615
+ const stroke = strokeFor(size);
616
+ const head = size * 0.18;
617
+ return (
618
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
619
+ <View
620
+ style={{
621
+ position: 'absolute',
622
+ left: size * 0.22,
623
+ bottom: size * 0.18,
624
+ width: head,
625
+ height: head,
626
+ borderRadius: head / 2,
627
+ borderWidth: stroke,
628
+ borderColor: color,
629
+ }}
630
+ />
631
+ <View
632
+ style={{
633
+ position: 'absolute',
634
+ left: size * 0.3,
635
+ bottom: size * 0.34,
636
+ width: stroke,
637
+ height: size * 0.42,
638
+ backgroundColor: color,
639
+ }}
640
+ />
641
+ <View
642
+ style={{
643
+ position: 'absolute',
644
+ top: size * 0.16,
645
+ right: size * 0.24,
646
+ width: size * 0.28,
647
+ height: stroke,
648
+ backgroundColor: color,
649
+ transform: [{ rotate: '32deg' }],
650
+ }}
651
+ />
652
+ </View>
653
+ );
654
+ }
655
+
656
+ export function AppChromeStoryStickerGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
657
+ const stroke = strokeFor(size);
658
+ const frame = size * 0.78;
659
+ return (
660
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
661
+ <View
662
+ style={{
663
+ width: frame,
664
+ height: frame,
665
+ borderRadius: size * 0.14,
666
+ borderWidth: stroke,
667
+ borderColor: color,
668
+ alignItems: 'center',
669
+ justifyContent: 'center',
670
+ }}
671
+ >
672
+ <View
673
+ style={{
674
+ flexDirection: 'row',
675
+ gap: frame * 0.14,
676
+ marginBottom: frame * 0.08,
677
+ }}
678
+ >
679
+ <View style={{ width: frame * 0.1, height: frame * 0.1, borderRadius: frame * 0.05, backgroundColor: color }} />
680
+ <View style={{ width: frame * 0.1, height: frame * 0.1, borderRadius: frame * 0.05, backgroundColor: color }} />
681
+ </View>
682
+ <View
683
+ style={{
684
+ width: frame * 0.34,
685
+ height: frame * 0.16,
686
+ borderBottomLeftRadius: frame * 0.17,
687
+ borderBottomRightRadius: frame * 0.17,
688
+ borderWidth: stroke,
689
+ borderTopWidth: 0,
690
+ borderColor: color,
691
+ }}
692
+ />
693
+ </View>
694
+ </View>
695
+ );
696
+ }
697
+
698
+ export function AppChromeStoryTextGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
699
+ const stroke = strokeFor(size);
700
+ const frame = size * 0.78;
701
+ return (
702
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
703
+ <View
704
+ style={{
705
+ width: frame,
706
+ height: frame * 0.72,
707
+ borderRadius: size * 0.1,
708
+ borderWidth: stroke,
709
+ borderColor: color,
710
+ alignItems: 'center',
711
+ justifyContent: 'center',
712
+ }}
713
+ >
714
+ <View style={{ flexDirection: 'row', alignItems: 'flex-end', gap: 1 }}>
715
+ <View style={{ width: stroke * 1.1, height: size * 0.28, backgroundColor: color, borderRadius: 1 }} />
716
+ <View style={{ width: size * 0.2, height: size * 0.2, borderRadius: size * 0.1, borderWidth: stroke, borderColor: color }} />
717
+ </View>
718
+ </View>
719
+ </View>
720
+ );
721
+ }
722
+
723
+ export function AppChromeStoryEffectsGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
724
+ return <AppChromeFlashGlyph color={color} size={size} />;
725
+ }
726
+
727
+ export function AppChromeStoryMentionGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
728
+ const stroke = strokeFor(size);
729
+ const ring = size * 0.78;
730
+ return (
731
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
732
+ <View
733
+ style={{
734
+ width: ring,
735
+ height: ring,
736
+ borderRadius: ring / 2,
737
+ borderWidth: stroke,
738
+ borderColor: color,
739
+ alignItems: 'center',
740
+ justifyContent: 'center',
741
+ }}
742
+ >
743
+ <View
744
+ style={{
745
+ width: stroke * 1.2,
746
+ height: size * 0.34,
747
+ backgroundColor: color,
748
+ borderRadius: 1,
749
+ }}
750
+ />
751
+ <View
752
+ style={{
753
+ position: 'absolute',
754
+ bottom: size * 0.22,
755
+ width: size * 0.14,
756
+ height: size * 0.14,
757
+ borderRadius: size * 0.07,
758
+ borderWidth: stroke,
759
+ borderColor: color,
760
+ }}
761
+ />
762
+ </View>
763
+ </View>
764
+ );
765
+ }
766
+
767
+ export function AppChromeRepostGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
768
+ const stroke = strokeFor(size);
769
+ const shaft = size * 0.36;
770
+ const head = size * 0.1;
771
+ const rowH = stroke;
772
+
773
+ return (
774
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
775
+ {/* seta superior → */}
776
+ <View
777
+ style={{
778
+ position: 'absolute',
779
+ top: size * 0.28,
780
+ left: size * 0.2,
781
+ width: shaft,
782
+ height: rowH,
783
+ backgroundColor: color,
784
+ borderRadius: 1,
785
+ }}
786
+ />
787
+ <View
788
+ style={{
789
+ position: 'absolute',
790
+ top: size * 0.28 + rowH / 2 - head,
791
+ left: size * 0.2 + shaft - head * 0.15,
792
+ width: 0,
793
+ height: 0,
794
+ borderTopWidth: head,
795
+ borderBottomWidth: head,
796
+ borderLeftWidth: head * 1.15,
797
+ borderTopColor: 'transparent',
798
+ borderBottomColor: 'transparent',
799
+ borderLeftColor: color,
800
+ }}
801
+ />
802
+ {/* seta inferior ← */}
803
+ <View
804
+ style={{
805
+ position: 'absolute',
806
+ top: size * 0.56,
807
+ left: size * 0.28,
808
+ width: shaft,
809
+ height: rowH,
810
+ backgroundColor: color,
811
+ borderRadius: 1,
812
+ }}
813
+ />
814
+ <View
815
+ style={{
816
+ position: 'absolute',
817
+ top: size * 0.56 + rowH / 2 - head,
818
+ left: size * 0.22,
819
+ width: 0,
820
+ height: 0,
821
+ borderTopWidth: head,
822
+ borderBottomWidth: head,
823
+ borderRightWidth: head * 1.15,
824
+ borderTopColor: 'transparent',
825
+ borderBottomColor: 'transparent',
826
+ borderRightColor: color,
827
+ }}
828
+ />
829
+ </View>
830
+ );
831
+ }
832
+
833
+ type HeartGlyphProps = AppChromeGlyphProps & { filled?: boolean };
834
+
835
+ function AppChromeHeartShape({ color = m3Colors.primary, size = 24, filled = false }: HeartGlyphProps) {
836
+ const stroke = strokeFor(size);
837
+ const unit = size * 0.26;
838
+ const fill = filled ? color : 'transparent';
839
+ const borderW = filled ? 0 : stroke;
840
+
841
+ return (
842
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
843
+ <View
844
+ style={{
845
+ width: unit * 1.65,
846
+ height: unit * 1.65,
847
+ transform: [{ rotate: '-45deg' }],
848
+ marginTop: unit * 0.18,
849
+ }}
850
+ >
851
+ <View
852
+ style={{
853
+ position: 'absolute',
854
+ width: unit,
855
+ height: unit * 1.62,
856
+ borderRadius: unit,
857
+ backgroundColor: fill,
858
+ borderWidth: borderW,
859
+ borderColor: color,
860
+ top: 0,
861
+ left: unit * 0.32,
862
+ }}
863
+ />
864
+ <View
865
+ style={{
866
+ position: 'absolute',
867
+ width: unit * 1.62,
868
+ height: unit,
869
+ borderRadius: unit,
870
+ backgroundColor: fill,
871
+ borderWidth: borderW,
872
+ borderColor: color,
873
+ top: unit * 0.32,
874
+ left: 0,
875
+ }}
876
+ />
877
+ </View>
878
+ </View>
879
+ );
880
+ }
881
+
882
+ export function AppChromePlayGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
883
+ return (
884
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
885
+ <View
886
+ style={{
887
+ width: 0,
888
+ height: 0,
889
+ borderTopWidth: size * 0.2,
890
+ borderBottomWidth: size * 0.2,
891
+ borderLeftWidth: size * 0.32,
892
+ borderTopColor: 'transparent',
893
+ borderBottomColor: 'transparent',
894
+ borderLeftColor: color,
895
+ marginLeft: size * 0.07,
896
+ }}
897
+ />
898
+ </View>
899
+ );
900
+ }
901
+
902
+ export function AppChromePauseGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
903
+ const barW = Math.max(2.4, size * 0.14);
904
+ const barH = size * 0.4;
905
+ const gap = size * 0.1;
906
+ return (
907
+ <View
908
+ style={{
909
+ width: size,
910
+ height: size,
911
+ flexDirection: 'row',
912
+ alignItems: 'center',
913
+ justifyContent: 'center',
914
+ gap,
915
+ }}
916
+ >
917
+ <View style={{ width: barW, height: barH, borderRadius: 2, backgroundColor: color }} />
918
+ <View style={{ width: barW, height: barH, borderRadius: 2, backgroundColor: color }} />
919
+ </View>
920
+ );
921
+ }
922
+
923
+ export function AppChromeHeartGlyph(props: AppChromeGlyphProps) {
924
+ return <AppChromeHeartShape {...props} filled={false} />;
925
+ }
926
+
927
+ export function AppChromeHeartFilledGlyph(props: AppChromeGlyphProps) {
928
+ return <AppChromeHeartShape {...props} filled />;
929
+ }
930
+
931
+ export function AppChromePlusGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
932
+ const stroke = strokeFor(size);
933
+ const arm = size * 0.46;
934
+ return (
935
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
936
+ <View style={{ width: arm, height: stroke, backgroundColor: color, borderRadius: 1 }} />
937
+ <View style={{ position: 'absolute', width: stroke, height: arm, backgroundColor: color, borderRadius: 1 }} />
938
+ </View>
939
+ );
940
+ }
941
+
942
+ /** Publicar — documento com + central. */
943
+ export function AppChromePublishGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
944
+ const stroke = strokeFor(size);
945
+ const frame = size * 0.74;
946
+ const plusLen = frame * 0.42;
947
+ return (
948
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
949
+ <View
950
+ style={{
951
+ width: frame,
952
+ height: frame,
953
+ borderRadius: size * 0.12,
954
+ borderWidth: stroke,
955
+ borderColor: color,
956
+ alignItems: 'center',
957
+ justifyContent: 'center',
958
+ }}
959
+ >
960
+ <View style={{ width: plusLen, height: stroke, backgroundColor: color, borderRadius: 1 }} />
961
+ <View
962
+ style={{
963
+ position: 'absolute',
964
+ width: stroke,
965
+ height: plusLen,
966
+ backgroundColor: color,
967
+ borderRadius: 1,
968
+ }}
969
+ />
970
+ </View>
971
+ </View>
972
+ );
973
+ }
974
+
975
+ export function AppChromeIncognitoGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
976
+ const stroke = strokeFor(size);
977
+ const frameW = size * 0.86;
978
+ const frameH = size * 0.34;
979
+ return (
980
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
981
+ <View
982
+ style={{
983
+ width: frameW,
984
+ height: frameH,
985
+ borderRadius: frameH / 2,
986
+ borderWidth: stroke,
987
+ borderColor: color,
988
+ marginTop: size * 0.08,
989
+ }}
990
+ />
991
+ <View
992
+ style={{
993
+ position: 'absolute',
994
+ top: size * 0.34,
995
+ width: frameW * 0.72,
996
+ height: frameH * 0.9,
997
+ borderBottomLeftRadius: frameH * 0.45,
998
+ borderBottomRightRadius: frameH * 0.45,
999
+ borderWidth: stroke,
1000
+ borderTopWidth: 0,
1001
+ borderColor: color,
1002
+ }}
1003
+ />
1004
+ </View>
1005
+ );
1006
+ }
1007
+
1008
+ export function AppChromeEventsGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
1009
+ const stroke = strokeFor(size);
1010
+ const pole = size * 0.12;
1011
+ return (
1012
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
1013
+ <View style={{ position: 'absolute', left: size * 0.22, width: pole, height: size * 0.72, backgroundColor: color }} />
1014
+ <View style={{ position: 'absolute', right: size * 0.22, width: pole, height: size * 0.72, backgroundColor: color }} />
1015
+ <View
1016
+ style={{
1017
+ position: 'absolute',
1018
+ top: size * 0.12,
1019
+ width: size * 0.72,
1020
+ height: size * 0.34,
1021
+ borderTopLeftRadius: size * 0.08,
1022
+ borderTopRightRadius: size * 0.08,
1023
+ borderWidth: stroke,
1024
+ borderColor: color,
1025
+ }}
1026
+ />
1027
+ </View>
1028
+ );
1029
+ }
1030
+
1031
+ export function AppChromeShieldGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
1032
+ const stroke = strokeFor(size);
1033
+ const w = size * 0.62;
1034
+ const h = size * 0.76;
1035
+ return (
1036
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
1037
+ <View
1038
+ style={{
1039
+ width: w,
1040
+ height: h,
1041
+ borderTopLeftRadius: w * 0.2,
1042
+ borderTopRightRadius: w * 0.2,
1043
+ borderBottomLeftRadius: w * 0.45,
1044
+ borderBottomRightRadius: w * 0.45,
1045
+ borderWidth: stroke,
1046
+ borderColor: color,
1047
+ }}
1048
+ />
1049
+ </View>
1050
+ );
1051
+ }
1052
+
1053
+ export function AppChromeProfileGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
1054
+ const stroke = strokeFor(size);
1055
+ const head = size * 0.28;
1056
+ return (
1057
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
1058
+ <View
1059
+ style={{
1060
+ width: head,
1061
+ height: head,
1062
+ borderRadius: head / 2,
1063
+ borderWidth: stroke,
1064
+ borderColor: color,
1065
+ marginBottom: size * 0.04,
1066
+ }}
1067
+ />
1068
+ <View
1069
+ style={{
1070
+ width: size * 0.62,
1071
+ height: size * 0.3,
1072
+ borderTopLeftRadius: size * 0.3,
1073
+ borderTopRightRadius: size * 0.3,
1074
+ borderWidth: stroke,
1075
+ borderColor: color,
1076
+ borderBottomWidth: 0,
1077
+ }}
1078
+ />
1079
+ </View>
1080
+ );
1081
+ }
1082
+
1083
+ export function AppChromeBookmarkGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
1084
+ const stroke = strokeFor(size);
1085
+ const w = size * 0.52;
1086
+ const h = size * 0.72;
1087
+ return (
1088
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
1089
+ <View
1090
+ style={{
1091
+ width: w,
1092
+ height: h,
1093
+ borderWidth: stroke,
1094
+ borderColor: color,
1095
+ borderBottomWidth: 0,
1096
+ }}
1097
+ />
1098
+ <View
1099
+ style={{
1100
+ position: 'absolute',
1101
+ bottom: size * 0.12,
1102
+ width: 0,
1103
+ height: 0,
1104
+ borderLeftWidth: w / 2,
1105
+ borderRightWidth: w / 2,
1106
+ borderTopWidth: size * 0.16,
1107
+ borderLeftColor: 'transparent',
1108
+ borderRightColor: 'transparent',
1109
+ borderTopColor: color,
1110
+ }}
1111
+ />
1112
+ </View>
1113
+ );
1114
+ }
1115
+
1116
+ export function AppChromeListGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
1117
+ const stroke = strokeFor(size);
1118
+ const lineW = size * 0.62;
1119
+ return (
1120
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center', gap: size * 0.1 }}>
1121
+ {[0, 1, 2].map((row) => (
1122
+ <View key={row} style={{ flexDirection: 'row', alignItems: 'center', gap: size * 0.08 }}>
1123
+ <View style={{ width: size * 0.14, height: size * 0.14, borderRadius: size * 0.07, borderWidth: stroke, borderColor: color }} />
1124
+ <View style={{ width: lineW, height: stroke, backgroundColor: color }} />
1125
+ </View>
1126
+ ))}
1127
+ </View>
1128
+ );
1129
+ }
1130
+
1131
+ export function AppChromeCommunitiesGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
1132
+ const stroke = strokeFor(size);
1133
+ const head = size * 0.22;
1134
+ return (
1135
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
1136
+ <View style={{ flexDirection: 'row', gap: size * 0.08, marginBottom: size * 0.04 }}>
1137
+ <View style={{ width: head, height: head, borderRadius: head / 2, borderWidth: stroke, borderColor: color }} />
1138
+ <View style={{ width: head, height: head, borderRadius: head / 2, borderWidth: stroke, borderColor: color }} />
1139
+ </View>
1140
+ <View
1141
+ style={{
1142
+ width: size * 0.72,
1143
+ height: size * 0.26,
1144
+ borderTopLeftRadius: size * 0.16,
1145
+ borderTopRightRadius: size * 0.16,
1146
+ borderWidth: stroke,
1147
+ borderColor: color,
1148
+ borderBottomWidth: 0,
1149
+ }}
1150
+ />
1151
+ </View>
1152
+ );
1153
+ }
1154
+
1155
+ export function AppChromeStarGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
1156
+ const stroke = strokeFor(size);
1157
+ const arm = size * 0.34;
1158
+ return (
1159
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
1160
+ <View style={{ position: 'absolute', width: arm, height: stroke, backgroundColor: color }} />
1161
+ <View style={{ position: 'absolute', width: stroke, height: arm, backgroundColor: color }} />
1162
+ <View style={{ position: 'absolute', width: arm, height: stroke, backgroundColor: color, transform: [{ rotate: '45deg' }] }} />
1163
+ <View style={{ position: 'absolute', width: arm, height: stroke, backgroundColor: color, transform: [{ rotate: '-45deg' }] }} />
1164
+ <View
1165
+ style={{
1166
+ width: size * 0.2,
1167
+ height: size * 0.2,
1168
+ borderRadius: size * 0.1,
1169
+ backgroundColor: color,
1170
+ }}
1171
+ />
1172
+ </View>
1173
+ );
1174
+ }
1175
+
1176
+ export function AppChromeSignOutGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
1177
+ const stroke = strokeFor(size);
1178
+ return (
1179
+ <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
1180
+ <View
1181
+ style={{
1182
+ position: 'absolute',
1183
+ left: size * 0.12,
1184
+ width: size * 0.34,
1185
+ height: size * 0.34,
1186
+ borderRadius: size * 0.17,
1187
+ borderWidth: stroke,
1188
+ borderColor: color,
1189
+ }}
1190
+ />
1191
+ <View style={{ position: 'absolute', right: size * 0.1, width: size * 0.34, height: stroke, backgroundColor: color }} />
1192
+ <View
1193
+ style={{
1194
+ position: 'absolute',
1195
+ right: size * 0.1,
1196
+ width: size * 0.16,
1197
+ height: size * 0.16,
1198
+ borderRightWidth: stroke,
1199
+ borderTopWidth: stroke,
1200
+ borderColor: color,
1201
+ transform: [{ rotate: '45deg' }],
1202
+ }}
1203
+ />
1204
+ </View>
1205
+ );
1206
+ }
1207
+
1208
+ const styles = StyleSheet.create({
1209
+ crosshair: {
1210
+ position: 'absolute',
1211
+ borderRadius: 1,
1212
+ },
1213
+ diag: {
1214
+ position: 'absolute',
1215
+ borderRadius: 1,
1216
+ },
1217
+ });