Live video on the AT Protocol
79
fork

Configure Feed

Select the types of activity you want to include in your feed.

at feat-iroh-replicator 760 lines 16 kB view raw
1/** 2 * Theme atoms - Enhanced exports with pairify function for array-style syntax 3 * These provide direct access to static design tokens and support composition 4 */ 5 6import { Platform } from "react-native"; 7import { 8 animations, 9 borderRadius, 10 colors as rawColors, 11 shadows, 12 spacing, 13 touchTargets, 14 typography, 15} from "./tokens"; 16 17// Type for style objects that can be spread 18type StyleValue = Record<string, any>; 19 20/** 21 * Pairify function - converts nested objects into key-value pairs that return style objects 22 * This allows for array-style syntax like style={[a.borders.green[300], a.shadows.xl]} 23 */ 24function pairify<T extends Record<string, any>>( 25 obj: T, 26 styleKeyPrefix: string, 27): Record<keyof T, StyleValue> { 28 const result: Record<string, StyleValue> = {}; 29 30 for (const [key, value] of Object.entries(obj)) { 31 if (typeof value === "object" && value !== null && !Array.isArray(value)) { 32 // For nested objects (like color scales), create another level 33 result[key] = {}; 34 for (const [nestedKey, nestedValue] of Object.entries(value)) { 35 result[key][nestedKey] = { [styleKeyPrefix]: nestedValue }; 36 } 37 } else { 38 // For simple values, create the style object directly 39 result[key] = { [styleKeyPrefix]: value }; 40 } 41 } 42 43 return result as Record<keyof T, StyleValue>; 44} 45 46/** 47 * Create pairified style atoms for easy composition 48 */ 49 50// Re-export static design tokens that don't change with theme 51export { animations, borderRadius, shadows, spacing, touchTargets }; 52 53// Export raw color tokens for advanced use cases 54export const colors = rawColors; 55 56// Platform-aware typography helper 57export const getPlatformTypography = () => { 58 if (Platform.OS === "ios") { 59 return typography.ios; 60 } else if (Platform.OS === "android") { 61 return typography.android; 62 } 63 return typography.universal; 64}; 65 66// Export all typography scales 67export const typographyAtoms = { 68 platform: getPlatformTypography(), 69 universal: typography.universal, 70 ios: typography.ios, 71 android: typography.android, 72}; 73 74// Static icon sizes (colors are handled by theme) 75export const iconSizes = { 76 sm: 16, 77 md: 20, 78 lg: 24, 79 xl: 32, 80}; 81 82// Common layout utilities 83export const layout = { 84 flex: { 85 center: { 86 justifyContent: "center" as const, 87 alignItems: "center" as const, 88 }, 89 alignCenter: { 90 alignItems: "center" as const, 91 }, 92 justifyCenter: { 93 justifyContent: "center" as const, 94 }, 95 row: { 96 flexDirection: "row" as const, 97 }, 98 column: { 99 flexDirection: "column" as const, 100 }, 101 spaceBetween: { 102 justifyContent: "space-between" as const, 103 }, 104 spaceAround: { 105 justifyContent: "space-around" as const, 106 }, 107 spaceEvenly: { 108 justifyContent: "space-evenly" as const, 109 }, 110 }, 111 position: { 112 absolute: { 113 position: "absolute" as const, 114 }, 115 relative: { 116 position: "relative" as const, 117 }, 118 }, 119}; 120 121// Enhanced border utilities with pairified colors and widths 122export const borders = { 123 width: pairify( 124 { 125 thin: 1, 126 medium: 2, 127 thick: 4, 128 }, 129 "borderWidth", 130 ), 131 132 style: { 133 solid: { borderStyle: "solid" as const }, 134 dashed: { borderStyle: "dashed" as const }, 135 dotted: { borderStyle: "dotted" as const }, 136 }, 137 138 // Pairified color borders 139 color: pairify(rawColors, "borderColor"), 140 141 // Top border utilities 142 top: { 143 width: pairify( 144 { 145 thin: 1, 146 medium: 2, 147 thick: 4, 148 }, 149 "borderTopWidth", 150 ), 151 color: pairify(rawColors, "borderTopColor"), 152 }, 153 154 // Bottom border utilities 155 bottom: { 156 width: pairify( 157 { 158 thin: 1, 159 medium: 2, 160 thick: 4, 161 }, 162 "borderBottomWidth", 163 ), 164 color: pairify(rawColors, "borderBottomColor"), 165 }, 166 167 // Left border utilities 168 left: { 169 width: pairify( 170 { 171 thin: 1, 172 medium: 2, 173 thick: 4, 174 }, 175 "borderLeftWidth", 176 ), 177 color: pairify(rawColors, "borderLeftColor"), 178 }, 179 180 // Right border utilities 181 right: { 182 width: pairify( 183 { 184 thin: 1, 185 medium: 2, 186 thick: 4, 187 }, 188 "borderRightWidth", 189 ), 190 color: pairify(rawColors, "borderRightColor"), 191 }, 192}; 193 194// Pairified spacing utilities 195export const spacingAtoms = { 196 margin: pairify(spacing, "margin"), 197 marginTop: pairify(spacing, "marginTop"), 198 marginRight: pairify(spacing, "marginRight"), 199 marginBottom: pairify(spacing, "marginBottom"), 200 marginLeft: pairify(spacing, "marginLeft"), 201 marginHorizontal: pairify(spacing, "marginHorizontal"), 202 marginVertical: pairify(spacing, "marginVertical"), 203 204 padding: pairify(spacing, "padding"), 205 paddingTop: pairify(spacing, "paddingTop"), 206 paddingRight: pairify(spacing, "paddingRight"), 207 paddingBottom: pairify(spacing, "paddingBottom"), 208 paddingLeft: pairify(spacing, "paddingLeft"), 209 paddingHorizontal: pairify(spacing, "paddingHorizontal"), 210 paddingVertical: pairify(spacing, "paddingVertical"), 211}; 212 213// Pairified border radius utilities 214export const radiusAtoms = { 215 all: pairify(borderRadius, "borderRadius"), 216 top: pairify(borderRadius, "borderTopLeftRadius"), 217 topRight: pairify(borderRadius, "borderTopRightRadius"), 218 bottom: pairify(borderRadius, "borderBottomLeftRadius"), 219 bottomRight: pairify(borderRadius, "borderBottomRightRadius"), 220 left: pairify(borderRadius, "borderTopLeftRadius"), 221 right: pairify(borderRadius, "borderTopRightRadius"), 222}; 223 224// Background color utilities 225export const backgrounds = pairify(rawColors, "backgroundColor"); 226 227// Text color utilities 228export const textColors = pairify(rawColors, "color"); 229 230// Percentage-based sizes 231const percentageSizes = { 232 "10": "10%", 233 "20": "20%", 234 "25": "25%", 235 "30": "30%", 236 "33": "33.333333%", 237 "40": "40%", 238 "50": "50%", 239 "60": "60%", 240 "66": "66.666667%", 241 "70": "70%", 242 "75": "75%", 243 "80": "80%", 244 "90": "90%", 245 "100": "100%", 246} as const; 247 248// Size utilities (width and height) 249export const sizes = { 250 width: { 251 ...pairify(spacing, "width"), 252 percent: pairify(percentageSizes, "width"), 253 }, 254 height: { 255 ...pairify(spacing, "height"), 256 percent: pairify(percentageSizes, "height"), 257 }, 258 minWidth: { 259 ...pairify(spacing, "minWidth"), 260 percent: pairify(percentageSizes, "minWidth"), 261 }, 262 minHeight: { 263 ...pairify(spacing, "minHeight"), 264 percent: pairify(percentageSizes, "minHeight"), 265 }, 266 maxWidth: { 267 ...pairify(spacing, "maxWidth"), 268 percent: pairify(percentageSizes, "maxWidth"), 269 }, 270 maxHeight: { 271 ...pairify(spacing, "maxHeight"), 272 percent: pairify(percentageSizes, "maxHeight"), 273 }, 274}; 275 276// Flex utilities 277export const flex = { 278 values: pairify( 279 { 280 0: 0, 281 1: 1, 282 2: 2, 283 3: 3, 284 4: 4, 285 5: 5, 286 }, 287 "flex", 288 ), 289 290 grow: pairify( 291 { 292 0: 0, 293 1: 1, 294 }, 295 "flexGrow", 296 ), 297 298 shrink: pairify( 299 { 300 0: 0, 301 1: 1, 302 }, 303 "flexShrink", 304 ), 305 306 basis: { 307 ...pairify(spacing, "flexBasis"), 308 ...pairify(percentageSizes, "flexBasis"), 309 auto: { flexBasis: "auto" }, 310 }, 311}; 312 313// Opacity utilities 314export const opacity = pairify( 315 { 316 0: 0, 317 5: 0.05, 318 10: 0.1, 319 20: 0.2, 320 25: 0.25, 321 30: 0.3, 322 40: 0.4, 323 50: 0.5, 324 60: 0.6, 325 70: 0.7, 326 75: 0.75, 327 80: 0.8, 328 90: 0.9, 329 95: 0.95, 330 100: 1, 331 }, 332 "opacity", 333); 334 335// Z-index utilities 336export const zIndex = pairify( 337 { 338 0: 0, 339 10: 10, 340 20: 20, 341 30: 30, 342 40: 40, 343 50: 50, 344 auto: "auto", 345 }, 346 "zIndex", 347); 348 349// Overflow utilities 350export const overflow = { 351 visible: { overflow: "visible" as const }, 352 hidden: { overflow: "hidden" as const }, 353 scroll: { overflow: "scroll" as const }, 354}; 355 356// Text alignment utilities 357export const textAlign = { 358 left: { textAlign: "left" as const }, 359 center: { textAlign: "center" as const }, 360 right: { textAlign: "right" as const }, 361 justify: { textAlign: "justify" as const }, 362 auto: { textAlign: "auto" as const }, 363}; 364 365// Font weight utilities 366export const fontWeight = pairify( 367 { 368 thin: "100", 369 extralight: "200", 370 light: "300", 371 normal: "400", 372 medium: "500", 373 semibold: "600", 374 bold: "700", 375 extrabold: "800", 376 black: "900", 377 }, 378 "fontWeight", 379); 380 381// Font size utilities (separate from typography for quick access) 382export const fontSize = pairify( 383 { 384 xs: 12, 385 sm: 14, 386 base: 16, 387 lg: 18, 388 xl: 20, 389 "2xl": 24, 390 "3xl": 30, 391 "4xl": 36, 392 "5xl": 48, 393 "6xl": 60, 394 "7xl": 72, 395 "8xl": 96, 396 "9xl": 128, 397 }, 398 "fontSize", 399); 400 401// Line height utilities 402export const lineHeight = pairify( 403 { 404 none: 1, 405 tight: 1.25, 406 snug: 1.375, 407 normal: 1.5, 408 relaxed: 1.625, 409 loose: 2, 410 3: 12, 411 4: 16, 412 5: 20, 413 6: 24, 414 7: 28, 415 8: 32, 416 9: 36, 417 10: 40, 418 }, 419 "lineHeight", 420); 421 422// Letter spacing utilities 423export const letterSpacing = pairify( 424 { 425 tighter: -0.5, 426 tight: -0.25, 427 normal: 0, 428 wide: 0.25, 429 wider: 0.5, 430 widest: 1, 431 }, 432 "letterSpacing", 433); 434 435// Text transform utilities 436export const textTransform = { 437 uppercase: { textTransform: "uppercase" as const }, 438 lowercase: { textTransform: "lowercase" as const }, 439 capitalize: { textTransform: "capitalize" as const }, 440 none: { textTransform: "none" as const }, 441}; 442 443// Text decoration utilities 444export const textDecoration = { 445 none: { textDecorationLine: "none" as const }, 446 underline: { textDecorationLine: "underline" as const }, 447 lineThrough: { textDecorationLine: "line-through" as const }, 448 underlineLineThrough: { 449 textDecorationLine: "underline line-through" as const, 450 }, 451}; 452 453// Text align vertical utilities (React Native specific) 454export const textAlignVertical = { 455 auto: { textAlignVertical: "auto" as const }, 456 top: { textAlignVertical: "top" as const }, 457 bottom: { textAlignVertical: "bottom" as const }, 458 center: { textAlignVertical: "center" as const }, 459}; 460 461// Transform utilities 462export const transforms = { 463 rotate: pairify( 464 { 465 0: 0, 466 1: 1, 467 2: 2, 468 3: 3, 469 6: 6, 470 12: 12, 471 45: 45, 472 90: 90, 473 180: 180, 474 270: 270, 475 }, 476 "rotate", 477 ), 478 479 scale: pairify( 480 { 481 0: 0, 482 50: 0.5, 483 75: 0.75, 484 90: 0.9, 485 95: 0.95, 486 100: 1, 487 105: 1.05, 488 110: 1.1, 489 125: 1.25, 490 150: 1.5, 491 200: 2, 492 }, 493 "scale", 494 ), 495 496 scaleX: pairify( 497 { 498 0: 0, 499 50: 0.5, 500 75: 0.75, 501 90: 0.9, 502 95: 0.95, 503 100: 1, 504 105: 1.05, 505 110: 1.1, 506 125: 1.25, 507 150: 1.5, 508 200: 2, 509 }, 510 "scaleX", 511 ), 512 513 scaleY: pairify( 514 { 515 0: 0, 516 50: 0.5, 517 75: 0.75, 518 90: 0.9, 519 95: 0.95, 520 100: 1, 521 105: 1.05, 522 110: 1.1, 523 125: 1.25, 524 150: 1.5, 525 200: 2, 526 }, 527 "scaleY", 528 ), 529 530 translateX: pairify(spacing, "translateX"), 531 translateY: pairify(spacing, "translateY"), 532}; 533 534// Absolute positioning utilities 535export const position = { 536 top: pairify(spacing, "top"), 537 right: pairify(spacing, "right"), 538 bottom: pairify(spacing, "bottom"), 539 left: pairify(spacing, "left"), 540 541 // Common position combinations 542 topLeft: (top: number, left: number) => ({ 543 position: "absolute" as const, 544 top, 545 left, 546 }), 547 topRight: (top: number, right: number) => ({ 548 position: "absolute" as const, 549 top, 550 right, 551 }), 552 bottomLeft: (bottom: number, left: number) => ({ 553 position: "absolute" as const, 554 bottom, 555 left, 556 }), 557 bottomRight: (bottom: number, right: number) => ({ 558 position: "absolute" as const, 559 bottom, 560 right, 561 }), 562 563 // Percentage-based positioning 564 percent: { 565 top: pairify( 566 { 567 0: "0%", 568 25: "25%", 569 50: "50%", 570 75: "75%", 571 100: "100%", 572 }, 573 "top", 574 ), 575 right: pairify( 576 { 577 0: "0%", 578 25: "25%", 579 50: "50%", 580 75: "75%", 581 100: "100%", 582 }, 583 "right", 584 ), 585 bottom: pairify( 586 { 587 0: "0%", 588 25: "25%", 589 50: "50%", 590 75: "75%", 591 100: "100%", 592 }, 593 "bottom", 594 ), 595 left: pairify( 596 { 597 0: "0%", 598 25: "25%", 599 50: "50%", 600 75: "75%", 601 100: "100%", 602 }, 603 "left", 604 ), 605 }, 606}; 607 608// Aspect ratio utilities (React Native 0.71+) 609export const aspectRatio = pairify( 610 { 611 square: 1, 612 video: 16 / 9, 613 photo: 4 / 3, 614 portrait: 3 / 4, 615 wide: 21 / 9, 616 ultrawide: 32 / 9, 617 "1/1": 1, 618 "3/2": 3 / 2, 619 "4/3": 4 / 3, 620 "16/9": 16 / 9, 621 "21/9": 21 / 9, 622 }, 623 "aspectRatio", 624); 625 626// Gap utilities (React Native 0.71+) 627export const gap = { 628 row: pairify(spacing, "rowGap"), 629 column: pairify(spacing, "columnGap"), 630 all: pairify(spacing, "gap"), 631}; 632 633// Common layout patterns 634export const layouts = { 635 // Full screen 636 fullScreen: { 637 position: "absolute" as const, 638 top: 0, 639 left: 0, 640 right: 0, 641 bottom: 0, 642 }, 643 644 // Centered content 645 centered: { 646 flex: 1, 647 justifyContent: "center" as const, 648 alignItems: "center" as const, 649 }, 650 651 // Centered modal/overlay 652 overlay: { 653 position: "absolute" as const, 654 top: 0, 655 left: 0, 656 right: 0, 657 bottom: 0, 658 justifyContent: "center" as const, 659 alignItems: "center" as const, 660 backgroundColor: "rgba(0, 0, 0, 0.5)", 661 }, 662 663 // Safe area friendly 664 safeContainer: { 665 flex: 1, 666 paddingTop: Platform.OS === "ios" ? 44 : 0, // Status bar height 667 }, 668 669 // Row with space between 670 spaceBetweenRow: { 671 flexDirection: "row" as const, 672 justifyContent: "space-between" as const, 673 alignItems: "center" as const, 674 }, 675 676 // Sticky header 677 stickyHeader: { 678 position: "absolute" as const, 679 top: 0, 680 left: 0, 681 right: 0, 682 zIndex: 10, 683 }, 684 685 // Bottom sheet style 686 bottomSheet: { 687 position: "absolute" as const, 688 bottom: 0, 689 left: 0, 690 right: 0, 691 borderTopLeftRadius: 16, 692 borderTopRightRadius: 16, 693 }, 694}; 695 696// Export everything as a combined atoms object for convenience 697export const atoms = { 698 colors: rawColors, 699 spacing, 700 borderRadius, 701 radius: radiusAtoms, 702 typography: typographyAtoms, 703 shadows, 704 touchTargets, 705 animations, 706 iconSizes, 707 layout, 708 borders, 709 backgrounds, 710 textColors, 711 spacingAtoms, 712 sizes, 713 flex, 714 opacity, 715 zIndex, 716 overflow, 717 textAlign, 718 fontWeight, 719 fontSize, 720 lineHeight, 721 letterSpacing, 722 textTransform, 723 textDecoration, 724 textAlignVertical, 725 transforms, 726 position, 727 aspectRatio, 728 gap, 729 layouts, 730}; 731 732// Convenient shorthand aliases 733export const a = atoms; 734export const bg = backgrounds; 735export const text = textColors; 736export const m = spacingAtoms.margin; 737export const mt = spacingAtoms.marginTop; 738export const mr = spacingAtoms.marginRight; 739export const mb = spacingAtoms.marginBottom; 740export const ml = spacingAtoms.marginLeft; 741export const mx = spacingAtoms.marginHorizontal; 742export const my = spacingAtoms.marginVertical; 743export const p = spacingAtoms.padding; 744export const pt = spacingAtoms.paddingTop; 745export const pr = spacingAtoms.paddingRight; 746export const pb = spacingAtoms.paddingBottom; 747export const pl = spacingAtoms.paddingLeft; 748export const px = spacingAtoms.paddingHorizontal; 749export const py = spacingAtoms.paddingVertical; 750export const w = sizes.width; 751export const h = sizes.height; 752export const r = radiusAtoms.all; 753export const top = position.top; 754export const right = position.right; 755export const bottom = position.bottom; 756export const left = position.left; 757export const rotate = transforms.rotate; 758export const scale = transforms.scale; 759export const translateX = transforms.translateX; 760export const translateY = transforms.translateY;