@palate/cli 0.0.0-stage → 0.0.1
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 +20 -0
- package/README.md +151 -2
- package/bin/palate.mjs +894 -0
- package/kb/anatomy/data-table.md +24 -0
- package/kb/anatomy/empty-state.md +16 -0
- package/kb/anatomy/filter-toolbar.md +19 -0
- package/kb/anatomy/meter.md +16 -0
- package/kb/anatomy/product-window.md +18 -0
- package/kb/anatomy/settings-page.md +18 -0
- package/kb/anatomy/status-indicator.md +17 -0
- package/kb/anatomy/toast-undo.md +16 -0
- package/kb/bench/briefs.json +618 -0
- package/kb/craft/SOURCES.md +48 -0
- package/kb/craft/creativity.md +55 -0
- package/kb/craft/details.md +75 -0
- package/kb/craft/landing-demos.md +46 -0
- package/kb/craft/mistakes.md +73 -0
- package/kb/craft/motion.md +53 -0
- package/kb/craft/principles.md +68 -0
- package/kb/index/discovery.json +1 -0
- package/kb/inspiration/index.json +79 -0
- package/kb/moves/animated-comparison-table.md +58 -0
- package/kb/moves/before-after-slider.md +58 -0
- package/kb/moves/bento-live-tiles.md +57 -0
- package/kb/moves/calm-motion-system.md +63 -0
- package/kb/moves/canvas-grain.md +58 -0
- package/kb/moves/changelog-as-magazine.md +56 -0
- package/kb/moves/code-drawn-diagram.md +56 -0
- package/kb/moves/colophon.md +54 -0
- package/kb/moves/command-palette-site-nav.md +58 -0
- package/kb/moves/confetti-free-celebration.md +58 -0
- package/kb/moves/console-easter-egg.md +57 -0
- package/kb/moves/copy-confirmation.md +57 -0
- package/kb/moves/cursor-reactive-light.md +57 -0
- package/kb/moves/dark-band-contrast-section.md +55 -0
- package/kb/moves/designed-dark-mode.md +58 -0
- package/kb/moves/duotone-photography.md +55 -0
- package/kb/moves/editorial-drop-cap.md +58 -0
- package/kb/moves/editorial-grid-pull-quotes.md +55 -0
- package/kb/moves/engraving-colour-lens.md +64 -0
- package/kb/moves/explorable-control.md +57 -0
- package/kb/moves/feature-films-on-painted-stages.md +58 -0
- package/kb/moves/first-win-onboarding.md +59 -0
- package/kb/moves/footer-live-status.md +56 -0
- package/kb/moves/footer-rewards-the-end.md +58 -0
- package/kb/moves/generative-brand-pattern.md +55 -0
- package/kb/moves/gentle-error-nudge.md +59 -0
- package/kb/moves/halftone-dot-imagery.md +55 -0
- package/kb/moves/hand-drawn-annotations.md +55 -0
- package/kb/moves/hero-paints-itself-in.md +65 -0
- package/kb/moves/honest-progress-narration.md +58 -0
- package/kb/moves/honest-testimonial-wall.md +57 -0
- package/kb/moves/inline-sparklines-in-copy.md +57 -0
- package/kb/moves/inspect-our-taste.md +58 -0
- package/kb/moves/interactive-pricing-calculator.md +59 -0
- package/kb/moves/isometric-illustration-system.md +56 -0
- package/kb/moves/kinetic-variable-type.md +57 -0
- package/kb/moves/konami-secret.md +59 -0
- package/kb/moves/layered-paper-depth.md +56 -0
- package/kb/moves/lightweight-3d-object-hero.md +59 -0
- package/kb/moves/line-engraving-from-image.md +63 -0
- package/kb/moves/link-preview-peek.md +57 -0
- package/kb/moves/live-data-ticker.md +61 -0
- package/kb/moves/made-with-proof.md +51 -0
- package/kb/moves/magnetic-buttons.md +55 -0
- package/kb/moves/marquee-done-right.md +58 -0
- package/kb/moves/moves.yaml +450 -0
- package/kb/moves/museum-painting-backdrop.md +59 -0
- package/kb/moves/one-colour-brand-world.md +56 -0
- package/kb/moves/playful-404.md +58 -0
- package/kb/moves/pointer-highlight-word.md +56 -0
- package/kb/moves/product-in-context.md +56 -0
- package/kb/moves/real-world-data.md +58 -0
- package/kb/moves/referral-reward-reveal.md +59 -0
- package/kb/moves/riso-print-texture.md +57 -0
- package/kb/moves/screenshot-detail-crops.md +56 -0
- package/kb/moves/scroll-progress-chapters.md +57 -0
- package/kb/moves/scroll-scrubbed-product-film.md +62 -0
- package/kb/moves/self-playing-product-demo.md +61 -0
- package/kb/moves/shape-continuity-morph.md +58 -0
- package/kb/moves/sliding-nav-indicator.md +58 -0
- package/kb/moves/sticky-scroll-story.md +56 -0
- package/kb/moves/story-led-long-scroll.md +56 -0
- package/kb/moves/tactile-button.md +63 -0
- package/kb/moves/technical-drawing-lines.md +57 -0
- package/kb/moves/time-of-day-theming.md +56 -0
- package/kb/moves/tiny-game-easter-egg.md +60 -0
- package/kb/moves/type-decode-reveal.md +57 -0
- package/kb/moves/typographic-numeral-hero.md +58 -0
- package/kb/moves/view-transitions-between-pages.md +57 -0
- package/kb/moves/waitlist-position-live.md +60 -0
- package/kb/patterns/app-team-members.md +27 -0
- package/kb/patterns/chat-agent-approvals.md +31 -0
- package/kb/patterns/commerce-product-page.md +34 -0
- package/kb/patterns/dashboard-entity-table.md +37 -0
- package/kb/patterns/dashboard-home-today.md +24 -0
- package/kb/patterns/docs-api-reference.md +31 -0
- package/kb/patterns/marketing-product-led-landing.md +30 -0
- package/kb/patterns/mobile-daily-checklist.md +26 -0
- package/kb/references/index.json +1 -0
- package/kb/references/thumbs/004c5e9072.jpg +0 -0
- package/kb/references/thumbs/008915eb21.jpg +0 -0
- package/kb/references/thumbs/0098cf66c2.jpg +0 -0
- package/kb/references/thumbs/012e61b31f.jpg +0 -0
- package/kb/references/thumbs/014d4e46fc.jpg +0 -0
- package/kb/references/thumbs/01e54f394a.jpg +0 -0
- package/kb/references/thumbs/01e99a579c.jpg +0 -0
- package/kb/references/thumbs/01fd014575.jpg +0 -0
- package/kb/references/thumbs/022778ca72.jpg +0 -0
- package/kb/references/thumbs/02717bf1e1.jpg +0 -0
- package/kb/references/thumbs/02a5cfdbe9.jpg +0 -0
- package/kb/references/thumbs/02c9823f8d.jpg +0 -0
- package/kb/references/thumbs/02f3974613.jpg +0 -0
- package/kb/references/thumbs/032427f1ce.jpg +0 -0
- package/kb/references/thumbs/03ba677d07.jpg +0 -0
- package/kb/references/thumbs/04f2476cfe.jpg +0 -0
- package/kb/references/thumbs/0563e7c52e.jpg +0 -0
- package/kb/references/thumbs/05fa6b8eef.jpg +0 -0
- package/kb/references/thumbs/065bce1517.jpg +0 -0
- package/kb/references/thumbs/06c017f113.jpg +0 -0
- package/kb/references/thumbs/0770e2d8d3.jpg +0 -0
- package/kb/references/thumbs/078a26c4cb.jpg +0 -0
- package/kb/references/thumbs/08679b6e84.jpg +0 -0
- package/kb/references/thumbs/088c45a34c.jpg +0 -0
- package/kb/references/thumbs/089e9fd4e4.jpg +0 -0
- package/kb/references/thumbs/08f773231e.jpg +0 -0
- package/kb/references/thumbs/093ca3e2e3.jpg +0 -0
- package/kb/references/thumbs/0963320f74.jpg +0 -0
- package/kb/references/thumbs/09fc1ded85.jpg +0 -0
- package/kb/references/thumbs/0a368f3963.jpg +0 -0
- package/kb/references/thumbs/0a9e0e5201.jpg +0 -0
- package/kb/references/thumbs/0aace67ee7.jpg +0 -0
- package/kb/references/thumbs/0b61ecf793.jpg +0 -0
- package/kb/references/thumbs/0bde18ae09.jpg +0 -0
- package/kb/references/thumbs/0bf7ee8143.jpg +0 -0
- package/kb/references/thumbs/0ca20a13e0.jpg +0 -0
- package/kb/references/thumbs/0cdc0198c4.jpg +0 -0
- package/kb/references/thumbs/0cf9790b28.jpg +0 -0
- package/kb/references/thumbs/0d0202904b.jpg +0 -0
- package/kb/references/thumbs/0d053aba18.jpg +0 -0
- package/kb/references/thumbs/0d0c2c13d2.jpg +0 -0
- package/kb/references/thumbs/0d30be99b0.jpg +0 -0
- package/kb/references/thumbs/0d503da1b7.jpg +0 -0
- package/kb/references/thumbs/0ddad7b740.jpg +0 -0
- package/kb/references/thumbs/0e0a148101.jpg +0 -0
- package/kb/references/thumbs/0e401b6b75.jpg +0 -0
- package/kb/references/thumbs/0e8f32ba0f.jpg +0 -0
- package/kb/references/thumbs/0ef1966a7d.jpg +0 -0
- package/kb/references/thumbs/0efd416d11.jpg +0 -0
- package/kb/references/thumbs/0f3af263ae.jpg +0 -0
- package/kb/references/thumbs/0f9644c3a5.jpg +0 -0
- package/kb/references/thumbs/1020552737.jpg +0 -0
- package/kb/references/thumbs/1037626587.jpg +0 -0
- package/kb/references/thumbs/10512b7e94.jpg +0 -0
- package/kb/references/thumbs/106dc4a7b5.jpg +0 -0
- package/kb/references/thumbs/108943f6f7.jpg +0 -0
- package/kb/references/thumbs/10a5551d51.jpg +0 -0
- package/kb/references/thumbs/10dd01076c.jpg +0 -0
- package/kb/references/thumbs/11b06e39da.jpg +0 -0
- package/kb/references/thumbs/11baa1ec83.jpg +0 -0
- package/kb/references/thumbs/11bbe12167.jpg +0 -0
- package/kb/references/thumbs/11ca37feb8.jpg +0 -0
- package/kb/references/thumbs/11f14d3f12.jpg +0 -0
- package/kb/references/thumbs/124530ceb5.jpg +0 -0
- package/kb/references/thumbs/1276402336.jpg +0 -0
- package/kb/references/thumbs/1280e5c9d6.jpg +0 -0
- package/kb/references/thumbs/12cac0d172.jpg +0 -0
- package/kb/references/thumbs/138be6623a.jpg +0 -0
- package/kb/references/thumbs/13a0c544d1.jpg +0 -0
- package/kb/references/thumbs/13a32cb94c.jpg +0 -0
- package/kb/references/thumbs/144035d641.jpg +0 -0
- package/kb/references/thumbs/1457e41924.jpg +0 -0
- package/kb/references/thumbs/14972e3a86.jpg +0 -0
- package/kb/references/thumbs/15a47f2e4c.jpg +0 -0
- package/kb/references/thumbs/15aa15d22e.jpg +0 -0
- package/kb/references/thumbs/160dcd24b7.jpg +0 -0
- package/kb/references/thumbs/1610978529.jpg +0 -0
- package/kb/references/thumbs/16db30ba37.jpg +0 -0
- package/kb/references/thumbs/16f19ae4f3.jpg +0 -0
- package/kb/references/thumbs/16f758b03f.jpg +0 -0
- package/kb/references/thumbs/1748e5b751.jpg +0 -0
- package/kb/references/thumbs/175d0b0e69.jpg +0 -0
- package/kb/references/thumbs/178f571a36.jpg +0 -0
- package/kb/references/thumbs/17c43dc025.jpg +0 -0
- package/kb/references/thumbs/17c7f05b50.jpg +0 -0
- package/kb/references/thumbs/17f97e61dd.jpg +0 -0
- package/kb/references/thumbs/1804e17365.jpg +0 -0
- package/kb/references/thumbs/195c162ed1.jpg +0 -0
- package/kb/references/thumbs/19e3699c29.jpg +0 -0
- package/kb/references/thumbs/1a48e0a4d5.jpg +0 -0
- package/kb/references/thumbs/1a6cda265e.jpg +0 -0
- package/kb/references/thumbs/1a7e012091.jpg +0 -0
- package/kb/references/thumbs/1a9173a172.jpg +0 -0
- package/kb/references/thumbs/1b34a6b4d2.jpg +0 -0
- package/kb/references/thumbs/1b5284f3b2.jpg +0 -0
- package/kb/references/thumbs/1b93fbd6d3.jpg +0 -0
- package/kb/references/thumbs/1c6728fef6.jpg +0 -0
- package/kb/references/thumbs/1c6f101618.jpg +0 -0
- package/kb/references/thumbs/1cf7011a94.jpg +0 -0
- package/kb/references/thumbs/1d1769e539.jpg +0 -0
- package/kb/references/thumbs/1d1fd23199.jpg +0 -0
- package/kb/references/thumbs/1d7b6602ac.jpg +0 -0
- package/kb/references/thumbs/1dbbc61b9e.jpg +0 -0
- package/kb/references/thumbs/1dbdd6d21d.jpg +0 -0
- package/kb/references/thumbs/1dd873744b.jpg +0 -0
- package/kb/references/thumbs/1df4dd7cf9.jpg +0 -0
- package/kb/references/thumbs/1ece8c35b8.jpg +0 -0
- package/kb/references/thumbs/1f0e5b9aa4.jpg +0 -0
- package/kb/references/thumbs/1f1419651b.jpg +0 -0
- package/kb/references/thumbs/1f2a6da92d.jpg +0 -0
- package/kb/references/thumbs/1f651f33c0.jpg +0 -0
- package/kb/references/thumbs/1f8b697d18.jpg +0 -0
- package/kb/references/thumbs/1fee3824cd.jpg +0 -0
- package/kb/references/thumbs/1ff7757853.jpg +0 -0
- package/kb/references/thumbs/2043182f01.jpg +0 -0
- package/kb/references/thumbs/2059dabcd5.jpg +0 -0
- package/kb/references/thumbs/209d9dbb95.jpg +0 -0
- package/kb/references/thumbs/20d8923554.jpg +0 -0
- package/kb/references/thumbs/210dd3b671.jpg +0 -0
- package/kb/references/thumbs/2120719116.jpg +0 -0
- package/kb/references/thumbs/21a7384429.jpg +0 -0
- package/kb/references/thumbs/225f187391.jpg +0 -0
- package/kb/references/thumbs/230caf7dd2.jpg +0 -0
- package/kb/references/thumbs/235afad355.jpg +0 -0
- package/kb/references/thumbs/2378066687.jpg +0 -0
- package/kb/references/thumbs/241faf68a1.jpg +0 -0
- package/kb/references/thumbs/24d9f1a9b9.jpg +0 -0
- package/kb/references/thumbs/2505c8b9a0.jpg +0 -0
- package/kb/references/thumbs/25593638ca.jpg +0 -0
- package/kb/references/thumbs/25dd454f18.jpg +0 -0
- package/kb/references/thumbs/2602e123e2.jpg +0 -0
- package/kb/references/thumbs/26095c0b11.jpg +0 -0
- package/kb/references/thumbs/26260d6238.jpg +0 -0
- package/kb/references/thumbs/26bba21836.jpg +0 -0
- package/kb/references/thumbs/26bde3520b.jpg +0 -0
- package/kb/references/thumbs/272e22067c.jpg +0 -0
- package/kb/references/thumbs/27421b3226.jpg +0 -0
- package/kb/references/thumbs/2769ebca41.jpg +0 -0
- package/kb/references/thumbs/27e2f6e8b0.jpg +0 -0
- package/kb/references/thumbs/28432ba373.jpg +0 -0
- package/kb/references/thumbs/2846626f19.jpg +0 -0
- package/kb/references/thumbs/28750e821e.jpg +0 -0
- package/kb/references/thumbs/289481230f.jpg +0 -0
- package/kb/references/thumbs/2897967408.jpg +0 -0
- package/kb/references/thumbs/28c0a5fa17.jpg +0 -0
- package/kb/references/thumbs/28c181fba5.jpg +0 -0
- package/kb/references/thumbs/29806f539f.jpg +0 -0
- package/kb/references/thumbs/2997f56ee7.jpg +0 -0
- package/kb/references/thumbs/29b34a10fb.jpg +0 -0
- package/kb/references/thumbs/29bd78cdb4.jpg +0 -0
- package/kb/references/thumbs/29c8c6c22a.jpg +0 -0
- package/kb/references/thumbs/2ac23f7fae.jpg +0 -0
- package/kb/references/thumbs/2b76e13f79.jpg +0 -0
- package/kb/references/thumbs/2b84226479.jpg +0 -0
- package/kb/references/thumbs/2bf2dbf737.jpg +0 -0
- package/kb/references/thumbs/2bf89abbf6.jpg +0 -0
- package/kb/references/thumbs/2c562cd534.jpg +0 -0
- package/kb/references/thumbs/2cfe9d48c4.jpg +0 -0
- package/kb/references/thumbs/2d49f19b27.jpg +0 -0
- package/kb/references/thumbs/2dc8670da7.jpg +0 -0
- package/kb/references/thumbs/2de947c469.jpg +0 -0
- package/kb/references/thumbs/2e075ca79f.jpg +0 -0
- package/kb/references/thumbs/2eb0820e6b.jpg +0 -0
- package/kb/references/thumbs/2ec56a9dc0.jpg +0 -0
- package/kb/references/thumbs/30bb4ad607.jpg +0 -0
- package/kb/references/thumbs/30d19b8444.jpg +0 -0
- package/kb/references/thumbs/3173c71d73.jpg +0 -0
- package/kb/references/thumbs/31e59e4518.jpg +0 -0
- package/kb/references/thumbs/322b8960e8.jpg +0 -0
- package/kb/references/thumbs/325c9be6f4.jpg +0 -0
- package/kb/references/thumbs/3273338982.jpg +0 -0
- package/kb/references/thumbs/32f8387f38.jpg +0 -0
- package/kb/references/thumbs/332f6b74c3.jpg +0 -0
- package/kb/references/thumbs/334b146b6a.jpg +0 -0
- package/kb/references/thumbs/339abd60e4.jpg +0 -0
- package/kb/references/thumbs/33e88ec295.jpg +0 -0
- package/kb/references/thumbs/340931b5d4.jpg +0 -0
- package/kb/references/thumbs/34165a93bd.jpg +0 -0
- package/kb/references/thumbs/34d0575dd7.jpg +0 -0
- package/kb/references/thumbs/3549e75f0a.jpg +0 -0
- package/kb/references/thumbs/35827f1561.jpg +0 -0
- package/kb/references/thumbs/37c50280ec.jpg +0 -0
- package/kb/references/thumbs/37e66ecf11.jpg +0 -0
- package/kb/references/thumbs/3841a04fdc.jpg +0 -0
- package/kb/references/thumbs/38490c088f.jpg +0 -0
- package/kb/references/thumbs/3850319e9f.jpg +0 -0
- package/kb/references/thumbs/3856a64166.jpg +0 -0
- package/kb/references/thumbs/3881f211c2.jpg +0 -0
- package/kb/references/thumbs/38c7dde2f3.jpg +0 -0
- package/kb/references/thumbs/38ce9e486c.jpg +0 -0
- package/kb/references/thumbs/390ea8e01b.jpg +0 -0
- package/kb/references/thumbs/391b7fc27c.jpg +0 -0
- package/kb/references/thumbs/395f7214dc.jpg +0 -0
- package/kb/references/thumbs/39e81a5db2.jpg +0 -0
- package/kb/references/thumbs/3a67c8d655.jpg +0 -0
- package/kb/references/thumbs/3a89c25e3b.jpg +0 -0
- package/kb/references/thumbs/3aa0837542.jpg +0 -0
- package/kb/references/thumbs/3aae18aa8a.jpg +0 -0
- package/kb/references/thumbs/3bdbe767db.jpg +0 -0
- package/kb/references/thumbs/3c0616fc7f.jpg +0 -0
- package/kb/references/thumbs/3c18e9db1d.jpg +0 -0
- package/kb/references/thumbs/3c5a14076c.jpg +0 -0
- package/kb/references/thumbs/3ca9ec15c6.jpg +0 -0
- package/kb/references/thumbs/3d7756fd35.jpg +0 -0
- package/kb/references/thumbs/3dd45bd33d.jpg +0 -0
- package/kb/references/thumbs/3de72d5414.jpg +0 -0
- package/kb/references/thumbs/3dede597af.jpg +0 -0
- package/kb/references/thumbs/3ea948619e.jpg +0 -0
- package/kb/references/thumbs/402c12054c.jpg +0 -0
- package/kb/references/thumbs/403ab4af90.jpg +0 -0
- package/kb/references/thumbs/40773a8c63.jpg +0 -0
- package/kb/references/thumbs/407d9583db.jpg +0 -0
- package/kb/references/thumbs/415dc1d84c.jpg +0 -0
- package/kb/references/thumbs/420b676a4f.jpg +0 -0
- package/kb/references/thumbs/42a1ee85eb.jpg +0 -0
- package/kb/references/thumbs/43059221aa.jpg +0 -0
- package/kb/references/thumbs/432fa0d22c.jpg +0 -0
- package/kb/references/thumbs/43826f20e3.jpg +0 -0
- package/kb/references/thumbs/43ac55c98a.jpg +0 -0
- package/kb/references/thumbs/43d098f3c3.jpg +0 -0
- package/kb/references/thumbs/4449d80c2c.jpg +0 -0
- package/kb/references/thumbs/44625727dc.jpg +0 -0
- package/kb/references/thumbs/4482bb87a1.jpg +0 -0
- package/kb/references/thumbs/44b078acdc.jpg +0 -0
- package/kb/references/thumbs/44d0305850.jpg +0 -0
- package/kb/references/thumbs/456bb6b59e.jpg +0 -0
- package/kb/references/thumbs/45df73ce48.jpg +0 -0
- package/kb/references/thumbs/45edb45d87.jpg +0 -0
- package/kb/references/thumbs/4671d57cd5.jpg +0 -0
- package/kb/references/thumbs/46cc108518.jpg +0 -0
- package/kb/references/thumbs/470022e614.jpg +0 -0
- package/kb/references/thumbs/4719a669ce.jpg +0 -0
- package/kb/references/thumbs/47404f5ad4.jpg +0 -0
- package/kb/references/thumbs/479d3eb977.jpg +0 -0
- package/kb/references/thumbs/479ed92ceb.jpg +0 -0
- package/kb/references/thumbs/47baed50c7.jpg +0 -0
- package/kb/references/thumbs/47fdcfd7b0.jpg +0 -0
- package/kb/references/thumbs/48fd5e94c5.jpg +0 -0
- package/kb/references/thumbs/493807917b.jpg +0 -0
- package/kb/references/thumbs/49a1c67293.jpg +0 -0
- package/kb/references/thumbs/49e2d7fafe.jpg +0 -0
- package/kb/references/thumbs/49f540fcb6.jpg +0 -0
- package/kb/references/thumbs/4a67ec4028.jpg +0 -0
- package/kb/references/thumbs/4a93275b04.jpg +0 -0
- package/kb/references/thumbs/4aae6f52da.jpg +0 -0
- package/kb/references/thumbs/4b1bae66bd.jpg +0 -0
- package/kb/references/thumbs/4b75da15a9.jpg +0 -0
- package/kb/references/thumbs/4b77789b88.jpg +0 -0
- package/kb/references/thumbs/4bc2f3f3a4.jpg +0 -0
- package/kb/references/thumbs/4c48f27b88.jpg +0 -0
- package/kb/references/thumbs/4c52bd8bfb.jpg +0 -0
- package/kb/references/thumbs/4c9b4acc60.jpg +0 -0
- package/kb/references/thumbs/4cbf0752d4.jpg +0 -0
- package/kb/references/thumbs/4cd2672517.jpg +0 -0
- package/kb/references/thumbs/4dd22a8181.jpg +0 -0
- package/kb/references/thumbs/4ee3447314.jpg +0 -0
- package/kb/references/thumbs/4ef29c8144.jpg +0 -0
- package/kb/references/thumbs/4f82fadfd6.jpg +0 -0
- package/kb/references/thumbs/4fc9b643d8.jpg +0 -0
- package/kb/references/thumbs/50549524b0.jpg +0 -0
- package/kb/references/thumbs/509a615883.jpg +0 -0
- package/kb/references/thumbs/50c03ef855.jpg +0 -0
- package/kb/references/thumbs/50cf9acad6.jpg +0 -0
- package/kb/references/thumbs/51131b025c.jpg +0 -0
- package/kb/references/thumbs/51da1124f0.jpg +0 -0
- package/kb/references/thumbs/524d5e7288.jpg +0 -0
- package/kb/references/thumbs/5251247c81.jpg +0 -0
- package/kb/references/thumbs/526b91b7ec.jpg +0 -0
- package/kb/references/thumbs/52f02f6c2e.jpg +0 -0
- package/kb/references/thumbs/530ab530dc.jpg +0 -0
- package/kb/references/thumbs/5335ee4404.jpg +0 -0
- package/kb/references/thumbs/5385b90939.jpg +0 -0
- package/kb/references/thumbs/53c54654cc.jpg +0 -0
- package/kb/references/thumbs/5420794c6c.jpg +0 -0
- package/kb/references/thumbs/542a9dce8b.jpg +0 -0
- package/kb/references/thumbs/5571530a5f.jpg +0 -0
- package/kb/references/thumbs/56cc68d804.jpg +0 -0
- package/kb/references/thumbs/577b7f7c44.jpg +0 -0
- package/kb/references/thumbs/57adf8f1bb.jpg +0 -0
- package/kb/references/thumbs/57c5f5e3a6.jpg +0 -0
- package/kb/references/thumbs/57ffe4e839.jpg +0 -0
- package/kb/references/thumbs/5817dfc7d6.jpg +0 -0
- package/kb/references/thumbs/581a182a7a.jpg +0 -0
- package/kb/references/thumbs/58807679c8.jpg +0 -0
- package/kb/references/thumbs/589a1d9111.jpg +0 -0
- package/kb/references/thumbs/59167391ab.jpg +0 -0
- package/kb/references/thumbs/5a70420166.jpg +0 -0
- package/kb/references/thumbs/5b10df1b8d.jpg +0 -0
- package/kb/references/thumbs/5b7a712fdb.jpg +0 -0
- package/kb/references/thumbs/5bc46b92ad.jpg +0 -0
- package/kb/references/thumbs/5c0546a120.jpg +0 -0
- package/kb/references/thumbs/5c2b6125a8.jpg +0 -0
- package/kb/references/thumbs/5c536b9e42.jpg +0 -0
- package/kb/references/thumbs/5c8e441d30.jpg +0 -0
- package/kb/references/thumbs/5cb6f1baa5.jpg +0 -0
- package/kb/references/thumbs/5ce6c1f21e.jpg +0 -0
- package/kb/references/thumbs/5cef052c0a.jpg +0 -0
- package/kb/references/thumbs/5d08438209.jpg +0 -0
- package/kb/references/thumbs/5d0f9af9b0.jpg +0 -0
- package/kb/references/thumbs/5d300ed332.jpg +0 -0
- package/kb/references/thumbs/5d708a4794.jpg +0 -0
- package/kb/references/thumbs/5de8826a98.jpg +0 -0
- package/kb/references/thumbs/5df7bff22c.jpg +0 -0
- package/kb/references/thumbs/5e087d0f00.jpg +0 -0
- package/kb/references/thumbs/5e44e70ca0.jpg +0 -0
- package/kb/references/thumbs/5eff5d80ce.jpg +0 -0
- package/kb/references/thumbs/5f015c96b1.jpg +0 -0
- package/kb/references/thumbs/5f3289b7c4.jpg +0 -0
- package/kb/references/thumbs/5f830c40eb.jpg +0 -0
- package/kb/references/thumbs/60c4c3527b.jpg +0 -0
- package/kb/references/thumbs/60e9e594dd.jpg +0 -0
- package/kb/references/thumbs/615421d7be.jpg +0 -0
- package/kb/references/thumbs/6176e4004f.jpg +0 -0
- package/kb/references/thumbs/61f0fe5e06.jpg +0 -0
- package/kb/references/thumbs/6213785db4.jpg +0 -0
- package/kb/references/thumbs/62a670ae09.jpg +0 -0
- package/kb/references/thumbs/63cc12981b.jpg +0 -0
- package/kb/references/thumbs/641f15cc71.jpg +0 -0
- package/kb/references/thumbs/642ab2081d.jpg +0 -0
- package/kb/references/thumbs/644a59bf6e.jpg +0 -0
- package/kb/references/thumbs/644da8a8e3.jpg +0 -0
- package/kb/references/thumbs/6458986897.jpg +0 -0
- package/kb/references/thumbs/64cfbd7b93.jpg +0 -0
- package/kb/references/thumbs/661a57686a.jpg +0 -0
- package/kb/references/thumbs/66355a813a.jpg +0 -0
- package/kb/references/thumbs/664396dd44.jpg +0 -0
- package/kb/references/thumbs/66d832d65f.jpg +0 -0
- package/kb/references/thumbs/66de9e9833.jpg +0 -0
- package/kb/references/thumbs/6750964fd9.jpg +0 -0
- package/kb/references/thumbs/67c7164832.jpg +0 -0
- package/kb/references/thumbs/681600b6cd.jpg +0 -0
- package/kb/references/thumbs/682e75afe4.jpg +0 -0
- package/kb/references/thumbs/69274bc952.jpg +0 -0
- package/kb/references/thumbs/696ec08c52.jpg +0 -0
- package/kb/references/thumbs/69760111cc.jpg +0 -0
- package/kb/references/thumbs/697e32664f.jpg +0 -0
- package/kb/references/thumbs/69df92544b.jpg +0 -0
- package/kb/references/thumbs/69e48c5229.jpg +0 -0
- package/kb/references/thumbs/6a5fb75de1.jpg +0 -0
- package/kb/references/thumbs/6a7389e472.jpg +0 -0
- package/kb/references/thumbs/6a9b041e02.jpg +0 -0
- package/kb/references/thumbs/6ab2fa93ee.jpg +0 -0
- package/kb/references/thumbs/6ae3400319.jpg +0 -0
- package/kb/references/thumbs/6b21344bf3.jpg +0 -0
- package/kb/references/thumbs/6bd1b67a8a.jpg +0 -0
- package/kb/references/thumbs/6c99156c4f.jpg +0 -0
- package/kb/references/thumbs/6cc9b65384.jpg +0 -0
- package/kb/references/thumbs/6d15830a73.jpg +0 -0
- package/kb/references/thumbs/6d4c33d180.jpg +0 -0
- package/kb/references/thumbs/6e36815799.jpg +0 -0
- package/kb/references/thumbs/6eddb9cbfc.jpg +0 -0
- package/kb/references/thumbs/6f97968a7c.jpg +0 -0
- package/kb/references/thumbs/6fa0716a7d.jpg +0 -0
- package/kb/references/thumbs/6facd57184.jpg +0 -0
- package/kb/references/thumbs/6fd57b785a.jpg +0 -0
- package/kb/references/thumbs/700b3cb185.jpg +0 -0
- package/kb/references/thumbs/71197443fa.jpg +0 -0
- package/kb/references/thumbs/72082bc9ee.jpg +0 -0
- package/kb/references/thumbs/72453db479.jpg +0 -0
- package/kb/references/thumbs/72cd64d500.jpg +0 -0
- package/kb/references/thumbs/72d1e75283.jpg +0 -0
- package/kb/references/thumbs/72e13f7f5b.jpg +0 -0
- package/kb/references/thumbs/7459f8e644.jpg +0 -0
- package/kb/references/thumbs/7470d55c79.jpg +0 -0
- package/kb/references/thumbs/74c468f02a.jpg +0 -0
- package/kb/references/thumbs/74fed6eb77.jpg +0 -0
- package/kb/references/thumbs/756e05080d.jpg +0 -0
- package/kb/references/thumbs/75df7e5f49.jpg +0 -0
- package/kb/references/thumbs/76226da6ef.jpg +0 -0
- package/kb/references/thumbs/76a34aa056.jpg +0 -0
- package/kb/references/thumbs/76c7076589.jpg +0 -0
- package/kb/references/thumbs/76cccc396c.jpg +0 -0
- package/kb/references/thumbs/774654789f.jpg +0 -0
- package/kb/references/thumbs/7746cc494d.jpg +0 -0
- package/kb/references/thumbs/7766e36aa3.jpg +0 -0
- package/kb/references/thumbs/78049331ef.jpg +0 -0
- package/kb/references/thumbs/78808a0ca5.jpg +0 -0
- package/kb/references/thumbs/7890b0a310.jpg +0 -0
- package/kb/references/thumbs/78911975e6.jpg +0 -0
- package/kb/references/thumbs/78d289d5a0.jpg +0 -0
- package/kb/references/thumbs/794126267e.jpg +0 -0
- package/kb/references/thumbs/7976eb9025.jpg +0 -0
- package/kb/references/thumbs/798519ec7c.jpg +0 -0
- package/kb/references/thumbs/7a6cc5eecc.jpg +0 -0
- package/kb/references/thumbs/7ac8a7cd4a.jpg +0 -0
- package/kb/references/thumbs/7b1341d61d.jpg +0 -0
- package/kb/references/thumbs/7b9c4031e3.jpg +0 -0
- package/kb/references/thumbs/7ba5ad3779.jpg +0 -0
- package/kb/references/thumbs/7be6eb2bd0.jpg +0 -0
- package/kb/references/thumbs/7c30864f5d.jpg +0 -0
- package/kb/references/thumbs/7c379b5e17.jpg +0 -0
- package/kb/references/thumbs/7c4050eb02.jpg +0 -0
- package/kb/references/thumbs/7ca47b3221.jpg +0 -0
- package/kb/references/thumbs/7d43516bd7.jpg +0 -0
- package/kb/references/thumbs/7da9dbb98a.jpg +0 -0
- package/kb/references/thumbs/7ddda8f57c.jpg +0 -0
- package/kb/references/thumbs/7ece6d215c.jpg +0 -0
- package/kb/references/thumbs/7eebf029de.jpg +0 -0
- package/kb/references/thumbs/7f45483c15.jpg +0 -0
- package/kb/references/thumbs/7fde06eaa5.jpg +0 -0
- package/kb/references/thumbs/80407b97e9.jpg +0 -0
- package/kb/references/thumbs/80f0a6cf4b.jpg +0 -0
- package/kb/references/thumbs/8118b451b8.jpg +0 -0
- package/kb/references/thumbs/816baed4a8.jpg +0 -0
- package/kb/references/thumbs/817d2d15d9.jpg +0 -0
- package/kb/references/thumbs/8260cb430d.jpg +0 -0
- package/kb/references/thumbs/827b562899.jpg +0 -0
- package/kb/references/thumbs/8293cf1e92.jpg +0 -0
- package/kb/references/thumbs/8294653169.jpg +0 -0
- package/kb/references/thumbs/83061f871f.jpg +0 -0
- package/kb/references/thumbs/833df778ca.jpg +0 -0
- package/kb/references/thumbs/83d3acaafc.jpg +0 -0
- package/kb/references/thumbs/844c6efeff.jpg +0 -0
- package/kb/references/thumbs/84563d482a.jpg +0 -0
- package/kb/references/thumbs/848082dd94.jpg +0 -0
- package/kb/references/thumbs/8494b1da94.jpg +0 -0
- package/kb/references/thumbs/84b71014be.jpg +0 -0
- package/kb/references/thumbs/84be4a5f3c.jpg +0 -0
- package/kb/references/thumbs/84fd0fd25a.jpg +0 -0
- package/kb/references/thumbs/853e488e22.jpg +0 -0
- package/kb/references/thumbs/858c91585d.jpg +0 -0
- package/kb/references/thumbs/85903e8fe9.jpg +0 -0
- package/kb/references/thumbs/86597d43fd.jpg +0 -0
- package/kb/references/thumbs/866eb99500.jpg +0 -0
- package/kb/references/thumbs/86ac050340.jpg +0 -0
- package/kb/references/thumbs/86afec7b64.jpg +0 -0
- package/kb/references/thumbs/87238127f5.jpg +0 -0
- package/kb/references/thumbs/87321df792.jpg +0 -0
- package/kb/references/thumbs/87460f70cd.jpg +0 -0
- package/kb/references/thumbs/8770dfeaec.jpg +0 -0
- package/kb/references/thumbs/8798451a8c.jpg +0 -0
- package/kb/references/thumbs/87da1f34a3.jpg +0 -0
- package/kb/references/thumbs/882cdf8c05.jpg +0 -0
- package/kb/references/thumbs/8839f4106f.jpg +0 -0
- package/kb/references/thumbs/8844455212.jpg +0 -0
- package/kb/references/thumbs/88abba0497.jpg +0 -0
- package/kb/references/thumbs/88b372435d.jpg +0 -0
- package/kb/references/thumbs/88bd4f35fa.jpg +0 -0
- package/kb/references/thumbs/88c71a075e.jpg +0 -0
- package/kb/references/thumbs/892e5f048e.jpg +0 -0
- package/kb/references/thumbs/893cc8e920.jpg +0 -0
- package/kb/references/thumbs/896c198814.jpg +0 -0
- package/kb/references/thumbs/8a8e22f756.jpg +0 -0
- package/kb/references/thumbs/8a9d8a35cb.jpg +0 -0
- package/kb/references/thumbs/8ab1d67fec.jpg +0 -0
- package/kb/references/thumbs/8ab201fe12.jpg +0 -0
- package/kb/references/thumbs/8ac372c102.jpg +0 -0
- package/kb/references/thumbs/8b15736d62.jpg +0 -0
- package/kb/references/thumbs/8b1d8d6a05.jpg +0 -0
- package/kb/references/thumbs/8bb6050e20.jpg +0 -0
- package/kb/references/thumbs/8c6c9d1577.jpg +0 -0
- package/kb/references/thumbs/8d337851e0.jpg +0 -0
- package/kb/references/thumbs/8d44b33cc5.jpg +0 -0
- package/kb/references/thumbs/8d4536ff3b.jpg +0 -0
- package/kb/references/thumbs/8d9b99454a.jpg +0 -0
- package/kb/references/thumbs/8dda2303ff.jpg +0 -0
- package/kb/references/thumbs/8dec722d62.jpg +0 -0
- package/kb/references/thumbs/8e0ea4ca74.jpg +0 -0
- package/kb/references/thumbs/8ebba84d69.jpg +0 -0
- package/kb/references/thumbs/8ef09140c0.jpg +0 -0
- package/kb/references/thumbs/8f2928a1b0.jpg +0 -0
- package/kb/references/thumbs/8f88f9ddba.jpg +0 -0
- package/kb/references/thumbs/8fa4451009.jpg +0 -0
- package/kb/references/thumbs/90109b0e02.jpg +0 -0
- package/kb/references/thumbs/90e854e5c9.jpg +0 -0
- package/kb/references/thumbs/914e79f893.jpg +0 -0
- package/kb/references/thumbs/9161369197.jpg +0 -0
- package/kb/references/thumbs/9165c87d6f.jpg +0 -0
- package/kb/references/thumbs/9193f6558a.jpg +0 -0
- package/kb/references/thumbs/91ac7df877.jpg +0 -0
- package/kb/references/thumbs/9216bd4931.jpg +0 -0
- package/kb/references/thumbs/922ae8a26a.jpg +0 -0
- package/kb/references/thumbs/92a70e6867.jpg +0 -0
- package/kb/references/thumbs/92c77ece22.jpg +0 -0
- package/kb/references/thumbs/92e5914fbf.jpg +0 -0
- package/kb/references/thumbs/92ee36419a.jpg +0 -0
- package/kb/references/thumbs/94153a60b0.jpg +0 -0
- package/kb/references/thumbs/9449666640.jpg +0 -0
- package/kb/references/thumbs/944be6a646.jpg +0 -0
- package/kb/references/thumbs/945831476e.jpg +0 -0
- package/kb/references/thumbs/94c1af82f4.jpg +0 -0
- package/kb/references/thumbs/9599d6d589.jpg +0 -0
- package/kb/references/thumbs/960710f4cf.jpg +0 -0
- package/kb/references/thumbs/9608f12d64.jpg +0 -0
- package/kb/references/thumbs/962dabfaa0.jpg +0 -0
- package/kb/references/thumbs/965a3a95c6.jpg +0 -0
- package/kb/references/thumbs/9672ed5ae4.jpg +0 -0
- package/kb/references/thumbs/96891ae9c1.jpg +0 -0
- package/kb/references/thumbs/96e1907c99.jpg +0 -0
- package/kb/references/thumbs/96f25b6578.jpg +0 -0
- package/kb/references/thumbs/97211df9ae.jpg +0 -0
- package/kb/references/thumbs/9769d763a5.jpg +0 -0
- package/kb/references/thumbs/9792bd6d05.jpg +0 -0
- package/kb/references/thumbs/97d2837e3e.jpg +0 -0
- package/kb/references/thumbs/97d90d1d85.jpg +0 -0
- package/kb/references/thumbs/97fcd5774a.jpg +0 -0
- package/kb/references/thumbs/980f68564e.jpg +0 -0
- package/kb/references/thumbs/98511fb393.jpg +0 -0
- package/kb/references/thumbs/98f8fa694d.jpg +0 -0
- package/kb/references/thumbs/9a42c6bb97.jpg +0 -0
- package/kb/references/thumbs/9ab3600a06.jpg +0 -0
- package/kb/references/thumbs/9ab48d9130.jpg +0 -0
- package/kb/references/thumbs/9ad519197d.jpg +0 -0
- package/kb/references/thumbs/9b1382c657.jpg +0 -0
- package/kb/references/thumbs/9b6cc1e077.jpg +0 -0
- package/kb/references/thumbs/9beede8480.jpg +0 -0
- package/kb/references/thumbs/9bf8976952.jpg +0 -0
- package/kb/references/thumbs/9cace7b75a.jpg +0 -0
- package/kb/references/thumbs/9cdcc5745e.jpg +0 -0
- package/kb/references/thumbs/9d0b269074.jpg +0 -0
- package/kb/references/thumbs/9d41788b48.jpg +0 -0
- package/kb/references/thumbs/9d475bd6af.jpg +0 -0
- package/kb/references/thumbs/9e6bc543d0.jpg +0 -0
- package/kb/references/thumbs/9ed0e0a206.jpg +0 -0
- package/kb/references/thumbs/9ef538de13.jpg +0 -0
- package/kb/references/thumbs/9efc373ab4.jpg +0 -0
- package/kb/references/thumbs/9f4a939fa5.jpg +0 -0
- package/kb/references/thumbs/9f8d12d7b9.jpg +0 -0
- package/kb/references/thumbs/9fd5e3efa7.jpg +0 -0
- package/kb/references/thumbs/a0a9b9c572.jpg +0 -0
- package/kb/references/thumbs/a29ca9b185.jpg +0 -0
- package/kb/references/thumbs/a2a42884af.jpg +0 -0
- package/kb/references/thumbs/a2f5064e34.jpg +0 -0
- package/kb/references/thumbs/a3112ce672.jpg +0 -0
- package/kb/references/thumbs/a3437736d1.jpg +0 -0
- package/kb/references/thumbs/a372667e76.jpg +0 -0
- package/kb/references/thumbs/a39bae94e9.jpg +0 -0
- package/kb/references/thumbs/a3fc75d94c.jpg +0 -0
- package/kb/references/thumbs/a440487631.jpg +0 -0
- package/kb/references/thumbs/a4993d5fb5.jpg +0 -0
- package/kb/references/thumbs/a500476a86.jpg +0 -0
- package/kb/references/thumbs/a55506bf46.jpg +0 -0
- package/kb/references/thumbs/a59a5f9843.jpg +0 -0
- package/kb/references/thumbs/a5bce0eede.jpg +0 -0
- package/kb/references/thumbs/a5d921e1f0.jpg +0 -0
- package/kb/references/thumbs/a5e19d4637.jpg +0 -0
- package/kb/references/thumbs/a5f92b97d5.jpg +0 -0
- package/kb/references/thumbs/a6562c210a.jpg +0 -0
- package/kb/references/thumbs/a6f61a8d09.jpg +0 -0
- package/kb/references/thumbs/a719fdf663.jpg +0 -0
- package/kb/references/thumbs/a724e5442f.jpg +0 -0
- package/kb/references/thumbs/a852b4319f.jpg +0 -0
- package/kb/references/thumbs/a896c08448.jpg +0 -0
- package/kb/references/thumbs/a8d190a4b8.jpg +0 -0
- package/kb/references/thumbs/a8dcdd57d7.jpg +0 -0
- package/kb/references/thumbs/a951347e18.jpg +0 -0
- package/kb/references/thumbs/a9a1a0bf7d.jpg +0 -0
- package/kb/references/thumbs/a9b72986a8.jpg +0 -0
- package/kb/references/thumbs/aa11555ba8.jpg +0 -0
- package/kb/references/thumbs/aa4aab9093.jpg +0 -0
- package/kb/references/thumbs/aa89b96658.jpg +0 -0
- package/kb/references/thumbs/aaeb3739b6.jpg +0 -0
- package/kb/references/thumbs/ab25a608ec.jpg +0 -0
- package/kb/references/thumbs/ab34b62268.jpg +0 -0
- package/kb/references/thumbs/ab3b0217bb.jpg +0 -0
- package/kb/references/thumbs/ac70c04afb.jpg +0 -0
- package/kb/references/thumbs/ace0879117.jpg +0 -0
- package/kb/references/thumbs/ad0515ae55.jpg +0 -0
- package/kb/references/thumbs/ad66b25b47.jpg +0 -0
- package/kb/references/thumbs/ad68229d2f.jpg +0 -0
- package/kb/references/thumbs/add6480693.jpg +0 -0
- package/kb/references/thumbs/ae5b8c3b8c.jpg +0 -0
- package/kb/references/thumbs/ae81247b47.jpg +0 -0
- package/kb/references/thumbs/af8aa54379.jpg +0 -0
- package/kb/references/thumbs/afa80dedd4.jpg +0 -0
- package/kb/references/thumbs/afe04d730f.jpg +0 -0
- package/kb/references/thumbs/b09a7dc315.jpg +0 -0
- package/kb/references/thumbs/b0c02629f6.jpg +0 -0
- package/kb/references/thumbs/b1cb4f91de.jpg +0 -0
- package/kb/references/thumbs/b1d4c13c92.jpg +0 -0
- package/kb/references/thumbs/b20eef86db.jpg +0 -0
- package/kb/references/thumbs/b3136ccdde.jpg +0 -0
- package/kb/references/thumbs/b3f5e8d7dd.jpg +0 -0
- package/kb/references/thumbs/b44adb81c9.jpg +0 -0
- package/kb/references/thumbs/b457a5894b.jpg +0 -0
- package/kb/references/thumbs/b461281e0f.jpg +0 -0
- package/kb/references/thumbs/b4942644f0.jpg +0 -0
- package/kb/references/thumbs/b49f8eccad.jpg +0 -0
- package/kb/references/thumbs/b56c69be23.jpg +0 -0
- package/kb/references/thumbs/b59786b33c.jpg +0 -0
- package/kb/references/thumbs/b5d368ce5a.jpg +0 -0
- package/kb/references/thumbs/b5eb442406.jpg +0 -0
- package/kb/references/thumbs/b7fdabf4ab.jpg +0 -0
- package/kb/references/thumbs/b88ee8d235.jpg +0 -0
- package/kb/references/thumbs/b8a4e5be8a.jpg +0 -0
- package/kb/references/thumbs/b8c85b661c.jpg +0 -0
- package/kb/references/thumbs/ba1b8e7435.jpg +0 -0
- package/kb/references/thumbs/ba9a593eed.jpg +0 -0
- package/kb/references/thumbs/baa7afc201.jpg +0 -0
- package/kb/references/thumbs/baf74398f7.jpg +0 -0
- package/kb/references/thumbs/bb3e947c10.jpg +0 -0
- package/kb/references/thumbs/bb4c1bb7c1.jpg +0 -0
- package/kb/references/thumbs/bbaa25cc8a.jpg +0 -0
- package/kb/references/thumbs/bc7e7f88cc.jpg +0 -0
- package/kb/references/thumbs/bc9d5b58f5.jpg +0 -0
- package/kb/references/thumbs/bcc99a51f7.jpg +0 -0
- package/kb/references/thumbs/bce13dd1c1.jpg +0 -0
- package/kb/references/thumbs/bd079a6130.jpg +0 -0
- package/kb/references/thumbs/bd2d70dda7.jpg +0 -0
- package/kb/references/thumbs/bd5895c5f2.jpg +0 -0
- package/kb/references/thumbs/bde8e31d62.jpg +0 -0
- package/kb/references/thumbs/be084e78f3.jpg +0 -0
- package/kb/references/thumbs/be94f170c8.jpg +0 -0
- package/kb/references/thumbs/bed33654f7.jpg +0 -0
- package/kb/references/thumbs/beeb9a0c18.jpg +0 -0
- package/kb/references/thumbs/bef42094dc.jpg +0 -0
- package/kb/references/thumbs/bf625496fa.jpg +0 -0
- package/kb/references/thumbs/bf771f1398.jpg +0 -0
- package/kb/references/thumbs/c0ddefa3d9.jpg +0 -0
- package/kb/references/thumbs/c0f01e536e.jpg +0 -0
- package/kb/references/thumbs/c1d592b678.jpg +0 -0
- package/kb/references/thumbs/c1e83e1b3e.jpg +0 -0
- package/kb/references/thumbs/c2168f8096.jpg +0 -0
- package/kb/references/thumbs/c249cd6b17.jpg +0 -0
- package/kb/references/thumbs/c2e3d4feed.jpg +0 -0
- package/kb/references/thumbs/c3cec01df1.jpg +0 -0
- package/kb/references/thumbs/c47bedb42d.jpg +0 -0
- package/kb/references/thumbs/c4b03b4680.jpg +0 -0
- package/kb/references/thumbs/c4e6d18ec3.jpg +0 -0
- package/kb/references/thumbs/c5477e2877.jpg +0 -0
- package/kb/references/thumbs/c566794674.jpg +0 -0
- package/kb/references/thumbs/c5b945afbb.jpg +0 -0
- package/kb/references/thumbs/c5e4659497.jpg +0 -0
- package/kb/references/thumbs/c622786702.jpg +0 -0
- package/kb/references/thumbs/c6250649ca.jpg +0 -0
- package/kb/references/thumbs/c6261a9526.jpg +0 -0
- package/kb/references/thumbs/c62e609076.jpg +0 -0
- package/kb/references/thumbs/c6602d3e85.jpg +0 -0
- package/kb/references/thumbs/c6c1a16e40.jpg +0 -0
- package/kb/references/thumbs/c77f932157.jpg +0 -0
- package/kb/references/thumbs/c79788f01e.jpg +0 -0
- package/kb/references/thumbs/c7a511ad1e.jpg +0 -0
- package/kb/references/thumbs/c7acfbc3c8.jpg +0 -0
- package/kb/references/thumbs/c7bb6d1bb8.jpg +0 -0
- package/kb/references/thumbs/c829eadcb9.jpg +0 -0
- package/kb/references/thumbs/c891fd9d85.jpg +0 -0
- package/kb/references/thumbs/c89f812ee3.jpg +0 -0
- package/kb/references/thumbs/c8a85b9f61.jpg +0 -0
- package/kb/references/thumbs/c8fdf85c9a.jpg +0 -0
- package/kb/references/thumbs/c961ac1031.jpg +0 -0
- package/kb/references/thumbs/c9fd3f88d8.jpg +0 -0
- package/kb/references/thumbs/ca0d6399c3.jpg +0 -0
- package/kb/references/thumbs/ca316c83e4.jpg +0 -0
- package/kb/references/thumbs/ca3b93aa0d.jpg +0 -0
- package/kb/references/thumbs/cb0596a85b.jpg +0 -0
- package/kb/references/thumbs/cb95a5c3ef.jpg +0 -0
- package/kb/references/thumbs/cbe238b656.jpg +0 -0
- package/kb/references/thumbs/cbf530e608.jpg +0 -0
- package/kb/references/thumbs/cc173494ec.jpg +0 -0
- package/kb/references/thumbs/ccb664bddf.jpg +0 -0
- package/kb/references/thumbs/ccf69d36cd.jpg +0 -0
- package/kb/references/thumbs/ccf759db42.jpg +0 -0
- package/kb/references/thumbs/cd2a285807.jpg +0 -0
- package/kb/references/thumbs/cd4a24a8ca.jpg +0 -0
- package/kb/references/thumbs/cdb3fe8938.jpg +0 -0
- package/kb/references/thumbs/cdce1b9bc6.jpg +0 -0
- package/kb/references/thumbs/cde3aa761a.jpg +0 -0
- package/kb/references/thumbs/ce9d5cd9c2.jpg +0 -0
- package/kb/references/thumbs/ceb01f8a34.jpg +0 -0
- package/kb/references/thumbs/cee15c98d0.jpg +0 -0
- package/kb/references/thumbs/cf6944ddae.jpg +0 -0
- package/kb/references/thumbs/d15dd21cd8.jpg +0 -0
- package/kb/references/thumbs/d1633bf2ed.jpg +0 -0
- package/kb/references/thumbs/d16a838000.jpg +0 -0
- package/kb/references/thumbs/d1cf87e9f0.jpg +0 -0
- package/kb/references/thumbs/d32511d913.jpg +0 -0
- package/kb/references/thumbs/d327e9dedd.jpg +0 -0
- package/kb/references/thumbs/d35bf6c85e.jpg +0 -0
- package/kb/references/thumbs/d37afc9d61.jpg +0 -0
- package/kb/references/thumbs/d3b66655c7.jpg +0 -0
- package/kb/references/thumbs/d40b4172b6.jpg +0 -0
- package/kb/references/thumbs/d4c40d1824.jpg +0 -0
- package/kb/references/thumbs/d4cb55a4b6.jpg +0 -0
- package/kb/references/thumbs/d4f0c30f7e.jpg +0 -0
- package/kb/references/thumbs/d51cce3ae5.jpg +0 -0
- package/kb/references/thumbs/d52948f9ba.jpg +0 -0
- package/kb/references/thumbs/d62bd3cba4.jpg +0 -0
- package/kb/references/thumbs/d668a21c92.jpg +0 -0
- package/kb/references/thumbs/d685072c52.jpg +0 -0
- package/kb/references/thumbs/d6d7b96093.jpg +0 -0
- package/kb/references/thumbs/d7cd874b21.jpg +0 -0
- package/kb/references/thumbs/d7e111736a.jpg +0 -0
- package/kb/references/thumbs/d88325f832.jpg +0 -0
- package/kb/references/thumbs/d9272ded76.jpg +0 -0
- package/kb/references/thumbs/d962e7c654.jpg +0 -0
- package/kb/references/thumbs/d97f000ee2.jpg +0 -0
- package/kb/references/thumbs/d9c1ae2543.jpg +0 -0
- package/kb/references/thumbs/d9ccb3cac8.jpg +0 -0
- package/kb/references/thumbs/da99019680.jpg +0 -0
- package/kb/references/thumbs/da9b8bc615.jpg +0 -0
- package/kb/references/thumbs/daafbee2c1.jpg +0 -0
- package/kb/references/thumbs/db0f11f143.jpg +0 -0
- package/kb/references/thumbs/db5dd367f5.jpg +0 -0
- package/kb/references/thumbs/db69677866.jpg +0 -0
- package/kb/references/thumbs/db87c1956e.jpg +0 -0
- package/kb/references/thumbs/dbb86d8bda.jpg +0 -0
- package/kb/references/thumbs/dbd3a8ff2a.jpg +0 -0
- package/kb/references/thumbs/dbdf4b2794.jpg +0 -0
- package/kb/references/thumbs/dd4c19b4b1.jpg +0 -0
- package/kb/references/thumbs/dd98d9f6fa.jpg +0 -0
- package/kb/references/thumbs/ddb00e3b6a.jpg +0 -0
- package/kb/references/thumbs/dde3541a5c.jpg +0 -0
- package/kb/references/thumbs/de2a4da502.jpg +0 -0
- package/kb/references/thumbs/de4c387a66.jpg +0 -0
- package/kb/references/thumbs/de5618fa82.jpg +0 -0
- package/kb/references/thumbs/de6bec2538.jpg +0 -0
- package/kb/references/thumbs/dea13cbb1f.jpg +0 -0
- package/kb/references/thumbs/deff9202aa.jpg +0 -0
- package/kb/references/thumbs/df12835f8d.jpg +0 -0
- package/kb/references/thumbs/df57acbb3d.jpg +0 -0
- package/kb/references/thumbs/df8265009e.jpg +0 -0
- package/kb/references/thumbs/dfc99a1e8e.jpg +0 -0
- package/kb/references/thumbs/dfc9fde460.jpg +0 -0
- package/kb/references/thumbs/e038348eee.jpg +0 -0
- package/kb/references/thumbs/e04c2ae1d5.jpg +0 -0
- package/kb/references/thumbs/e070345c43.jpg +0 -0
- package/kb/references/thumbs/e0a0c84d47.jpg +0 -0
- package/kb/references/thumbs/e0af1e6b9e.jpg +0 -0
- package/kb/references/thumbs/e1025942c4.jpg +0 -0
- package/kb/references/thumbs/e11b6f5b82.jpg +0 -0
- package/kb/references/thumbs/e1553de3fc.jpg +0 -0
- package/kb/references/thumbs/e162ebe7cd.jpg +0 -0
- package/kb/references/thumbs/e1f1e531d8.jpg +0 -0
- package/kb/references/thumbs/e20842e5c9.jpg +0 -0
- package/kb/references/thumbs/e24e7d949b.jpg +0 -0
- package/kb/references/thumbs/e2a3e5d10a.jpg +0 -0
- package/kb/references/thumbs/e2de02615a.jpg +0 -0
- package/kb/references/thumbs/e305dad7dd.jpg +0 -0
- package/kb/references/thumbs/e52e3ef97f.jpg +0 -0
- package/kb/references/thumbs/e570e92d06.jpg +0 -0
- package/kb/references/thumbs/e583932fb9.jpg +0 -0
- package/kb/references/thumbs/e5da3c038f.jpg +0 -0
- package/kb/references/thumbs/e657634af3.jpg +0 -0
- package/kb/references/thumbs/e67946e3e1.jpg +0 -0
- package/kb/references/thumbs/e69e0f3639.jpg +0 -0
- package/kb/references/thumbs/e6ebe66031.jpg +0 -0
- package/kb/references/thumbs/e7db9563c9.jpg +0 -0
- package/kb/references/thumbs/e84a4c3b7b.jpg +0 -0
- package/kb/references/thumbs/e84cf52c27.jpg +0 -0
- package/kb/references/thumbs/e8707cf6e8.jpg +0 -0
- package/kb/references/thumbs/e888890b40.jpg +0 -0
- package/kb/references/thumbs/e8a502b418.jpg +0 -0
- package/kb/references/thumbs/e8ba68371d.jpg +0 -0
- package/kb/references/thumbs/e9098f54cc.jpg +0 -0
- package/kb/references/thumbs/e9144deae9.jpg +0 -0
- package/kb/references/thumbs/e93e98d757.jpg +0 -0
- package/kb/references/thumbs/e9762dd435.jpg +0 -0
- package/kb/references/thumbs/e9db4544c8.jpg +0 -0
- package/kb/references/thumbs/e9ddffeacd.jpg +0 -0
- package/kb/references/thumbs/e9e2cf1d7e.jpg +0 -0
- package/kb/references/thumbs/ea1e23e623.jpg +0 -0
- package/kb/references/thumbs/ea41200f5e.jpg +0 -0
- package/kb/references/thumbs/eaf4916e1a.jpg +0 -0
- package/kb/references/thumbs/eb2c505fc8.jpg +0 -0
- package/kb/references/thumbs/eb47943693.jpg +0 -0
- package/kb/references/thumbs/eb4ffd6625.jpg +0 -0
- package/kb/references/thumbs/eb82ac0a4d.jpg +0 -0
- package/kb/references/thumbs/ebeb345ade.jpg +0 -0
- package/kb/references/thumbs/ec4e2aba0a.jpg +0 -0
- package/kb/references/thumbs/ed683bc9f7.jpg +0 -0
- package/kb/references/thumbs/ed9e236a84.jpg +0 -0
- package/kb/references/thumbs/ee45e1caea.jpg +0 -0
- package/kb/references/thumbs/ee50bbf2e7.jpg +0 -0
- package/kb/references/thumbs/eed6ad3b7b.jpg +0 -0
- package/kb/references/thumbs/eee247fd70.jpg +0 -0
- package/kb/references/thumbs/ef87b6cb99.jpg +0 -0
- package/kb/references/thumbs/ef87dccf04.jpg +0 -0
- package/kb/references/thumbs/ef941bba1e.jpg +0 -0
- package/kb/references/thumbs/effc14fb2c.jpg +0 -0
- package/kb/references/thumbs/f04aa5a191.jpg +0 -0
- package/kb/references/thumbs/f13f12485f.jpg +0 -0
- package/kb/references/thumbs/f16a5c0fd4.jpg +0 -0
- package/kb/references/thumbs/f1ba7a7a8f.jpg +0 -0
- package/kb/references/thumbs/f1bc4c9c19.jpg +0 -0
- package/kb/references/thumbs/f1ee827878.jpg +0 -0
- package/kb/references/thumbs/f21736aeff.jpg +0 -0
- package/kb/references/thumbs/f22bc41213.jpg +0 -0
- package/kb/references/thumbs/f266aaffcc.jpg +0 -0
- package/kb/references/thumbs/f2c0ed0d65.jpg +0 -0
- package/kb/references/thumbs/f32ac710fd.jpg +0 -0
- package/kb/references/thumbs/f32b697ff6.jpg +0 -0
- package/kb/references/thumbs/f39c883904.jpg +0 -0
- package/kb/references/thumbs/f3b9d55e6e.jpg +0 -0
- package/kb/references/thumbs/f3c1763e14.jpg +0 -0
- package/kb/references/thumbs/f40853fd43.jpg +0 -0
- package/kb/references/thumbs/f4fd07dc4d.jpg +0 -0
- package/kb/references/thumbs/f50b756ee5.jpg +0 -0
- package/kb/references/thumbs/f51272e9b3.jpg +0 -0
- package/kb/references/thumbs/f538895eee.jpg +0 -0
- package/kb/references/thumbs/f5d28081b5.jpg +0 -0
- package/kb/references/thumbs/f6046c9501.jpg +0 -0
- package/kb/references/thumbs/f62e4af316.jpg +0 -0
- package/kb/references/thumbs/f6f6bffeb8.jpg +0 -0
- package/kb/references/thumbs/f736e00af6.jpg +0 -0
- package/kb/references/thumbs/f7932da47d.jpg +0 -0
- package/kb/references/thumbs/f879e118ca.jpg +0 -0
- package/kb/references/thumbs/f88257215d.jpg +0 -0
- package/kb/references/thumbs/f88c45a6d7.jpg +0 -0
- package/kb/references/thumbs/f89a7b646e.jpg +0 -0
- package/kb/references/thumbs/f8a1e7a274.jpg +0 -0
- package/kb/references/thumbs/f9183cf2b6.jpg +0 -0
- package/kb/references/thumbs/f995de5ce9.jpg +0 -0
- package/kb/references/thumbs/f9ada2c3e1.jpg +0 -0
- package/kb/references/thumbs/f9d4616f89.jpg +0 -0
- package/kb/references/thumbs/f9f4307bb0.jpg +0 -0
- package/kb/references/thumbs/fa070122c7.jpg +0 -0
- package/kb/references/thumbs/fa29cc1369.jpg +0 -0
- package/kb/references/thumbs/fa791a4dab.jpg +0 -0
- package/kb/references/thumbs/fa8060509e.jpg +0 -0
- package/kb/references/thumbs/fafeed4003.jpg +0 -0
- package/kb/references/thumbs/fb1c024f38.jpg +0 -0
- package/kb/references/thumbs/fb77aa28b3.jpg +0 -0
- package/kb/references/thumbs/fb9f7f1966.jpg +0 -0
- package/kb/references/thumbs/fba8a8c2da.jpg +0 -0
- package/kb/references/thumbs/fce2754c36.jpg +0 -0
- package/kb/references/thumbs/fce2fb83df.jpg +0 -0
- package/kb/references/thumbs/fd4c51bb47.jpg +0 -0
- package/kb/references/thumbs/fd8c269817.jpg +0 -0
- package/kb/references/thumbs/fdb7b250ca.jpg +0 -0
- package/kb/references/thumbs/fe18088de8.jpg +0 -0
- package/kb/references/thumbs/fe4f742ba7.jpg +0 -0
- package/kb/references/thumbs/fe64742ce7.jpg +0 -0
- package/kb/references/thumbs/feb5d62161.jpg +0 -0
- package/kb/references/thumbs/fed21b3e98.jpg +0 -0
- package/kb/references/thumbs/fed2205951.jpg +0 -0
- package/kb/references/thumbs/ffdacf1715.jpg +0 -0
- package/kb/sections/_buttons.md +93 -0
- package/kb/sections/_finish.md +325 -0
- package/kb/sections/about-founder-note.md +85 -0
- package/kb/sections/about-team-roster.md +86 -0
- package/kb/sections/alternating-rows-live-tiles.md +110 -0
- package/kb/sections/annotated-product-shot.md +105 -0
- package/kb/sections/asymmetric-bento-dominant.md +114 -0
- package/kb/sections/before-after-features.md +104 -0
- package/kb/sections/before-after-repair.md +107 -0
- package/kb/sections/bento-lead-tile.md +112 -0
- package/kb/sections/book-a-slot-honest.md +116 -0
- package/kb/sections/capability-prompt-ledger.md +68 -0
- package/kb/sections/case-study-band.md +113 -0
- package/kb/sections/centred-stack-hero.md +107 -0
- package/kb/sections/closing-demo-final-state.md +81 -0
- package/kb/sections/closing-full-bleed-line-and-form.md +86 -0
- package/kb/sections/closing-result-previewed.md +88 -0
- package/kb/sections/closing-three-real-steps.md +87 -0
- package/kb/sections/command-reference-table.md +70 -0
- package/kb/sections/comparison-old-way-bars.md +88 -0
- package/kb/sections/comparison-same-task-two-ways.md +88 -0
- package/kb/sections/day-of-the-place.md +102 -0
- package/kb/sections/docs-reading-rail.md +88 -0
- package/kb/sections/editorial-columns-hero.md +107 -0
- package/kb/sections/editorial-essay-pull-quote.md +112 -0
- package/kb/sections/events-calendar-list.md +107 -0
- package/kb/sections/explorable-control-demo.md +102 -0
- package/kb/sections/faq-open-answers-editorial.md +85 -0
- package/kb/sections/faq-ruled-accordion-aside.md +87 -0
- package/kb/sections/footer-closing-scene.md +84 -0
- package/kb/sections/footer-editorial-sitemap.md +85 -0
- package/kb/sections/footer-minimal-credits.md +80 -0
- package/kb/sections/full-bleed-image-band.md +103 -0
- package/kb/sections/full-bleed-image-hero.md +105 -0
- package/kb/sections/gallery-first-hero.md +109 -0
- package/kb/sections/horizontal-scroll-strip.md +101 -0
- package/kb/sections/how-i-work-own-voice.md +111 -0
- package/kb/sections/how-it-works-in-place.md +109 -0
- package/kb/sections/impact-numbers-sourced.md +109 -0
- package/kb/sections/install-steps-per-agent.md +77 -0
- package/kb/sections/masonry-real-work.md +109 -0
- package/kb/sections/numbered-editorial-columns.md +105 -0
- package/kb/sections/object-first-hero.md +106 -0
- package/kb/sections/object-timeline.md +105 -0
- package/kb/sections/one-huge-number.md +100 -0
- package/kb/sections/one-person-story.md +103 -0
- package/kb/sections/order-ahead-ticket.md +119 -0
- package/kb/sections/press-strip-quoted.md +106 -0
- package/kb/sections/pricing-comparison-table-sticky.md +94 -0
- package/kb/sections/pricing-free-pro-upgrade-moment.md +85 -0
- package/kb/sections/pricing-plan-beside-product.md +88 -0
- package/kb/sections/pricing-plans-ledger.md +94 -0
- package/kb/sections/pricing-usage-calculator.md +93 -0
- package/kb/sections/printed-menu-card.md +110 -0
- package/kb/sections/process-happening.md +102 -0
- package/kb/sections/project-index-ruled.md +106 -0
- package/kb/sections/proof-logo-cloud-with-reasons.md +82 -0
- package/kb/sections/proof-measured-numbers.md +88 -0
- package/kb/sections/proof-output-wall.md +84 -0
- package/kb/sections/proof-single-honest-quote.md +81 -0
- package/kb/sections/resources-searchable-list.md +110 -0
- package/kb/sections/rooms-and-rates.md +107 -0
- package/kb/sections/ruled-facts-table.md +108 -0
- package/kb/sections/ruled-list-pinned-visual.md +107 -0
- package/kb/sections/scroll-scrubbed-product-demo.md +103 -0
- package/kb/sections/self-playing-run-demo.md +104 -0
- package/kb/sections/services-price-ledger.md +106 -0
- package/kb/sections/signup-form-with-next-steps.md +86 -0
- package/kb/sections/signup-waitlist-place-in-line.md +90 -0
- package/kb/sections/spec-sheet-features.md +108 -0
- package/kb/sections/split-hero-live-object.md +108 -0
- package/kb/sections/sticky-feature-narrative.md +104 -0
- package/kb/sections/todays-board-hero.md +112 -0
- package/kb/sections/touchable-tool-hero.md +111 -0
- package/kb/sections/typographic-statement-hero.md +99 -0
- package/kb/sections/visit-hours-map.md +110 -0
- package/kb/sections/ways-to-help-honest.md +115 -0
- package/kb/sources/design-reference.md +991 -0
- package/kb/sources/product-and-docs.md +37 -0
- package/kb/systems/1win/DESIGN.md +463 -0
- package/kb/systems/LICENSE-awesome-design-md +21 -0
- package/kb/systems/README.md +7 -0
- package/kb/systems/airbnb/DESIGN.md +545 -0
- package/kb/systems/airtable/DESIGN.md +554 -0
- package/kb/systems/aljazeera/DESIGN.md +594 -0
- package/kb/systems/apple/DESIGN.md +562 -0
- package/kb/systems/binance/DESIGN.md +634 -0
- package/kb/systems/bmw/DESIGN.md +544 -0
- package/kb/systems/bmw-m/DESIGN.md +503 -0
- package/kb/systems/bugatti/DESIGN.md +454 -0
- package/kb/systems/cal/DESIGN.md +542 -0
- package/kb/systems/categories.json +87 -0
- package/kb/systems/claude/DESIGN.md +589 -0
- package/kb/systems/clay/DESIGN.md +541 -0
- package/kb/systems/clickhouse/DESIGN.md +544 -0
- package/kb/systems/cohere/DESIGN.md +451 -0
- package/kb/systems/coinbase/DESIGN.md +570 -0
- package/kb/systems/composio/DESIGN.md +506 -0
- package/kb/systems/cursor/DESIGN.md +537 -0
- package/kb/systems/dell-1996/DESIGN.md +632 -0
- package/kb/systems/dji/DESIGN.md +882 -0
- package/kb/systems/elevenlabs/DESIGN.md +504 -0
- package/kb/systems/expo/DESIGN.md +526 -0
- package/kb/systems/ferrari/DESIGN.md +531 -0
- package/kb/systems/figma/DESIGN.md +578 -0
- package/kb/systems/framer/DESIGN.md +544 -0
- package/kb/systems/hashicorp/DESIGN.md +575 -0
- package/kb/systems/hp/DESIGN.md +670 -0
- package/kb/systems/ibm/DESIGN.md +550 -0
- package/kb/systems/intercom/DESIGN.md +546 -0
- package/kb/systems/jobright/DESIGN.md +525 -0
- package/kb/systems/kraken/DESIGN.md +125 -0
- package/kb/systems/lamborghini/DESIGN.md +288 -0
- package/kb/systems/linear.app/DESIGN.md +548 -0
- package/kb/systems/lovable/DESIGN.md +298 -0
- package/kb/systems/mastercard/DESIGN.md +365 -0
- package/kb/systems/mercury/DESIGN.md +568 -0
- package/kb/systems/meta/DESIGN.md +683 -0
- package/kb/systems/minimax/DESIGN.md +746 -0
- package/kb/systems/mintlify/DESIGN.md +852 -0
- package/kb/systems/miro/DESIGN.md +825 -0
- package/kb/systems/mistral.ai/DESIGN.md +773 -0
- package/kb/systems/mongodb/DESIGN.md +767 -0
- package/kb/systems/mydealz/DESIGN.md +551 -0
- package/kb/systems/nerdwallet/DESIGN.md +722 -0
- package/kb/systems/nike/DESIGN.md +575 -0
- package/kb/systems/nintendo-2001/DESIGN.md +649 -0
- package/kb/systems/notion/DESIGN.md +821 -0
- package/kb/systems/nvidia/DESIGN.md +640 -0
- package/kb/systems/ollama/DESIGN.md +539 -0
- package/kb/systems/opencode.ai/DESIGN.md +521 -0
- package/kb/systems/oracle/DESIGN.md +778 -0
- package/kb/systems/oura/DESIGN.md +616 -0
- package/kb/systems/pinterest/DESIGN.md +597 -0
- package/kb/systems/playstation/DESIGN.md +661 -0
- package/kb/systems/posthog/DESIGN.md +690 -0
- package/kb/systems/raycast/DESIGN.md +669 -0
- package/kb/systems/renault/DESIGN.md +589 -0
- package/kb/systems/replicate/DESIGN.md +616 -0
- package/kb/systems/resend/DESIGN.md +585 -0
- package/kb/systems/revolut/DESIGN.md +636 -0
- package/kb/systems/runwayml/DESIGN.md +244 -0
- package/kb/systems/sanity/DESIGN.md +357 -0
- package/kb/systems/sap/DESIGN.md +639 -0
- package/kb/systems/sentry/DESIGN.md +551 -0
- package/kb/systems/shopify/DESIGN.md +516 -0
- package/kb/systems/slack/DESIGN.md +482 -0
- package/kb/systems/spacex/DESIGN.md +363 -0
- package/kb/systems/spotify/DESIGN.md +246 -0
- package/kb/systems/starbucks/DESIGN.md +580 -0
- package/kb/systems/stripe/DESIGN.md +487 -0
- package/kb/systems/supabase/DESIGN.md +462 -0
- package/kb/systems/superhuman/DESIGN.md +448 -0
- package/kb/systems/tesla/DESIGN.md +286 -0
- package/kb/systems/theverge/DESIGN.md +339 -0
- package/kb/systems/together.ai/DESIGN.md +633 -0
- package/kb/systems/uber/DESIGN.md +636 -0
- package/kb/systems/vercel/DESIGN.md +736 -0
- package/kb/systems/vodafone/DESIGN.md +538 -0
- package/kb/systems/voltagent/DESIGN.md +521 -0
- package/kb/systems/warp/DESIGN.md +526 -0
- package/kb/systems/webflow/DESIGN.md +588 -0
- package/kb/systems/wired/DESIGN.md +497 -0
- package/kb/systems/wise/DESIGN.md +544 -0
- package/kb/systems/x.ai/DESIGN.md +465 -0
- package/kb/systems/zapier/DESIGN.md +537 -0
- package/kb/taste/garvit-by-job.md +46 -0
- package/kb/taste/garvit-portfolio.md +94 -0
- package/kb/universal/color-roles.md +26 -0
- package/kb/universal/copy.md +16 -0
- package/kb/universal/details.md +31 -0
- package/kb/universal/first-screen.md +30 -0
- package/kb/universal/fit-the-codebase.md +29 -0
- package/kb/universal/layout-width.md +28 -0
- package/kb/universal/motion-feedback.md +23 -0
- package/kb/universal/signature.md +29 -0
- package/kb/universal/states.md +17 -0
- package/kb/universal/type-app.md +33 -0
- package/kb/universal/type-marketing.md +28 -0
- package/package.json +36 -4
- package/scripts/pack-assets.mjs +48 -0
- package/skill/palate/SKILL.md +261 -0
- package/src/auth-recheck.mjs +4 -0
- package/src/auth.mjs +416 -0
- package/src/capture.mjs +182 -0
- package/src/catalog/classify.mjs +96 -0
- package/src/catalog/curated.mjs +128 -0
- package/src/catalog/index-build.mjs +67 -0
- package/src/catalog/literal.mjs +146 -0
- package/src/catalog/store.mjs +40 -0
- package/src/catalog/vibrant.mjs +126 -0
- package/src/check.mjs +93 -0
- package/src/concept.mjs +157 -0
- package/src/context.mjs +226 -0
- package/src/copy.mjs +188 -0
- package/src/devserver.mjs +135 -0
- package/src/fontgenre.mjs +44 -0
- package/src/guard-agents.mjs +213 -0
- package/src/guard.mjs +377 -0
- package/src/kb.mjs +91 -0
- package/src/look.mjs +312 -0
- package/src/loop/ambition.mjs +620 -0
- package/src/loop/animate.mjs +70 -0
- package/src/loop/artdirection.mjs +264 -0
- package/src/loop/bench.mjs +184 -0
- package/src/loop/benchpick.mjs +155 -0
- package/src/loop/blueprint.mjs +620 -0
- package/src/loop/board.html +180 -0
- package/src/loop/build.mjs +393 -0
- package/src/loop/buttons.mjs +413 -0
- package/src/loop/common.mjs +206 -0
- package/src/loop/cost.mjs +63 -0
- package/src/loop/craft.mjs +152 -0
- package/src/loop/craftchecks.mjs +148 -0
- package/src/loop/critique.mjs +393 -0
- package/src/loop/details.mjs +225 -0
- package/src/loop/direction.html +168 -0
- package/src/loop/direction.mjs +256 -0
- package/src/loop/directions.json +8 -0
- package/src/loop/explore.mjs +219 -0
- package/src/loop/fail.mjs +110 -0
- package/src/loop/fix.mjs +194 -0
- package/src/loop/floor.mjs +677 -0
- package/src/loop/forget.mjs +52 -0
- package/src/loop/gate.mjs +1053 -0
- package/src/loop/grid.html +123 -0
- package/src/loop/growth.mjs +118 -0
- package/src/loop/icons.mjs +109 -0
- package/src/loop/imagery.mjs +1280 -0
- package/src/loop/judge-api.mjs +245 -0
- package/src/loop/judge.mjs +167 -0
- package/src/loop/layouts.mjs +492 -0
- package/src/loop/library.mjs +82 -0
- package/src/loop/lookplan.mjs +182 -0
- package/src/loop/lookvec.mjs +645 -0
- package/src/loop/match.mjs +923 -0
- package/src/loop/matched.mjs +26 -0
- package/src/loop/myrefs.mjs +151 -0
- package/src/loop/pick.mjs +213 -0
- package/src/loop/picker.html +118 -0
- package/src/loop/plan.mjs +289 -0
- package/src/loop/polish.mjs +39 -0
- package/src/loop/research-learn.mjs +41 -0
- package/src/loop/research.mjs +1130 -0
- package/src/loop/rulereview.mjs +146 -0
- package/src/loop/rules-board.html +199 -0
- package/src/loop/rules.mjs +939 -0
- package/src/loop/similar.mjs +276 -0
- package/src/loop/states-source.mjs +258 -0
- package/src/loop/states.mjs +1547 -0
- package/src/loop/stats.mjs +78 -0
- package/src/loop/taste.mjs +81 -0
- package/src/loop/timeline.mjs +149 -0
- package/src/loop/variants.mjs +228 -0
- package/src/loop/vary.mjs +249 -0
- package/src/mcp/server.mjs +1246 -0
- package/src/motion.mjs +207 -0
- package/src/moves.mjs +242 -0
- package/src/novelty.mjs +116 -0
- package/src/page-ambition.js +181 -0
- package/src/page-craft.js +724 -0
- package/src/page-details.js +415 -0
- package/src/page-devices.js +365 -0
- package/src/page-fingerprint.js +281 -0
- package/src/page-gate.js +1307 -0
- package/src/page-look.js +698 -0
- package/src/page-metrics.js +78 -0
- package/src/page-principles.js +1167 -0
- package/src/page-rules.js +308 -0
- package/src/page-sections.js +211 -0
- package/src/page-states.js +703 -0
- package/src/paths.mjs +13 -0
- package/src/png.mjs +107 -0
- package/src/point/auto.mjs +224 -0
- package/src/point/locate.mjs +114 -0
- package/src/point/overlay.js +1516 -0
- package/src/point/server.mjs +1122 -0
- package/src/point/trail.mjs +219 -0
- package/src/pool.mjs +80 -0
- package/src/principles.mjs +279 -0
- package/src/refs.mjs +299 -0
- package/src/robots.mjs +145 -0
- package/src/sections.mjs +210 -0
- package/src/shoot.mjs +235 -0
- package/src/systems/apply.mjs +355 -0
- package/src/systems/load.mjs +251 -0
- package/src/systems/pick.mjs +213 -0
- package/templates/vite-react-tw/index.html +12 -0
- package/templates/vite-react-tw/package.json +25 -0
- package/templates/vite-react-tw/src/App.tsx +3 -0
- package/templates/vite-react-tw/src/index.css +1 -0
- package/templates/vite-react-tw/src/main.tsx +10 -0
- package/templates/vite-react-tw/tsconfig.app.json +26 -0
- package/templates/vite-react-tw/tsconfig.json +7 -0
- package/templates/vite-react-tw/tsconfig.node.json +23 -0
- package/templates/vite-react-tw/vite.config.ts +8 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
// Runs inside the page (read as text and evaluated with an op and its argument). The stateful parts of a
|
|
2
|
+
// screen and how each holds up in a state:
|
|
3
|
+
// find lists, tables and card grids, forms, numbers, images and text that comes from data, plus buttons
|
|
4
|
+
// that may act; marks each with data-palate-c so the same render can find it again
|
|
5
|
+
// mark finds the same parts again in another render (by selector, then by their items' signature)
|
|
6
|
+
// measure per part: items, overflow and clipping, layout breaks, empty / error / loading messages that
|
|
7
|
+
// appeared, broken images; page-wide: sideways scroll, leaked "undefined", "1 items", the focus
|
|
8
|
+
// transform DOM-level states for data that is static in the code: long text, many items, one item
|
|
9
|
+
// texts every visible text, to tell what a state added
|
|
10
|
+
// focus where keyboard focus is, and whether it can be seen
|
|
11
|
+
(op, arg = {}) => {
|
|
12
|
+
const clean = (s) => (s ?? "").replace(/\s+/g, " ").trim();
|
|
13
|
+
const visible = (el) => {
|
|
14
|
+
if (!el || el.nodeType !== 1) return false;
|
|
15
|
+
const r = el.getBoundingClientRect();
|
|
16
|
+
const cs = getComputedStyle(el);
|
|
17
|
+
return r.width > 1 && r.height > 1 && cs.display !== "none" && cs.visibility !== "hidden" && parseFloat(cs.opacity) > 0.02;
|
|
18
|
+
};
|
|
19
|
+
const box = (el) => {
|
|
20
|
+
const r = el.getBoundingClientRect();
|
|
21
|
+
return { x: Math.round(r.left + scrollX), y: Math.round(r.top + scrollY), width: Math.round(r.width), height: Math.round(r.height) };
|
|
22
|
+
};
|
|
23
|
+
// Not data: navigation, menus, decorative miniatures, palate's own overlay.
|
|
24
|
+
const CHROME = "nav, header, footer, [role=navigation], [role=banner], [role=contentinfo], [role=tablist], [role=menu], [role=menubar], [role=listbox], [role=tree], select, datalist, svg, [aria-hidden=true], [inert], script, style, template, noscript, [data-palate-ignore]";
|
|
25
|
+
const stableId = (id) => id && !/^[:«]|^radix-|^headlessui-|^react-aria|:r[\w]*:|«|\d{4,}/.test(id) && document.querySelectorAll(`#${CSS.escape(id)}`).length === 1;
|
|
26
|
+
const selOf = (el) => {
|
|
27
|
+
const parts = [];
|
|
28
|
+
for (let e = el; e && e.nodeType === 1 && e !== document.body; e = e.parentElement) {
|
|
29
|
+
if (stableId(e.id)) {
|
|
30
|
+
parts.unshift(`#${CSS.escape(e.id)}`);
|
|
31
|
+
return parts.join(" > ");
|
|
32
|
+
}
|
|
33
|
+
let n = 1;
|
|
34
|
+
for (let s = e.previousElementSibling; s; s = s.previousElementSibling) if (s.tagName === e.tagName) n++;
|
|
35
|
+
parts.unshift(`${e.tagName.toLowerCase()}:nth-of-type(${n})`);
|
|
36
|
+
}
|
|
37
|
+
return ["body", ...parts].join(" > ");
|
|
38
|
+
};
|
|
39
|
+
const kidsOf = (p) => [...p.children].flatMap((k) => (getComputedStyle(k).display === "contents" ? kidsOf(k) : [k]));
|
|
40
|
+
const sigOf = (el) => `${el.tagName.toLowerCase()}${[...el.classList].filter((c) => /^[a-z_-][\w-]*$/i.test(c) && !/^(is-|active|selected|current|open|first|last|odd|even)/.test(c)).sort().slice(0, 5).map((c) => `.${c}`).join("")}`;
|
|
41
|
+
const shapeOf = (el) => [...el.children].slice(0, 4).map((c) => c.tagName).join(",");
|
|
42
|
+
const ownText = (el) => clean([...el.childNodes].filter((n) => n.nodeType === 3).map((n) => n.textContent).join(" "));
|
|
43
|
+
const EMPTY_RE = /\b(no \w+(?: \w+)? (?:yet|found|here|to show|available|match)|nothing (?:here|to show|yet|found)|is empty|empty|no results|no items|no data|get started|add (?:your|a|the) first|create (?:your|a|the) first|invite (?:your|a|the)? ?first|start by)\b|^no \w+/i;
|
|
44
|
+
const ERROR_RE = /\b(error|wrong|couldn.?t|could not|can.?t (?:load|reach|connect|save)|cannot|failed|failure|unable|problem|try again|retry|offline|no connection|connection (?:lost|failed)|went wrong|unavailable|timed? ?out|not respond)/i;
|
|
45
|
+
const LOADING_RE = /\b(loading|fetching|please wait|one moment|saving|sending|submitting|joining|inviting|working|uploading)\b|…$|\.\.\.$/i;
|
|
46
|
+
const CUES = "[aria-busy=true], [role=progressbar], progress, [class*=skeleton i], [class*=spinner i], [class*=loading i], [class*=loader i], [class*=shimmer i], [class*=placeholder-glow], .animate-pulse, .animate-spin, [data-loading], [data-state=loading], [data-pending]";
|
|
47
|
+
|
|
48
|
+
// Every visible element's own text, so a state's new text can be told from what was there before.
|
|
49
|
+
const allTexts = () => {
|
|
50
|
+
const out = [];
|
|
51
|
+
for (const el of document.body.querySelectorAll("*")) {
|
|
52
|
+
if (/^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE|svg)$/i.test(el.tagName) || el.closest("svg, [data-palate-ignore]")) continue;
|
|
53
|
+
const t = ownText(el);
|
|
54
|
+
if (t && t.length <= 300 && visible(el)) out.push({ t, el });
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const labelOf = (e) => clean(e.getAttribute("aria-label") || (e.getAttribute("aria-labelledby") && document.getElementById(e.getAttribute("aria-labelledby").split(/\s+/)[0])?.textContent) || "");
|
|
60
|
+
// The part's own name: its label, the heading just before it, or the label of the region it sits in. A
|
|
61
|
+
// labelled region is a boundary: the heading of the section next to it is not this part's.
|
|
62
|
+
const headingOf = (el) => {
|
|
63
|
+
if (labelOf(el)) return labelOf(el).slice(0, 60);
|
|
64
|
+
for (let e = el, k = 0; e && e !== document.body && k < 5; e = e.parentElement, k++) {
|
|
65
|
+
if (e !== el && e.matches("section, article, aside, form, fieldset, [role=region], [role=dialog], [role=group]") && labelOf(e)) return labelOf(e).slice(0, 60);
|
|
66
|
+
for (let s = e.previousElementSibling; s; s = s.previousElementSibling) {
|
|
67
|
+
const h = s.matches("h1, h2, h3, h4, h5, h6, [role=heading]") ? s : s.querySelector("h1, h2, h3, h4, h5, h6, [role=heading]");
|
|
68
|
+
if (h && clean(h.textContent)) return clean(h.textContent).slice(0, 60);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return "";
|
|
72
|
+
};
|
|
73
|
+
// Text that names another part (its heading, the label of its region, a legend or caption) is that part's
|
|
74
|
+
// label, not a part of its own.
|
|
75
|
+
const HEADING = "h1, h2, h3, h4, h5, h6, [role=heading], label, legend, caption, th, dt, figcaption";
|
|
76
|
+
const labelsAPart = (block, parts) => {
|
|
77
|
+
const t = clean(block.textContent);
|
|
78
|
+
if (block.id && document.querySelector(`[aria-labelledby~="${CSS.escape(block.id)}"], [aria-describedby~="${CSS.escape(block.id)}"]`)) return true;
|
|
79
|
+
if (!block.matches(HEADING)) return false;
|
|
80
|
+
return parts.some((p) => p.contains(block) || headingOf(p) === t.slice(0, 60) || (block.closest("section, article, aside, [role=region], form, fieldset") ?? document.body).contains(p) && block.closest("section, article, aside, [role=region], form, fieldset"));
|
|
81
|
+
};
|
|
82
|
+
const regionOf = (el) => {
|
|
83
|
+
const r = el.parentElement?.closest("section, article, aside, form, [role=region], [role=dialog], main > *, li, td");
|
|
84
|
+
return r && r !== document.body && r.getBoundingClientRect().height < Math.max(innerHeight * 2.5, 2000) ? r : el.parentElement?.parentElement ?? el.parentElement ?? el;
|
|
85
|
+
};
|
|
86
|
+
const surface = (el) => {
|
|
87
|
+
const cs = getComputedStyle(el);
|
|
88
|
+
return (cs.backgroundColor !== "rgba(0, 0, 0, 0)" && cs.backgroundColor !== "transparent") || parseFloat(cs.borderTopWidth) > 0 || cs.boxShadow !== "none";
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// A collection: a container whose visible children are mostly the same kind of item (same tag and classes,
|
|
92
|
+
// same inner shape), each with text or a picture. The outermost such container wins.
|
|
93
|
+
const collections = () => {
|
|
94
|
+
const cands = [];
|
|
95
|
+
for (const el of document.body.querySelectorAll("*")) {
|
|
96
|
+
if (/^(P|H[1-6]|SPAN|A|BUTTON|LABEL|TR|IMG|PICTURE|BODY|MAIN|SELECT|OPTION|svg|path|g|INPUT|TEXTAREA|CODE|PRE)$/i.test(el.tagName)) continue;
|
|
97
|
+
if (el.closest(CHROME) || !visible(el)) continue;
|
|
98
|
+
const kids = kidsOf(el).filter((k) => !/^(SCRIPT|STYLE|TEMPLATE|BR|HR|LINK)$/.test(k.tagName) && visible(k));
|
|
99
|
+
const listy = /^(UL|OL|TBODY|DL)$/.test(el.tagName) || /^(list|grid|feed|rowgroup|table)$/.test(el.getAttribute("role") || "");
|
|
100
|
+
const min = listy ? 2 : 3;
|
|
101
|
+
if (kids.length < min) continue;
|
|
102
|
+
const counts = new Map();
|
|
103
|
+
for (const k of kids) counts.set(sigOf(k), (counts.get(sigOf(k)) || 0) + 1);
|
|
104
|
+
const [sig, n] = [...counts].sort((a, b) => b[1] - a[1])[0];
|
|
105
|
+
if (n < min || n < kids.length * 0.6) continue;
|
|
106
|
+
const items = kids.filter((k) => sigOf(k) === sig);
|
|
107
|
+
if (items.some((k) => /^(SECTION|MAIN|HEADER|FOOTER|NAV|ASIDE|FORM)$/.test(k.tagName))) continue;
|
|
108
|
+
const leaf = items.every((k) => !k.children.length || /^(P|H[1-6]|SPAN|EM|STRONG|A|CODE|B|I|SMALL|BUTTON)$/.test(k.tagName));
|
|
109
|
+
if (leaf && !listy) continue;
|
|
110
|
+
// The same inner shape: page blocks that only share a class don't count.
|
|
111
|
+
const shapes = new Map();
|
|
112
|
+
for (const k of items) shapes.set(shapeOf(k), (shapes.get(shapeOf(k)) || 0) + 1);
|
|
113
|
+
if (Math.max(...shapes.values()) < items.length * 0.6) continue;
|
|
114
|
+
const rects = items.map((k) => k.getBoundingClientRect());
|
|
115
|
+
if (rects.some((b) => b.height > Math.max(innerHeight * 0.9, 760))) continue;
|
|
116
|
+
if (rects.reduce((a, b) => a + b.width * b.height, 0) < 3000) continue;
|
|
117
|
+
if (!items.every((k) => clean(k.textContent) || k.querySelector("img, picture, canvas, video, svg"))) continue;
|
|
118
|
+
cands.push({ el, items, sig, shape: [...shapes].sort((a, b) => b[1] - a[1])[0][0], listy });
|
|
119
|
+
}
|
|
120
|
+
return cands.filter((c) => !cands.some((o) => o !== c && o.items.some((it) => it.contains(c.el))));
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const kindOf = (c) => {
|
|
124
|
+
const el = c.el;
|
|
125
|
+
if (/^(TBODY|TABLE)$/.test(el.tagName) || /rowgroup|table/.test(el.getAttribute("role") || "")) return "table";
|
|
126
|
+
const tops = new Set(c.items.map((k) => Math.round(k.getBoundingClientRect().top)));
|
|
127
|
+
const lefts = new Set(c.items.map((k) => Math.round(k.getBoundingClientRect().left)));
|
|
128
|
+
if (c.items.filter(surface).length >= c.items.length * 0.6) return tops.size > 1 && lefts.size > 1 ? "cards" : lefts.size > 1 ? "cards" : "list";
|
|
129
|
+
return tops.size > 1 && lefts.size > 1 ? "grid" : "list";
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const describe = (el) => {
|
|
133
|
+
if (!el) return null;
|
|
134
|
+
const t = clean(el.getAttribute?.("aria-label") || el.textContent || el.value || el.getAttribute?.("placeholder") || "").slice(0, 50);
|
|
135
|
+
return `<${el.tagName.toLowerCase()}${el.id && stableId(el.id) ? `#${el.id}` : ""}>${t ? ` "${t}"` : ""}`;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Where a focused control that can't be seen itself shows its focus: its label, the label around it, its
|
|
139
|
+
// wrapper or a sibling (and what they hold), compared focused and blurred with transitions off. Focus is
|
|
140
|
+
// put back as it was. The first visible element whose paint changed, or null.
|
|
141
|
+
const focusShownOn = (a) => {
|
|
142
|
+
const near = new Set([...(a.labels ?? []), a.closest("label"), a.parentElement, a.nextElementSibling, a.previousElementSibling].filter((e) => e && e !== document.body));
|
|
143
|
+
const cands = [];
|
|
144
|
+
for (const e of near) for (const x of [e, ...e.querySelectorAll("*")].slice(0, 12)) if (x !== a && !cands.includes(x)) cands.push(x);
|
|
145
|
+
const props = (c) => [c.outlineStyle, c.outlineWidth, c.outlineColor, c.boxShadow, c.borderTopColor, c.borderBottomColor, c.borderTopWidth, c.backgroundColor, c.backgroundImage, c.color, c.textDecorationLine, c.opacity, c.transform].join("|");
|
|
146
|
+
const paint = (x) => [props(getComputedStyle(x)), ...["::before", "::after"].map((p) => getComputedStyle(x, p)).filter((c) => c.content && c.content !== "none" && c.content !== "normal").map(props)].join("~");
|
|
147
|
+
const still = document.createElement("style");
|
|
148
|
+
still.setAttribute("data-palate-ignore", "");
|
|
149
|
+
still.textContent = "*, *::before, *::after { transition: none !important; animation-play-state: paused !important; }";
|
|
150
|
+
document.head.appendChild(still);
|
|
151
|
+
try {
|
|
152
|
+
const on = cands.map(paint);
|
|
153
|
+
a.blur();
|
|
154
|
+
const off = cands.map(paint);
|
|
155
|
+
a.focus({ preventScroll: true, focusVisible: true });
|
|
156
|
+
return cands.find((x, i) => on[i] !== off[i] && visible(x)) ?? null;
|
|
157
|
+
} finally {
|
|
158
|
+
if (document.activeElement !== a) a.focus({ preventScroll: true });
|
|
159
|
+
still.remove();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
if (op === "texts") return [...new Set(allTexts().map((x) => x.t))].slice(0, 4000);
|
|
164
|
+
|
|
165
|
+
if (op === "find") {
|
|
166
|
+
const out = [];
|
|
167
|
+
const taken = [];
|
|
168
|
+
const cols = collections()
|
|
169
|
+
.sort((a, b) => b.el.getBoundingClientRect().width * b.el.getBoundingClientRect().height - a.el.getBoundingClientRect().width * a.el.getBoundingClientRect().height)
|
|
170
|
+
.slice(0, 10)
|
|
171
|
+
.sort((a, b) => (a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1));
|
|
172
|
+
for (const c of cols) {
|
|
173
|
+
const kind = kindOf(c);
|
|
174
|
+
out.push({ el: c.el, kind, sig: c.sig, shape: c.shape, count: c.items.length, itemBox: box(c.items[0]), texts: c.items.slice(0, 3).map((k) => clean(k.textContent).slice(0, 80)), images: c.el.querySelectorAll("img").length });
|
|
175
|
+
taken.push(c.el);
|
|
176
|
+
}
|
|
177
|
+
const inTaken = (el) => taken.some((t) => t.contains(el));
|
|
178
|
+
// Forms, and inputs with a button beside them outside any form. Same-looking forms are tested once.
|
|
179
|
+
const forms = [];
|
|
180
|
+
for (const f of document.querySelectorAll("form")) if (visible(f) && !f.closest("[aria-hidden=true], [inert], [data-palate-ignore]")) forms.push({ el: f, orphan: false });
|
|
181
|
+
for (const i of document.querySelectorAll("input:not([type=hidden]):not([type=checkbox]):not([type=radio]), textarea")) {
|
|
182
|
+
if (i.closest("form") || !visible(i) || i.closest(CHROME)) continue;
|
|
183
|
+
// A live filter (a search box over a list, filter chips beside it) has nothing to submit or fail.
|
|
184
|
+
if (i.type === "search" || i.closest("[role=search]")) continue;
|
|
185
|
+
let g = i.parentElement;
|
|
186
|
+
for (let k = 0; g && k < 3 && !g.querySelector("button"); k++) g = g.parentElement;
|
|
187
|
+
if (g?.querySelector("button") && !forms.some((f) => f.el.contains(g) || g.contains(f.el))) forms.push({ el: g, orphan: true });
|
|
188
|
+
}
|
|
189
|
+
for (const f of forms.slice(0, 4)) {
|
|
190
|
+
const fields = [...f.el.querySelectorAll("input:not([type=hidden]):not([type=submit]):not([type=button]), textarea, select")].filter(visible).map((x) => ({ sel: selOf(x), type: x.tagName === "INPUT" ? x.type : x.tagName.toLowerCase(), name: x.name || x.id || "", required: x.required || x.getAttribute("aria-required") === "true", label: clean(x.labels?.[0]?.textContent || x.getAttribute("aria-label") || x.placeholder || "").slice(0, 40), rules: { pattern: x.getAttribute("pattern") || null, minLength: x.minLength > 0 ? x.minLength : null, maxLength: x.maxLength > 0 ? x.maxLength : null, inputMode: x.getAttribute("inputmode") || null, autocomplete: x.getAttribute("autocomplete") || null, placeholder: x.placeholder || null, min: x.getAttribute("min"), max: x.getAttribute("max") } }));
|
|
191
|
+
const submit = f.el.querySelector("button[type=submit], input[type=submit], button:not([type])") ?? f.el.querySelector("button");
|
|
192
|
+
if (!fields.length || !submit) continue;
|
|
193
|
+
const name = clean(f.el.getAttribute("aria-label") || f.el.querySelector("legend, h2, h3, h4")?.textContent || f.el.querySelector("label")?.textContent || "").slice(0, 60);
|
|
194
|
+
out.push({ el: f.el, kind: "form", name, texts: [name, clean(submit.textContent || submit.value)].filter(Boolean), orphan: f.orphan, fields, submit: selOf(submit), submitText: clean(submit.textContent || submit.value).slice(0, 40), noValidate: Boolean(f.el.noValidate), formSig: `${fields.map((x) => x.type).join(",")}|${clean(submit.textContent)}` });
|
|
195
|
+
}
|
|
196
|
+
// Numbers set large (counters, totals), outside collections.
|
|
197
|
+
let nums = 0;
|
|
198
|
+
for (const el of document.body.querySelectorAll("*")) {
|
|
199
|
+
if (nums >= 4 || el.closest(CHROME) || inTaken(el)) continue;
|
|
200
|
+
const t = ownText(el);
|
|
201
|
+
if (!/^[$€£¥]?\s?\d[\d.,]*\s?(%|[kKmMbB]|\+)?$/.test(t) || parseFloat(getComputedStyle(el).fontSize) < 20 || !visible(el)) continue;
|
|
202
|
+
out.push({ el, kind: "number", texts: [t] });
|
|
203
|
+
nums++;
|
|
204
|
+
}
|
|
205
|
+
// Large standalone images.
|
|
206
|
+
let imgs = 0;
|
|
207
|
+
for (const im of document.querySelectorAll("img")) {
|
|
208
|
+
if (imgs >= 4 || im.closest(CHROME) || inTaken(im)) continue;
|
|
209
|
+
const r = im.getBoundingClientRect();
|
|
210
|
+
if (r.width < 100 || r.height < 60 || !visible(im)) continue;
|
|
211
|
+
out.push({ el: im, kind: "image", texts: [im.alt || ""] });
|
|
212
|
+
imgs++;
|
|
213
|
+
}
|
|
214
|
+
// Text that came from data (it matches a string the app fetched), outside collections and forms.
|
|
215
|
+
const data = new Set((arg.dataStrings ?? []).filter((s) => s.length >= 3));
|
|
216
|
+
if (data.size) {
|
|
217
|
+
const seen = new Set();
|
|
218
|
+
const parts = out.map((c) => c.el);
|
|
219
|
+
// A whole word or phrase from the data: "firing" (a status) is not in "This week's firings".
|
|
220
|
+
const escRe = (x) => x.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
221
|
+
const inText = (t, d) => t === d || (d.length >= 6 && new RegExp(`(^|[^\\w])${escRe(d)}($|[^\\w])`).test(t));
|
|
222
|
+
for (const { t, el } of allTexts()) {
|
|
223
|
+
if (seen.size >= 4 || inTaken(el) || el.closest("form") || el.closest(CHROME)) continue;
|
|
224
|
+
if (![...data].some((d) => inText(t, d))) continue;
|
|
225
|
+
const block = el.closest("p, h1, h2, h3, h4, h5, h6, li, dd, td, div") ?? el;
|
|
226
|
+
if (seen.has(block) || labelsAPart(block, parts) || labelsAPart(el, parts)) continue;
|
|
227
|
+
seen.add(block);
|
|
228
|
+
out.push({ el: block, kind: "text", texts: [t.slice(0, 80)] });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Buttons that may act (not submits, not navigation): tested by clicking, with the network mocked.
|
|
232
|
+
const actions = [...document.querySelectorAll("button:not([type=submit]), [role=button]")]
|
|
233
|
+
.filter((b) => visible(b) && !b.closest(CHROME) && !b.closest("form") && !b.matches(":disabled") && !b.closest("[aria-disabled=true]") && clean(b.textContent || b.getAttribute("aria-label")).length > 0)
|
|
234
|
+
.slice(0, 8)
|
|
235
|
+
.map((b) => ({ sel: selOf(b), text: clean(b.textContent || b.getAttribute("aria-label")).slice(0, 40) }));
|
|
236
|
+
const components = out.map((c, i) => {
|
|
237
|
+
const id = `C${i + 1}`;
|
|
238
|
+
c.el.setAttribute("data-palate-c", id);
|
|
239
|
+
const region = regionOf(c.el);
|
|
240
|
+
const { el, ...rest } = c;
|
|
241
|
+
return { id, ...rest, selector: selOf(el), region: selOf(region), heading: rest.name || headingOf(el), className: typeof el.className === "string" ? el.className.slice(0, 160) : "", box: box(el), tag: el.tagName.toLowerCase() };
|
|
242
|
+
});
|
|
243
|
+
return { components, actions, title: document.title };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (op === "mark") {
|
|
247
|
+
const res = {};
|
|
248
|
+
for (const c of arg.components ?? []) {
|
|
249
|
+
let el = document.querySelector(`[data-palate-c="${c.id}"]`);
|
|
250
|
+
let via = el ? "marked" : null;
|
|
251
|
+
if (!el) {
|
|
252
|
+
try {
|
|
253
|
+
el = document.querySelector(c.selector);
|
|
254
|
+
} catch {}
|
|
255
|
+
// The selector may now point at something else: for collections, its items must still look the same.
|
|
256
|
+
if (el && c.sig && !kidsOf(el).some((k) => sigOf(k) === c.sig) && kidsOf(el).length) el = null;
|
|
257
|
+
if (el && el.tagName.toLowerCase() !== c.tag) el = null;
|
|
258
|
+
via = el ? "selector" : null;
|
|
259
|
+
}
|
|
260
|
+
if (!el && c.sig) {
|
|
261
|
+
el = [...document.body.querySelectorAll(c.tag)].find((x) => !x.closest("[data-palate-ignore]") && kidsOf(x).filter((k) => sigOf(k) === c.sig).length >= 1) ?? null;
|
|
262
|
+
via = el ? "items" : null;
|
|
263
|
+
}
|
|
264
|
+
if (el) el.setAttribute("data-palate-c", c.id);
|
|
265
|
+
res[c.id] = { present: Boolean(el && visible(el)), via };
|
|
266
|
+
}
|
|
267
|
+
return res;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (op === "transform") {
|
|
271
|
+
const NAME = "Maximiliana Alexandrova-Featherstonehaugh de la Cruz-Villanueva";
|
|
272
|
+
const COMPANY = "International Consolidated Holdings & Subsidiaries Worldwide Ltd.";
|
|
273
|
+
const EMAIL = "maximiliana.alexandrova-featherstonehaugh@international-consolidated-holdings.co.uk";
|
|
274
|
+
const WORD = "Supercalifragilisticexpialidocious-pneumonoultramicroscopicsilicovolcanoconiosis";
|
|
275
|
+
const longer = (t, i) => {
|
|
276
|
+
if (/^\S+@\S+\.\S+$/.test(t)) return EMAIL;
|
|
277
|
+
if (/^[$€£¥]?\s?\d[\d.,]*\s?(%|[kKmMbB]|\+)?$/.test(t)) return "1,234,567,890";
|
|
278
|
+
if (/^https?:\/\//.test(t)) return `https://example.com/${WORD.toLowerCase()}/${WORD.toLowerCase()}`;
|
|
279
|
+
if (t.length <= 32 && t.split(" ").length <= 4 && /^[A-Z]/.test(t)) return i % 2 ? COMPANY : NAME;
|
|
280
|
+
return `${t} ${t} ${t}`;
|
|
281
|
+
};
|
|
282
|
+
// Long text goes only where data would: names, titles and values in items, cells and fields. Fixed copy
|
|
283
|
+
// around them (control and segment labels, column and term labels, captions, footnotes, the section's
|
|
284
|
+
// own heading, a number in a heading, sentences) stays as written: it only grows when someone edits it.
|
|
285
|
+
const UI_COPY = "legend, th, dt, caption, figcaption, small, sup, sub, footer, h1, h2, [role=note]";
|
|
286
|
+
// A control whose text is one short label (a segment, a tab, a radio's span) is UI copy; a control that
|
|
287
|
+
// holds a record (a selectable card with a piece, a name and a status) is data.
|
|
288
|
+
const CONTROL = "label, button, [role=button], [role=radio], [role=tab], [role=switch], [role=option], [aria-pressed], [aria-checked], [aria-selected]";
|
|
289
|
+
const slotsOf = (e) => {
|
|
290
|
+
const out = [];
|
|
291
|
+
const w = document.createTreeWalker(e, NodeFilter.SHOW_TEXT);
|
|
292
|
+
for (let n; (n = w.nextNode()); ) if (clean(n.textContent) && !n.parentElement.closest("svg, .sr-only, [aria-hidden=true]")) out.push(clean(n.textContent));
|
|
293
|
+
return out;
|
|
294
|
+
};
|
|
295
|
+
const NOTE = /(^|[\s_-])(foot|footnote|footnotes|fine|fineprint|note|notes|legal|disclaimer|caption|eyebrow|kicker)([\s_-]|$)/i;
|
|
296
|
+
const dataSlot = (p, root, t) => {
|
|
297
|
+
// Prose (a sentence, a description) is written copy; data is short: a name, a title, a value.
|
|
298
|
+
if (t.split(/\s+/).length > 6 || (/[.!?:]$/.test(t) && t.split(/\s+/).length > 2)) return false;
|
|
299
|
+
// A product drawn in HTML on the page (a labelled mock window, a figure) shows demo data written once.
|
|
300
|
+
if (p.closest("[role=group][aria-label], [role=group][aria-labelledby], [role=img], figure, [data-product]")) return false;
|
|
301
|
+
const ui = p.closest(UI_COPY);
|
|
302
|
+
if (ui && (root.contains(ui) || ui.contains(root))) return false;
|
|
303
|
+
const ctl = p.closest(CONTROL);
|
|
304
|
+
if (ctl && root.contains(ctl)) {
|
|
305
|
+
const slots = slotsOf(ctl);
|
|
306
|
+
if (slots.length <= 2 && slots.join(" ").split(" ").length <= 5) return false;
|
|
307
|
+
}
|
|
308
|
+
for (let e = p; e && e !== document.body; e = e.parentElement) {
|
|
309
|
+
if (NOTE.test(`${e.id} ${typeof e.className === "string" ? e.className : ""}`)) return false;
|
|
310
|
+
if (e === root) break;
|
|
311
|
+
}
|
|
312
|
+
return !(/^[$€£¥]?\s?\d[\d.,]*\s?(%|[kKmMbB]|\+)?$/.test(t) && p.closest("h1, h2, h3, h4, h5, h6, [role=heading]"));
|
|
313
|
+
};
|
|
314
|
+
const done = {};
|
|
315
|
+
for (const c of arg.components ?? []) {
|
|
316
|
+
const el = document.querySelector(`[data-palate-c="${c.id}"]`);
|
|
317
|
+
if (!el) continue;
|
|
318
|
+
const items = c.sig ? kidsOf(el).filter((k) => sigOf(k) === c.sig) : [];
|
|
319
|
+
if (arg.mode === "many" && items.length) {
|
|
320
|
+
let last = items[items.length - 1];
|
|
321
|
+
let n = items.length;
|
|
322
|
+
while (n < (arg.n ?? 50)) {
|
|
323
|
+
const copy = items[n % items.length].cloneNode(true);
|
|
324
|
+
copy.removeAttribute("id");
|
|
325
|
+
copy.querySelectorAll("[id]").forEach((x) => x.removeAttribute("id"));
|
|
326
|
+
last.parentNode.insertBefore(copy, last.nextSibling);
|
|
327
|
+
last = copy;
|
|
328
|
+
n++;
|
|
329
|
+
}
|
|
330
|
+
done[c.id] = n;
|
|
331
|
+
} else if (arg.mode === "one" && items.length > 1) {
|
|
332
|
+
items.slice(1).forEach((k) => k.remove());
|
|
333
|
+
done[c.id] = 1;
|
|
334
|
+
} else if (arg.mode === "long") {
|
|
335
|
+
const roots = items.length ? items : [el];
|
|
336
|
+
let changed = 0;
|
|
337
|
+
roots.forEach((root, i) => {
|
|
338
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
339
|
+
let k = 0;
|
|
340
|
+
for (let n; (n = walker.nextNode()) && k < 3; ) {
|
|
341
|
+
const t = clean(n.textContent);
|
|
342
|
+
if (!t || n.parentElement.closest("svg, script, style") || !dataSlot(n.parentElement, el, t)) continue;
|
|
343
|
+
n.textContent = longer(t, i + k);
|
|
344
|
+
if (i === 0 && k === 0) n.textContent += ` ${WORD}`;
|
|
345
|
+
k++;
|
|
346
|
+
changed++;
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
done[c.id] = changed;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return done;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (op === "measure") {
|
|
356
|
+
const base = new Set(arg.baseTexts ?? []);
|
|
357
|
+
const texts = allTexts();
|
|
358
|
+
const fresh = texts.filter((x) => !base.has(x.t));
|
|
359
|
+
const pageCues = [...document.querySelectorAll(CUES)].filter((e) => visible(e) && !e.closest("[data-palate-ignore]")).map(describe).slice(0, 4);
|
|
360
|
+
const brokenImg = (im) => visible(im) && im.complete && im.naturalWidth === 0 && !!(im.currentSrc || im.src);
|
|
361
|
+
// An avatar: small, round, and next to a person's name (or named as one). A photo of a thing is not.
|
|
362
|
+
const PERSON = /^[A-Z][a-zà-ÿ'’.-]+(?:\s+(?:de|da|van|von|la|le|del|di|[A-Z][a-zà-ÿ'’.-]+)){1,3}$/;
|
|
363
|
+
const avatarish = (im) => {
|
|
364
|
+
const r = im.getBoundingClientRect();
|
|
365
|
+
const cs = getComputedStyle(im);
|
|
366
|
+
const radius = parseFloat(cs.borderTopLeftRadius) || 0;
|
|
367
|
+
const round = /%/.test(cs.borderTopLeftRadius) ? radius >= 40 : radius >= Math.min(r.width, r.height) * 0.4;
|
|
368
|
+
const named = /avatar|profile|user|member|author/i.test(`${im.className} ${im.alt} ${im.currentSrc || im.src}`);
|
|
369
|
+
let person = PERSON.test(clean(im.alt));
|
|
370
|
+
for (let e = im.parentElement, k = 0; e && !person && k < 3; e = e.parentElement, k++) person = [...e.querySelectorAll("*")].some((x) => x !== im && !x.children.length && PERSON.test(clean(x.textContent)));
|
|
371
|
+
return r.width <= 64 && round && (person || named);
|
|
372
|
+
};
|
|
373
|
+
const overflowIn = (root) => {
|
|
374
|
+
const out = [];
|
|
375
|
+
const cr = root.getBoundingClientRect();
|
|
376
|
+
for (const el of [root, ...root.querySelectorAll("*")]) {
|
|
377
|
+
if (out.length >= 8) break;
|
|
378
|
+
if (el.closest("svg") || !visible(el)) continue;
|
|
379
|
+
const cs = getComputedStyle(el);
|
|
380
|
+
if (/^inline$/.test(cs.display)) continue;
|
|
381
|
+
const text = ownText(el) || (el.children.length === 0 ? clean(el.textContent) : "");
|
|
382
|
+
const sel = selOf(el);
|
|
383
|
+
if (el.clientWidth > 0 && el.scrollWidth > el.clientWidth + 1) {
|
|
384
|
+
if (/hidden|clip/.test(cs.overflowX)) {
|
|
385
|
+
if (cs.textOverflow === "ellipsis") {
|
|
386
|
+
if (!el.title && !el.closest("[title]") && !el.getAttribute("aria-label")) out.push({ kind: "ellipsis", sel, text: text.slice(0, 60), px: el.scrollWidth - el.clientWidth });
|
|
387
|
+
} else if (text) out.push({ kind: "clip", sel, text: text.slice(0, 60), px: el.scrollWidth - el.clientWidth });
|
|
388
|
+
} else if (cs.overflowX === "visible" && text) out.push({ kind: "spill", sel, text: text.slice(0, 60), px: el.scrollWidth - el.clientWidth });
|
|
389
|
+
}
|
|
390
|
+
if (text && el.clientHeight > 0 && el.scrollHeight > el.clientHeight + 2 && /hidden|clip/.test(cs.overflowY) && cs.webkitLineClamp === "none" && !(cs.textOverflow === "ellipsis")) out.push({ kind: "clip-y", sel, text: text.slice(0, 60), px: el.scrollHeight - el.clientHeight });
|
|
391
|
+
if (text && el !== root && getComputedStyle(root).overflowX === "visible") {
|
|
392
|
+
const r = el.getBoundingClientRect();
|
|
393
|
+
const past = Math.max(r.right - cr.right, cr.left - r.left);
|
|
394
|
+
if (past > 2 && r.width > 0) out.push({ kind: "outside", sel, text: text.slice(0, 60), px: Math.round(past) });
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// One entry per element, the most telling first.
|
|
398
|
+
const seen = new Set();
|
|
399
|
+
return out.filter((o) => !seen.has(o.sel) && seen.add(o.sel));
|
|
400
|
+
};
|
|
401
|
+
const comps = {};
|
|
402
|
+
for (const c of arg.components ?? []) {
|
|
403
|
+
const el = document.querySelector(`[data-palate-c="${c.id}"]`);
|
|
404
|
+
let region = null;
|
|
405
|
+
try {
|
|
406
|
+
region = (el && el.parentElement?.closest("section, article, aside, form, [role=region], [role=dialog], main > *")) || document.querySelector(c.region);
|
|
407
|
+
} catch {}
|
|
408
|
+
if (region && region.getBoundingClientRect().height > Math.max(innerHeight * 2.5, 2000)) region = el?.parentElement ?? null;
|
|
409
|
+
const scope = region ?? el;
|
|
410
|
+
const within = (node) => Boolean((scope && scope.contains(node)) || (el && el.contains(node)));
|
|
411
|
+
const here = fresh.filter((x) => within(x.el)).map((x) => x.t);
|
|
412
|
+
// New text in the part's own place: inside it, or where it was on the page.
|
|
413
|
+
const b0 = c.box;
|
|
414
|
+
const inPlace = fresh
|
|
415
|
+
.filter((x) => {
|
|
416
|
+
if (el && el.contains(x.el)) return true;
|
|
417
|
+
if (!b0) return false;
|
|
418
|
+
const r = x.el.getBoundingClientRect();
|
|
419
|
+
const y = r.top + scrollY;
|
|
420
|
+
return y >= b0.y - 24 && y <= b0.y + Math.max(b0.height, 160) && r.right + scrollX > b0.x && r.left + scrollX < b0.x + b0.width;
|
|
421
|
+
})
|
|
422
|
+
.map((x) => x.t);
|
|
423
|
+
const items = el && c.sig ? kidsOf(el).filter((k) => sigOf(k) === c.sig && visible(k)) : [];
|
|
424
|
+
const count = el && c.sig ? items.length : null;
|
|
425
|
+
const cueEls = scope ? [...scope.querySelectorAll(CUES)].filter(visible) : [];
|
|
426
|
+
const runningAnims = scope ? document.getAnimations().filter((a) => a.playState === "running" && a.effect?.getTiming?.().iterations === Infinity && a.effect?.target && scope.contains(a.effect.target) && visible(a.effect.target)).length : 0;
|
|
427
|
+
const cue = cueEls.length ? describe(cueEls[0]) : scope?.getAttribute("aria-busy") === "true" ? "aria-busy" : here.find((t) => LOADING_RE.test(t)) ? `"${here.find((t) => LOADING_RE.test(t))}"` : runningAnims ? `${runningAnims} running animation(s)` : null;
|
|
428
|
+
const scopeTexts = scope ? texts.filter((x) => scope.contains(x.el)).map((x) => x.t) : [];
|
|
429
|
+
const errorEl = scope ? [...scope.querySelectorAll("[role=alert], [aria-live]")].find((a) => visible(a) && clean(a.textContent)) : null;
|
|
430
|
+
comps[c.id] = {
|
|
431
|
+
present: Boolean(el && visible(el)),
|
|
432
|
+
box: el && visible(el) ? box(el) : null,
|
|
433
|
+
regionBox: region && visible(region) ? box(region) : null,
|
|
434
|
+
count,
|
|
435
|
+
itemBox: items[0] ? box(items[0]) : null,
|
|
436
|
+
newTexts: here.slice(0, 8),
|
|
437
|
+
emptyMsg: inPlace.find((t) => EMPTY_RE.test(t)) ?? here.find((t) => EMPTY_RE.test(t)) ?? ((count === 0 || !el) && inPlace.length ? inPlace[0] : null) ?? fresh.find((x) => EMPTY_RE.test(x.t) && x.t.length < 160)?.t ?? null,
|
|
438
|
+
inPlace: inPlace.slice(0, 6),
|
|
439
|
+
errorMsg: here.find((t) => ERROR_RE.test(t)) ?? (errorEl && !base.has(clean(errorEl.textContent)) ? clean(errorEl.textContent).slice(0, 120) : null) ?? fresh.find((x) => ERROR_RE.test(x.t) && x.t.length < 200)?.t ?? null,
|
|
440
|
+
retry: scope ? [...scope.querySelectorAll("button, a[href], [role=button]")].some((b) => visible(b) && /retry|try again|reload|refresh/i.test(b.textContent)) || fresh.some((x) => /retry|try again|reload|refresh/i.test(x.t) && x.el.closest("button, a, [role=button]")) : false,
|
|
441
|
+
loadingCue: cue,
|
|
442
|
+
actions: scope ? [...scope.querySelectorAll("button, a[href], [role=button]")].filter(visible).map((b) => clean(b.textContent || b.getAttribute("aria-label"))).filter(Boolean).slice(0, 4) : [],
|
|
443
|
+
scopeText: scopeTexts.join(" ").slice(0, 400),
|
|
444
|
+
overflow: el && visible(el) ? overflowIn(el) : [],
|
|
445
|
+
broken: el ? [...(el.tagName === "IMG" ? [el] : el.querySelectorAll("img"))].filter(brokenImg).map((im) => ({ src: (im.currentSrc || im.src).slice(-60), alt: im.alt, w: Math.round(im.getBoundingClientRect().width), avatar: avatarish(im) })).slice(0, 6) : [],
|
|
446
|
+
// How far the part reaches past the right edge of the screen (it makes the page scroll sideways).
|
|
447
|
+
past: el && visible(el) ? Math.max(0, Math.round(el.getBoundingClientRect().right - document.documentElement.clientWidth)) : 0,
|
|
448
|
+
paging: scope ? [...scope.querySelectorAll("button, a, nav")].some((b) => visible(b) && (/show more|load more|view all|see all|next|previous|older|newer|page \d/i.test(b.textContent) || /pagination/i.test(b.getAttribute("aria-label") || ""))) || (el && /auto|scroll/.test(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight + 4) : false,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
const fields = (arg.fields ?? []).map((s) => {
|
|
452
|
+
try {
|
|
453
|
+
const f = document.querySelector(s);
|
|
454
|
+
return f ? f.value ?? "" : null;
|
|
455
|
+
} catch {
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
let submit = null;
|
|
460
|
+
if (arg.submit) {
|
|
461
|
+
try {
|
|
462
|
+
const b = document.querySelector(arg.submit);
|
|
463
|
+
if (b) submit = { disabled: Boolean(b.disabled), ariaDisabled: b.getAttribute("aria-disabled") === "true", busy: b.getAttribute("aria-busy") === "true", text: clean(b.textContent || b.value), cue: [...b.querySelectorAll(CUES)].some(visible) || [...b.querySelectorAll("svg")].some((s) => /spin|loader|loading/i.test(s.getAttribute("class") || "")) };
|
|
464
|
+
} catch {}
|
|
465
|
+
}
|
|
466
|
+
// "1 pieces", "1 members": one of anything, in the plural. "0 piece" when the page says "pieces" elsewhere.
|
|
467
|
+
const NOT_PLURAL = /(ss|us|is|ics|ous)$|^(does|goes|always|perhaps|towards|across|unless|plus|minus|this|thus|news|series|species|lens|alias|atlas|canvas|chaos|whereas|besides|sometimes|nevertheless)$/;
|
|
468
|
+
const baseJoined = [...base].join(" \n ");
|
|
469
|
+
const slip = (t) => {
|
|
470
|
+
const one = t.match(/(?:^|[^\d.,\w])1\s+([a-z]{3,}s)\b/);
|
|
471
|
+
if (one && !NOT_PLURAL.test(one[1])) return true;
|
|
472
|
+
const zero = t.match(/(?:^|[^\d.,\w])0\s+([a-z]{3,})\b/);
|
|
473
|
+
return Boolean(zero && !/s$/.test(zero[1]) && new RegExp(`(^|\\W)${zero[1]}s(\\W|$)`).test(baseJoined));
|
|
474
|
+
};
|
|
475
|
+
// Own text, and short blocks whose number and word sit in different elements (<b>1</b> pieces).
|
|
476
|
+
const shortBlocks = [...document.body.querySelectorAll("*")].filter((el) => el.children.length && el.children.length <= 4 && !el.closest("svg, script, style") && visible(el)).map((el) => clean(el.textContent)).filter((t) => t.length <= 60);
|
|
477
|
+
const a = document.activeElement;
|
|
478
|
+
const root = document.querySelector("#root, #app, #__next, #svelte, [data-reactroot]");
|
|
479
|
+
return {
|
|
480
|
+
comps,
|
|
481
|
+
// A crashed render: the app's root emptied, or a dev error overlay on top.
|
|
482
|
+
rootEmpty: Boolean(root && !root.children.length),
|
|
483
|
+
overlay: Boolean(document.querySelector("vite-error-overlay, #webpack-dev-server-client-overlay")),
|
|
484
|
+
overflowX: Math.max(0, document.documentElement.scrollWidth - document.documentElement.clientWidth),
|
|
485
|
+
pageHeight: document.documentElement.scrollHeight,
|
|
486
|
+
bodyText: clean(document.body.innerText).length,
|
|
487
|
+
newTexts: fresh.map((x) => x.t).slice(0, 30),
|
|
488
|
+
errorTexts: fresh.filter((x) => ERROR_RE.test(x.t) && x.t.length < 200).map((x) => x.t).slice(0, 4),
|
|
489
|
+
emptyTexts: fresh.filter((x) => EMPTY_RE.test(x.t) && x.t.length < 160).map((x) => x.t).slice(0, 4),
|
|
490
|
+
leaks: texts.filter((x) => /^(undefined|null|NaN|\[object Object\]|Invalid Date)$/.test(x.t) || /\b(undefined|NaN)\b|\[object Object\]/.test(x.t)).map((x) => ({ text: x.t.slice(0, 60), sel: selOf(x.el) })).slice(0, 4),
|
|
491
|
+
plurals: [...new Set(texts.map((x) => x.t).concat(shortBlocks).filter((t) => t.length <= 80 && slip(t)).map((t) => t.slice(0, 60)))].filter((t, i, a) => !a.some((o) => o !== t && t.includes(o))).slice(0, 3),
|
|
492
|
+
broken: [...document.querySelectorAll("img")].filter(brokenImg).map((im) => ({ src: (im.currentSrc || im.src).slice(-60), alt: im.alt, sel: selOf(im), w: Math.round(im.getBoundingClientRect().width) })).slice(0, 10),
|
|
493
|
+
images: [...document.querySelectorAll("img")].filter(visible).length,
|
|
494
|
+
cues: pageCues,
|
|
495
|
+
fields,
|
|
496
|
+
submit,
|
|
497
|
+
focus: !a || a === document.body || a === document.documentElement ? null : describe(a),
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// After a send: how many records show the values palate typed (not counting success notes), how many
|
|
502
|
+
// success messages are up, and the retry button the UI offers, if any.
|
|
503
|
+
if (op === "outcome") {
|
|
504
|
+
const base = new Set(arg.baseTexts ?? []);
|
|
505
|
+
const SUCCESS = /\b(sent|saved|added|created|invited|success(?:ful(?:ly)?)?|done|thanks|thank you|submitted|subscribed|updated|scheduled|booked|confirmed)\b/i;
|
|
506
|
+
const values = (arg.values ?? []).filter((v) => v && v.length >= 6);
|
|
507
|
+
const texts = allTexts();
|
|
508
|
+
const note = (el) => el.closest("[role=status], [role=alert], [aria-live], [role=dialog]");
|
|
509
|
+
const records = texts.filter((x) => values.some((v) => x.t.includes(v)) && !SUCCESS.test(x.t) && !note(x.el) && !x.el.closest("form")).length;
|
|
510
|
+
const successes = texts.filter((x) => !base.has(x.t) && SUCCESS.test(x.t) && x.t.length < 160 && !/^(sent|saved|done)$/i.test(x.t) && !x.el.closest("button, label, h1, h2, h3, h4")).map((x) => x.t);
|
|
511
|
+
const retry = [...document.querySelectorAll("button, [role=button], a")].find((b) => visible(b) && !b.disabled && /^(retry|try again|resend|send again|re-?try)\b/i.test(clean(b.textContent || b.getAttribute("aria-label"))));
|
|
512
|
+
return { records, successes: successes.slice(0, 4), retry: retry ? selOf(retry) : null };
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Keyboard error recovery (one form, arg: { id, fields, submit }):
|
|
516
|
+
// active where focus is: which of the form's fields, its submit, inside the form at all
|
|
517
|
+
// recover-arm before the submit: the values, the texts and the live regions as they are, and a watch on
|
|
518
|
+
// every live region from here on (a message set and cleared in between is still seen)
|
|
519
|
+
// recover-read after it: each field (aria-invalid, :invalid, what its aria-describedby / aria-errormessage
|
|
520
|
+
// point at), the message on screen, the live regions that changed, where focus went (a field
|
|
521
|
+
// or an error summary linking to one), and whether field and message fit the screen
|
|
522
|
+
const LIVE = "[role=alert], [role=status], [role=log], [aria-live]:not([aria-live=off]), output";
|
|
523
|
+
const VALID_RE = /\b(required|invalid|enter (?:a|an|your|the)|must|please|valid|missing|format|too (?:long|short)|at (?:least|most)|can.?t be (?:blank|empty)|isn.?t|doesn.?t look|not a|looks? like|incorrect)\b/i;
|
|
524
|
+
const msgish = (t) => ERROR_RE.test(t) || VALID_RE.test(t);
|
|
525
|
+
const formEl = () => (arg.id ? document.querySelector(`[data-palate-c="${arg.id}"]`) : null);
|
|
526
|
+
const fieldEls = () => (arg.fields ?? []).map((s) => {
|
|
527
|
+
try {
|
|
528
|
+
return document.querySelector(s);
|
|
529
|
+
} catch {
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
const vbox = (el) => {
|
|
534
|
+
const r = el.getBoundingClientRect();
|
|
535
|
+
return { left: Math.round(r.left), top: Math.round(r.top), width: Math.round(r.width), height: Math.round(r.height), right: Math.round(r.right), bottom: Math.round(r.bottom) };
|
|
536
|
+
};
|
|
537
|
+
const offX = (el) => {
|
|
538
|
+
const r = el.getBoundingClientRect();
|
|
539
|
+
return r.left < -1 || r.right > document.documentElement.clientWidth + 1;
|
|
540
|
+
};
|
|
541
|
+
// Covered by something fixed or sticky (a header, a cookie bar), not by its own label.
|
|
542
|
+
const coveredBy = (el) => {
|
|
543
|
+
const r = el.getBoundingClientRect();
|
|
544
|
+
for (const [fx, fy] of [[0.5, 0.5], [0.12, 0.3], [0.88, 0.3]]) {
|
|
545
|
+
const x = r.left + r.width * fx;
|
|
546
|
+
const y = r.top + r.height * fy;
|
|
547
|
+
if (x < 0 || y < 0 || x >= innerWidth || y >= innerHeight) continue;
|
|
548
|
+
const t = document.elementFromPoint(x, y);
|
|
549
|
+
if (!t || el.contains(t) || t.contains(el) || t.closest("[data-palate-ignore]")) continue;
|
|
550
|
+
for (let e = t; e && e !== document.body; e = e.parentElement) if (/fixed|sticky/.test(getComputedStyle(e).position)) return describe(e);
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
};
|
|
554
|
+
const liveRegions = () => [...document.querySelectorAll(LIVE)];
|
|
555
|
+
const liveInfo = (el) => ({ role: el.getAttribute("role") || el.tagName.toLowerCase(), ariaLive: el.getAttribute("aria-live"), alert: el.getAttribute("role") === "alert" || el.getAttribute("aria-live") === "assertive", hidden: !el.getClientRects().length || Boolean(el.closest("[aria-hidden=true], [hidden]")) });
|
|
556
|
+
|
|
557
|
+
if (op === "active") {
|
|
558
|
+
const a = document.activeElement;
|
|
559
|
+
const f = formEl();
|
|
560
|
+
if (!a || a === document.body || a === document.documentElement) return { body: true, field: -1, submit: false, inForm: false };
|
|
561
|
+
let submit = false;
|
|
562
|
+
try {
|
|
563
|
+
submit = Boolean(arg.submit && document.querySelector(arg.submit) === a);
|
|
564
|
+
} catch {}
|
|
565
|
+
return { field: fieldEls().indexOf(a), submit, inForm: Boolean(f && f.contains(a)), sel: selOf(a), what: describe(a) };
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (op === "recover-arm") {
|
|
569
|
+
const prev = window.__palateRec;
|
|
570
|
+
if (prev && arg.again) {
|
|
571
|
+
prev.submits = 0;
|
|
572
|
+
prev.invalids = 0;
|
|
573
|
+
return { values: fieldEls().map((x) => (x ? x.value ?? "" : null)) };
|
|
574
|
+
}
|
|
575
|
+
const st = (window.__palateRec = { texts: new Set(allTexts().map((x) => x.t)), before: new Map(), live: [], submits: 0, invalids: 0 });
|
|
576
|
+
for (const el of liveRegions()) st.before.set(el, clean(el.textContent));
|
|
577
|
+
st.look = () => {
|
|
578
|
+
for (const el of liveRegions()) {
|
|
579
|
+
const t = clean(el.textContent);
|
|
580
|
+
if (!t || (st.before.has(el) && st.before.get(el) === t) || st.live.some((x) => x.el === el && x.text === t)) continue;
|
|
581
|
+
st.live.push({ el, text: t.slice(0, 200), existed: st.before.has(el), ...liveInfo(el) });
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
new MutationObserver(st.look).observe(document.body, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["role", "aria-live", "hidden", "class", "style"] });
|
|
585
|
+
document.addEventListener("submit", () => st.submits++, true);
|
|
586
|
+
document.addEventListener("invalid", () => st.invalids++, true);
|
|
587
|
+
return { values: fieldEls().map((x) => (x ? x.value ?? "" : null)) };
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (op === "recover-read") {
|
|
591
|
+
const st = window.__palateRec ?? { texts: new Set(), before: new Map(), live: [], submits: 0, invalids: 0, look: () => {} };
|
|
592
|
+
st.look();
|
|
593
|
+
const form = formEl();
|
|
594
|
+
const els = fieldEls();
|
|
595
|
+
const fresh = allTexts().filter((x) => !st.texts.has(x.t));
|
|
596
|
+
const refs = (el, attr) => (el.getAttribute(attr) ?? "").split(/\s+/).filter(Boolean).map((id) => document.getElementById(id)).filter(Boolean)
|
|
597
|
+
.map((d) => ({ attr, id: d.id, text: clean(d.textContent).slice(0, 160), visible: visible(d) && Boolean(clean(d.textContent)), fresh: Boolean(clean(d.textContent)) && !st.texts.has(clean(d.textContent)) }));
|
|
598
|
+
const fields = els.map((el) => el && {
|
|
599
|
+
id: el.id || null,
|
|
600
|
+
value: el.value ?? "",
|
|
601
|
+
ariaInvalid: el.getAttribute("aria-invalid") === "true",
|
|
602
|
+
nativeInvalid: Boolean(el.matches?.(":invalid")),
|
|
603
|
+
validationMessage: (el.validationMessage || "").slice(0, 120),
|
|
604
|
+
described: [...refs(el, "aria-describedby"), ...refs(el, "aria-errormessage")],
|
|
605
|
+
box: vbox(el),
|
|
606
|
+
offX: offX(el),
|
|
607
|
+
coveredBy: visible(el) ? coveredBy(el) : null,
|
|
608
|
+
});
|
|
609
|
+
// The message on screen: what a marked field points at, else new text in or next to the form that reads
|
|
610
|
+
// like an error, else any new text in the form, else an error anywhere (a toast).
|
|
611
|
+
const marked = els.filter((el, i) => el && (fields[i].ariaInvalid || fields[i].nativeInvalid));
|
|
612
|
+
let msgEl = null;
|
|
613
|
+
for (const el of marked) {
|
|
614
|
+
for (const id of `${el.getAttribute("aria-describedby") ?? ""} ${el.getAttribute("aria-errormessage") ?? ""}`.split(/\s+/).filter(Boolean)) {
|
|
615
|
+
const d = document.getElementById(id);
|
|
616
|
+
const t = clean(d?.textContent);
|
|
617
|
+
if (!msgEl && d && visible(d) && t && (!st.texts.has(t) || msgish(t))) msgEl = d;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (!msgEl) {
|
|
621
|
+
const fr = form?.getBoundingClientRect();
|
|
622
|
+
const near = fresh.filter((x) => form && (form.contains(x.el) || (() => {
|
|
623
|
+
const r = x.el.getBoundingClientRect();
|
|
624
|
+
return r.bottom >= fr.top - 80 && r.top <= fr.bottom + 80;
|
|
625
|
+
})()));
|
|
626
|
+
msgEl = (near.find((x) => msgish(x.t)) ?? near.find((x) => form?.contains(x.el) && !x.el.closest("button, label")) ?? fresh.find((x) => msgish(x.t) && x.t.length < 200))?.el ?? null;
|
|
627
|
+
}
|
|
628
|
+
const message = msgEl ? { text: clean(msgEl.textContent).slice(0, 160), sel: selOf(msgEl), box: vbox(msgEl), offX: offX(msgEl), inLive: Boolean(msgEl.closest(LIVE)) } : null;
|
|
629
|
+
// Focus: a field, or an error summary (the focused element or a block just around it links to a field).
|
|
630
|
+
const a = document.activeElement;
|
|
631
|
+
const none = !a || a === document.body || a === document.documentElement;
|
|
632
|
+
let summary = null;
|
|
633
|
+
for (let e = none ? null : a, k = 0; e && e !== document.body && k < 3 && !summary; e = e.parentElement, k++) {
|
|
634
|
+
const links = [...(e.matches("a[href^='#']") ? [e] : []), ...e.querySelectorAll("a[href^='#']")].map((l) => decodeURIComponent(l.getAttribute("href").slice(1))).filter(Boolean);
|
|
635
|
+
if (links.length && links.some((id) => els.some((x) => x && x.id === id))) summary = { sel: selOf(e), links, alert: Boolean(e.closest("[role=alert], [aria-live=assertive], [aria-live=polite]")), labelled: Boolean(e.getAttribute("aria-labelledby") || e.getAttribute("aria-label") || e.querySelector("h1, h2, h3, h4, [role=heading]")) };
|
|
636
|
+
}
|
|
637
|
+
let submitted = false;
|
|
638
|
+
try {
|
|
639
|
+
submitted = Boolean(arg.submit && document.querySelector(arg.submit) === a);
|
|
640
|
+
} catch {}
|
|
641
|
+
return {
|
|
642
|
+
fields,
|
|
643
|
+
message,
|
|
644
|
+
stillShown: arg.message ? allTexts().some((x) => x.t === arg.message || (arg.message.length > 12 && x.t.includes(arg.message))) : false,
|
|
645
|
+
live: st.live.map(({ el, ...x }) => x).slice(0, 8),
|
|
646
|
+
submits: st.submits,
|
|
647
|
+
invalids: st.invalids,
|
|
648
|
+
nativeBlocked: st.invalids > 0 && st.submits === 0,
|
|
649
|
+
active: none ? { body: true, field: -1 } : { field: els.indexOf(a), submit: submitted, sel: selOf(a), what: describe(a), summary, coveredBy: visible(a) ? coveredBy(a) : null, offX: offX(a) },
|
|
650
|
+
overflowX: Math.max(0, document.documentElement.scrollWidth - document.documentElement.clientWidth),
|
|
651
|
+
width: document.documentElement.clientWidth,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// After palate filled a form and pressed send: which fields the page says are wrong (aria-invalid, :invalid,
|
|
656
|
+
// or named by a new validation message), and that message.
|
|
657
|
+
if (op === "validity") {
|
|
658
|
+
const base = new Set(arg.baseTexts ?? []);
|
|
659
|
+
const form = formEl();
|
|
660
|
+
// Validation also asks ("Choose a collection.", "Add the date…").
|
|
661
|
+
const ASK = /^(please )?(choose|select|pick|add|enter|tell|give|fill|provide|type|confirm|agree|accept)\b/i;
|
|
662
|
+
const fresh = allTexts().filter((x) => !base.has(x.t) && (msgish(x.t) || ASK.test(x.t)) && x.t.length < 200 && !x.el.closest("button, label"));
|
|
663
|
+
const near = fresh.filter((x) => form && (form.contains(x.el) || form.parentElement?.contains(x.el)));
|
|
664
|
+
const message = (near[0] ?? fresh[0])?.t ?? null;
|
|
665
|
+
const fields = fieldEls().map((el) => {
|
|
666
|
+
if (!el) return null;
|
|
667
|
+
// A hint that was there before the send ("The town is fine if…") is not an error.
|
|
668
|
+
const said = `${el.getAttribute("aria-describedby") ?? ""} ${el.getAttribute("aria-errormessage") ?? ""}`.split(/\s+/).filter(Boolean).map((id) => clean(document.getElementById(id)?.textContent)).filter((t) => t && (msgish(t) || ASK.test(t)) && !base.has(t));
|
|
669
|
+
return { invalid: el.getAttribute("aria-invalid") === "true" || Boolean(el.matches?.(":invalid")), said: said[0] ?? null, value: el.value ?? "", checked: Boolean(el.checked) };
|
|
670
|
+
});
|
|
671
|
+
return { fields, message };
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
if (op === "focus") {
|
|
675
|
+
const a = document.activeElement;
|
|
676
|
+
if (!a || a === document.body || a === document.documentElement) return { body: true };
|
|
677
|
+
const r = a.getBoundingClientRect();
|
|
678
|
+
const cs = getComputedStyle(a);
|
|
679
|
+
let hidden = r.width < 1 || r.height < 1 || cs.visibility === "hidden";
|
|
680
|
+
for (let e = a; e && !hidden; e = e.parentElement) if (parseFloat(getComputedStyle(e).opacity) < 0.05) hidden = true;
|
|
681
|
+
const inView = r.bottom > 0 && r.top < innerHeight && r.right > 0 && r.left < innerWidth;
|
|
682
|
+
let obscured = null;
|
|
683
|
+
if (!hidden && inView) {
|
|
684
|
+
const x = Math.min(innerWidth - 1, Math.max(0, r.left + r.width / 2));
|
|
685
|
+
const y = Math.min(innerHeight - 1, Math.max(0, r.top + Math.min(r.height / 2, 10)));
|
|
686
|
+
const top = document.elementFromPoint(x, y);
|
|
687
|
+
if (top && top !== a && !a.contains(top) && !top.contains(a) && !top.closest("[data-palate-ignore]")) obscured = describe(top.closest("header, nav, [role=banner], [role=dialog], aside, div") ?? top);
|
|
688
|
+
}
|
|
689
|
+
const sr = /sr-only|visually-hidden|skip/i.test(`${a.className} ${a.parentElement?.className ?? ""}`);
|
|
690
|
+
// A native control hidden on purpose (opacity 0, sr-only, clipped) draws its focus on its label or a
|
|
691
|
+
// sibling (`input:focus-visible + span`): fine when that shows, lost when nothing does.
|
|
692
|
+
const clipped = (cs.clip && cs.clip !== "auto") || /inset\(50%|inset\(100%/.test(cs.clipPath) || (r.width <= 2 && r.height <= 2);
|
|
693
|
+
if (a.matches("input, select, textarea") && (hidden || sr || clipped)) {
|
|
694
|
+
const by = focusShownOn(a);
|
|
695
|
+
const br = by?.getBoundingClientRect();
|
|
696
|
+
const byInView = br ? br.bottom > 0 && br.top < innerHeight && br.right > 0 && br.left < innerWidth : inView;
|
|
697
|
+
return { sel: selOf(a), what: describe(a), hidden: !by, shownOn: by ? describe(by) : null, inView: byInView, obscured: by ? null : obscured, y: Math.round((br ?? r).top + scrollY) };
|
|
698
|
+
}
|
|
699
|
+
return { sel: selOf(a), what: describe(a), hidden: hidden && !sr, inView, obscured, y: Math.round(r.top + scrollY) };
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return null;
|
|
703
|
+
};
|