Generate web slides from Markdoc

feat: add theming module

Adds @morkdeck/theme, responsible for converting DTCG tokens into CSS
variables, and generating helper TS code for referencing said CSS
variables by name in Web Component styles.

graham.systems 04420b97 571e1ac6

verified
+2
deno.json
··· 4 4 "./packages/core", 5 5 "./packages/runtime", 6 6 "./packages/server", 7 + "./packages/theme", 7 8 "./packages/wc" 8 9 ], 9 10 "tasks": { ··· 20 21 ] 21 22 }, 22 23 "imports": { 24 + "lit": "npm:lit@^3.3.1", 23 25 "xstate": "npm:xstate@^5.20.2" 24 26 } 25 27 }
+342
deno.lock
··· 27 27 "jsr:@std/text@~1.0.7": "1.0.15", 28 28 "npm:@lit/context@^1.1.6": "1.1.6", 29 29 "npm:@markdoc/markdoc@*": "0.5.2", 30 + "npm:@terrazzo/parser@~0.10.2": "0.10.2", 31 + "npm:@terrazzo/plugin-css@~0.10.2": "0.10.2_@terrazzo+cli@0.10.2", 32 + "npm:@terrazzo/plugin-js@~0.10.1": "0.10.1_@terrazzo+cli@0.10.2", 30 33 "npm:@types/blobshape@^1.0.3": "1.0.3", 31 34 "npm:@types/hast@^3.0.4": "3.0.4", 32 35 "npm:@types/node@*": "22.15.15", ··· 144 147 "npm": { 145 148 "@babel/runtime@7.28.3": { 146 149 "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==" 150 + }, 151 + "@clack/core@0.4.1": { 152 + "integrity": "sha512-Pxhij4UXg8KSr7rPek6Zowm+5M22rbd2g1nfojHJkxp5YkFqiZ2+YLEM/XGVIzvGOcM0nqjIFxrpDwWRZYWYjA==", 153 + "dependencies": [ 154 + "picocolors", 155 + "sisteransi" 156 + ] 157 + }, 158 + "@clack/prompts@0.9.1": { 159 + "integrity": "sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==", 160 + "dependencies": [ 161 + "@clack/core", 162 + "picocolors", 163 + "sisteransi" 164 + ] 147 165 }, 148 166 "@esbuild/aix-ppc64@0.25.8": { 149 167 "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", ··· 405 423 "os": ["win32"], 406 424 "cpu": ["x64"] 407 425 }, 426 + "@hono/node-server@1.18.2_hono@4.8.4": { 427 + "integrity": "sha512-icgNvC0vRYivzyuSSaUv9ttcwtN8fDyd1k3AOIBDJgYd84tXRZSS6na8X54CY/oYoFTNhEmZraW/Rb9XYwX4KA==", 428 + "dependencies": [ 429 + "hono" 430 + ] 431 + }, 432 + "@humanwhocodes/momoa@3.3.9": { 433 + "integrity": "sha512-LHw6Op4bJb3/3KZgOgwflJx5zY9XOy0NU1NuyUFKGdTwHYmP+PbnQGCYQJ8NVNlulLfQish34b0VuUlLYP3AXA==" 434 + }, 408 435 "@lit-labs/ssr-dom-shim@1.4.0": { 409 436 "integrity": "sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==" 410 437 }, ··· 473 500 "@shikijs/vscode-textmate@10.0.2": { 474 501 "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==" 475 502 }, 503 + "@terrazzo/cli@0.10.2": { 504 + "integrity": "sha512-LgUwwdW1GvOo5KghWcTg4Xuy951Arr4cimRymyQvUk4IZkYMOyH7btUmMLTEAAO4W7cV5F/U9u1cSPOxh6866A==", 505 + "dependencies": [ 506 + "@clack/prompts", 507 + "@hono/node-server", 508 + "@humanwhocodes/momoa", 509 + "@terrazzo/parser", 510 + "@terrazzo/token-tools", 511 + "@types/escodegen", 512 + "chokidar", 513 + "detect-package-manager", 514 + "dotenv", 515 + "escodegen", 516 + "merge-anything", 517 + "meriyah", 518 + "mime", 519 + "picocolors", 520 + "yaml-to-momoa" 521 + ], 522 + "bin": true 523 + }, 524 + "@terrazzo/parser@0.10.2": { 525 + "integrity": "sha512-aEJzLWVzS0NF/HJVSySnWkf03MRbUnYmG781P2ytqATnvhBb9YSdjmBW/1e/WTmDOksCWrSEyWjaxomPqss0mQ==", 526 + "dependencies": [ 527 + "@humanwhocodes/momoa", 528 + "@terrazzo/token-tools", 529 + "@types/babel__code-frame", 530 + "@types/culori", 531 + "culori", 532 + "merge-anything", 533 + "picocolors", 534 + "scule", 535 + "wildcard-match" 536 + ] 537 + }, 538 + "@terrazzo/plugin-css@0.10.2_@terrazzo+cli@0.10.2": { 539 + "integrity": "sha512-RSkIRMMipz300zfL0gX27HPq9xLRV9PwB5RkQuaryAjzHbjM8Cv5cyAVECukFUC0PDH4/FklCFEvvREG+erFrg==", 540 + "dependencies": [ 541 + "@terrazzo/cli", 542 + "@terrazzo/token-tools", 543 + "wildcard-match" 544 + ] 545 + }, 546 + "@terrazzo/plugin-js@0.10.1_@terrazzo+cli@0.10.2": { 547 + "integrity": "sha512-GRIw+BJQLoYXw3nzAZ2I40uyKSuX5hptJiCBMtykQ5pmvdLEe48pjMiiy4nhxWN3oNEVxGOabu/sOH3ygZvRLg==", 548 + "dependencies": [ 549 + "@terrazzo/cli", 550 + "@terrazzo/token-tools" 551 + ] 552 + }, 553 + "@terrazzo/token-tools@0.10.2": { 554 + "integrity": "sha512-flEzbPxB9d9G7/c/wmWWchyzLCf6Lqma3y1ZMgNuXWLKv3Pw+ExOWBGGHac3zofk+cfKVfEBx1s4B57tt+IOiA==", 555 + "dependencies": [ 556 + "@humanwhocodes/momoa", 557 + "culori", 558 + "wildcard-match" 559 + ] 560 + }, 561 + "@types/babel__code-frame@7.0.6": { 562 + "integrity": "sha512-Anitqkl3+KrzcW2k77lRlg/GfLZLWXBuNgbEcIOU6M92yw42vsd3xV/Z/yAHEj8m+KUjL6bWOVOFqX8PFPJ4LA==" 563 + }, 476 564 "@types/blobshape@1.0.3": { 477 565 "integrity": "sha512-jbJZ9AIebK77LoeN8PjPyAs88GJCDKO+ZpWCJlLlV2FXkeYScQsvkZmlGHGvSRk/WFmUOdbGJ75umLATGX1lsw==" 566 + }, 567 + "@types/culori@4.0.0": { 568 + "integrity": "sha512-aFljQwjb++sl6TAyEXeHTiK/fk9epZOQ+nMmadjnAvzZFIvNoQ0x8XQYfcOaRTBwmDUPUlghhZCJ66MTcqQAsg==" 569 + }, 570 + "@types/escodegen@0.0.10": { 571 + "integrity": "sha512-IVvcNLEFbiL17qiGRGzyfx/u9K6lA5w6wcQSIgv2h4JG3ZAFIY1Be9ITTSPuARIxRpzW54s8OvcF6PdonBbDzg==" 478 572 }, 479 573 "@types/hast@3.0.4": { 480 574 "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", ··· 516 610 "@ungap/structured-clone@1.3.0": { 517 611 "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==" 518 612 }, 613 + "anymatch@3.1.3": { 614 + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 615 + "dependencies": [ 616 + "normalize-path", 617 + "picomatch" 618 + ] 619 + }, 620 + "binary-extensions@2.3.0": { 621 + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==" 622 + }, 623 + "braces@3.0.3": { 624 + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 625 + "dependencies": [ 626 + "fill-range" 627 + ] 628 + }, 519 629 "ccount@2.0.1": { 520 630 "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" 521 631 }, ··· 525 635 "character-entities-legacy@3.0.0": { 526 636 "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==" 527 637 }, 638 + "chokidar@3.6.0": { 639 + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 640 + "dependencies": [ 641 + "anymatch", 642 + "braces", 643 + "glob-parent", 644 + "is-binary-path", 645 + "is-glob", 646 + "normalize-path", 647 + "readdirp" 648 + ], 649 + "optionalDependencies": [ 650 + "fsevents" 651 + ] 652 + }, 528 653 "comma-separated-tokens@2.0.3": { 529 654 "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" 530 655 }, 656 + "cross-spawn@7.0.6": { 657 + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 658 + "dependencies": [ 659 + "path-key", 660 + "shebang-command", 661 + "which" 662 + ] 663 + }, 664 + "culori@4.0.2": { 665 + "integrity": "sha512-1+BhOB8ahCn4O0cep0Sh2l9KCOfOdY+BXJnKMHFFzDEouSr/el18QwXEMRlOj9UY5nCeA8UN3a/82rUWRBeyBw==" 666 + }, 531 667 "dequal@2.0.3": { 532 668 "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" 533 669 }, 670 + "detect-package-manager@3.0.2": { 671 + "integrity": "sha512-8JFjJHutStYrfWwzfretQoyNGoZVW1Fsrp4JO9spa7h/fBfwgTMEIy4/LBzRDGsxwVPHU0q+T9YvwLDJoOApLQ==", 672 + "dependencies": [ 673 + "execa" 674 + ] 675 + }, 534 676 "devlop@1.1.0": { 535 677 "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", 536 678 "dependencies": [ 537 679 "dequal" 538 680 ] 681 + }, 682 + "dotenv@16.6.1": { 683 + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==" 539 684 }, 540 685 "esbuild@0.25.8": { 541 686 "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", ··· 603 748 "scripts": true, 604 749 "bin": true 605 750 }, 751 + "escodegen@2.1.0": { 752 + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", 753 + "dependencies": [ 754 + "esprima", 755 + "estraverse", 756 + "esutils" 757 + ], 758 + "optionalDependencies": [ 759 + "source-map" 760 + ], 761 + "bin": true 762 + }, 763 + "esprima@4.0.1": { 764 + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 765 + "bin": true 766 + }, 767 + "estraverse@5.3.0": { 768 + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" 769 + }, 770 + "esutils@2.0.3": { 771 + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" 772 + }, 773 + "execa@5.1.1": { 774 + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", 775 + "dependencies": [ 776 + "cross-spawn", 777 + "get-stream", 778 + "human-signals", 779 + "is-stream", 780 + "merge-stream", 781 + "npm-run-path", 782 + "onetime", 783 + "signal-exit", 784 + "strip-final-newline" 785 + ] 786 + }, 787 + "fill-range@7.1.1": { 788 + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 789 + "dependencies": [ 790 + "to-regex-range" 791 + ] 792 + }, 606 793 "framer-motion@12.23.12": { 607 794 "integrity": "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==", 608 795 "dependencies": [ ··· 611 798 "tslib" 612 799 ] 613 800 }, 801 + "fsevents@2.3.3": { 802 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 803 + "os": ["darwin"], 804 + "scripts": true 805 + }, 806 + "get-stream@6.0.1": { 807 + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" 808 + }, 809 + "glob-parent@5.1.2": { 810 + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 811 + "dependencies": [ 812 + "is-glob" 813 + ] 814 + }, 614 815 "hast-util-is-element@3.0.0": { 615 816 "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", 616 817 "dependencies": [ ··· 639 840 "@types/hast" 640 841 ] 641 842 }, 843 + "hono@4.8.4": { 844 + "integrity": "sha512-KOIBp1+iUs0HrKztM4EHiB2UtzZDTBihDtOF5K6+WaJjCPeaW4Q92R8j63jOhvJI5+tZSMuKD9REVEXXY9illg==" 845 + }, 642 846 "html-void-elements@3.0.0": { 643 847 "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==" 644 848 }, 849 + "human-signals@2.1.0": { 850 + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" 851 + }, 852 + "is-binary-path@2.1.0": { 853 + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 854 + "dependencies": [ 855 + "binary-extensions" 856 + ] 857 + }, 858 + "is-extglob@2.1.1": { 859 + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" 860 + }, 861 + "is-glob@4.0.3": { 862 + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 863 + "dependencies": [ 864 + "is-extglob" 865 + ] 866 + }, 867 + "is-number@7.0.0": { 868 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" 869 + }, 870 + "is-stream@2.0.1": { 871 + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" 872 + }, 873 + "is-what@4.1.16": { 874 + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==" 875 + }, 876 + "isexe@2.0.0": { 877 + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" 878 + }, 645 879 "lit-element@4.2.1": { 646 880 "integrity": "sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==", 647 881 "dependencies": [ ··· 678 912 "vfile" 679 913 ] 680 914 }, 915 + "merge-anything@5.1.7": { 916 + "integrity": "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==", 917 + "dependencies": [ 918 + "is-what" 919 + ] 920 + }, 921 + "merge-stream@2.0.0": { 922 + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" 923 + }, 924 + "meriyah@6.1.4": { 925 + "integrity": "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==" 926 + }, 681 927 "micromark-util-character@2.1.1": { 682 928 "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", 683 929 "dependencies": [ ··· 702 948 "micromark-util-types@2.0.2": { 703 949 "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==" 704 950 }, 951 + "mime@4.0.7": { 952 + "integrity": "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==", 953 + "bin": true 954 + }, 955 + "mimic-fn@2.1.0": { 956 + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" 957 + }, 705 958 "mini-svg-data-uri@1.4.4": { 706 959 "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", 707 960 "bin": true ··· 722 975 "tslib" 723 976 ] 724 977 }, 978 + "normalize-path@3.0.0": { 979 + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" 980 + }, 981 + "npm-run-path@4.0.1": { 982 + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", 983 + "dependencies": [ 984 + "path-key" 985 + ] 986 + }, 987 + "onetime@5.1.2": { 988 + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 989 + "dependencies": [ 990 + "mimic-fn" 991 + ] 992 + }, 725 993 "oniguruma-parser@0.12.1": { 726 994 "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==" 727 995 }, ··· 733 1001 "regex-recursion" 734 1002 ] 735 1003 }, 1004 + "path-key@3.1.1": { 1005 + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" 1006 + }, 1007 + "picocolors@1.1.1": { 1008 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" 1009 + }, 1010 + "picomatch@2.3.1": { 1011 + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" 1012 + }, 736 1013 "polished@4.3.1": { 737 1014 "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", 738 1015 "dependencies": [ ··· 742 1019 "property-information@7.1.0": { 743 1020 "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==" 744 1021 }, 1022 + "readdirp@3.6.0": { 1023 + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1024 + "dependencies": [ 1025 + "picomatch" 1026 + ] 1027 + }, 745 1028 "regex-recursion@6.0.2": { 746 1029 "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", 747 1030 "dependencies": [ ··· 757 1040 "regex-utilities" 758 1041 ] 759 1042 }, 1043 + "scule@1.3.0": { 1044 + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==" 1045 + }, 1046 + "shebang-command@2.0.0": { 1047 + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1048 + "dependencies": [ 1049 + "shebang-regex" 1050 + ] 1051 + }, 1052 + "shebang-regex@3.0.0": { 1053 + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" 1054 + }, 760 1055 "shiki@3.8.1": { 761 1056 "integrity": "sha512-+MYIyjwGPCaegbpBeFN9+oOifI8CKiKG3awI/6h3JeT85c//H2wDW/xCJEGuQ5jPqtbboKNqNy+JyX9PYpGwNg==", 762 1057 "dependencies": [ ··· 770 1065 "@types/hast" 771 1066 ] 772 1067 }, 1068 + "signal-exit@3.0.7": { 1069 + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" 1070 + }, 1071 + "sisteransi@1.0.5": { 1072 + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" 1073 + }, 1074 + "source-map@0.6.1": { 1075 + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 1076 + }, 773 1077 "space-separated-tokens@2.0.2": { 774 1078 "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" 775 1079 }, ··· 778 1082 "dependencies": [ 779 1083 "character-entities-html4", 780 1084 "character-entities-legacy" 1085 + ] 1086 + }, 1087 + "strip-final-newline@2.0.0": { 1088 + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" 1089 + }, 1090 + "to-regex-range@5.0.1": { 1091 + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1092 + "dependencies": [ 1093 + "is-number" 781 1094 ] 782 1095 }, 783 1096 "trim-lines@3.0.1": { ··· 836 1149 "vfile-message" 837 1150 ] 838 1151 }, 1152 + "which@2.0.2": { 1153 + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1154 + "dependencies": [ 1155 + "isexe" 1156 + ], 1157 + "bin": true 1158 + }, 1159 + "wildcard-match@5.1.4": { 1160 + "integrity": "sha512-wldeCaczs8XXq7hj+5d/F38JE2r7EXgb6WQDM84RVwxy81T/sxB5e9+uZLK9Q9oNz1mlvjut+QtvgaOQFPVq/g==" 1161 + }, 839 1162 "xstate@5.20.2": { 840 1163 "integrity": "sha512-GZmLmc+WPKfFRxuTDAxCg0cUhS/ZnWaRD86DO8MKizeK4a050jd5k7UNnIQ2jJDWRig2/r0tmVXeezUNIhoz5Q==" 841 1164 }, 1165 + "yaml-to-momoa@0.0.6": { 1166 + "integrity": "sha512-H6OxymcTIB5fTCQV7/+ETO9Wh6v1vpBDpmW94XnscKE+jQl6x58us/G6r6z5IiPCi5wuSvJ+0wipUsp0s2/Yyg==", 1167 + "dependencies": [ 1168 + "@humanwhocodes/momoa", 1169 + "yaml" 1170 + ] 1171 + }, 1172 + "yaml@2.8.0": { 1173 + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", 1174 + "bin": true 1175 + }, 842 1176 "zwitch@2.0.4": { 843 1177 "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" 844 1178 } ··· 858 1192 }, 859 1193 "workspace": { 860 1194 "dependencies": [ 1195 + "npm:lit@^3.3.1", 861 1196 "npm:xstate@^5.20.2" 862 1197 ], 863 1198 "members": { ··· 888 1223 "jsr:@std/http@^1.0.20", 889 1224 "jsr:@std/path@^1.1.1", 890 1225 "npm:esbuild@~0.25.9" 1226 + ] 1227 + }, 1228 + "packages/theme": { 1229 + "dependencies": [ 1230 + "npm:@terrazzo/parser@~0.10.2", 1231 + "npm:@terrazzo/plugin-css@~0.10.2", 1232 + "npm:@terrazzo/plugin-js@~0.10.1" 891 1233 ] 892 1234 }, 893 1235 "packages/wc": {
+9 -6
packages/core/favicon.ts
··· 19 19 const encoder = new TextEncoder(); 20 20 const hash = await crypto.subtle.digest("SHA-256", encoder.encode(content)); 21 21 const hashStr = encodeHex(hash); 22 - 22 + 23 23 // Generate colors 24 24 const baseColor = hsl(...colorHash.hsl(hashStr)); 25 25 const complementaryColor = adjustHue(180, baseColor); 26 - 26 + 27 27 // Generate shapes and construct SVG directly 28 28 const rectRadius = size * 0.25; 29 29 const center = size / 2; 30 30 const circleRadius = size * 0.25; 31 - 32 - const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewbox="0 0 ${size} ${size}">` + 31 + 32 + const svg = 33 + `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewbox="0 0 ${size} ${size}">` + 33 34 `<path d="M ${rectRadius.toFixed(2)} 0 ` + 34 35 `L ${(size - rectRadius).toFixed(2)} 0 ` + 35 36 `Q ${size} 0 ${size} ${rectRadius.toFixed(2)} ` + ··· 39 40 `Q 0 ${size} 0 ${(size - rectRadius).toFixed(2)} ` + 40 41 `L 0 ${rectRadius.toFixed(2)} ` + 41 42 `Q 0 0 ${rectRadius.toFixed(2)} 0 Z" fill="${baseColor}" />` + 42 - `<circle cx="${center}" cy="${center}" r="${circleRadius.toFixed(2)}" fill="${complementaryColor}" />` + 43 + `<circle cx="${center}" cy="${center}" r="${ 44 + circleRadius.toFixed(2) 45 + }" fill="${complementaryColor}" />` + 43 46 `</svg>`; 44 47 45 48 return svgToUri(svg); 46 - } 49 + }
+3 -1
packages/core/renderer.ts
··· 3 3 import { generateFavicon } from "./favicon.ts"; 4 4 import { Eta } from "@eta-dev/eta"; 5 5 import { resolve } from "@std/path"; 6 + import { compileCss } from "@morkdeck/theme"; 6 7 import type { RenderOptions } from "./types.ts"; 7 8 8 9 const eta = new Eta({ ··· 13 14 path: string, 14 15 options?: RenderOptions, 15 16 ) { 16 - const encoder = new TextEncoder(); 17 17 const file = await Deno.readTextFile(path); 18 18 const ast = Markdoc.parse(file); 19 19 ··· 48 48 49 49 // Generate favicon 50 50 const favicon = await generateFavicon(file, 16); 51 + const tokens = await compileCss(); 51 52 52 53 return eta.render("presentation", { 53 54 body: Markdoc.renderers.html(await Promise.resolve(tree)), 54 55 title, 55 56 includes, 56 57 favicon, 58 + tokens, 57 59 }); 58 60 }
+5 -3
packages/core/templates/partials/slide-styles.eta
··· 3 3 <link href="https://fonts.googleapis.com/css2?family=Recursive:slnt,wght,CASL,CRSV,MONO@-15..0,300..1000,0..1,0..1,0..1&display=swap" rel="stylesheet"> 4 4 5 5 <style> 6 + <%= it.tokens %> 7 + 6 8 body { 7 9 margin: 0; 8 10 box-sizing: border-box; 9 11 font-family: "Recursive", sans-serif; 10 - background-color: #191724; 11 - color: #908caa; 12 + background-color: var(--morkdeck-color-base); 13 + color: var(--morkdeck-color-subtle); 12 14 } 13 15 14 16 h1, h2, h3, h4, h5, h6 { 15 17 display: block; 16 - color: #e0def4; 18 + color: var(--morkdeck-color-text); 17 19 margin-bottom: 2cqi; 18 20 } 19 21
+1 -1
packages/core/templates/presentation.eta
··· 5 5 6 6 <%~ include("./partials/favicon", { favicon: it.favicon }) %> 7 7 8 - <%~ include("./partials/slide-styles") %> 8 + <%~ include("./partials/slide-styles", { tokens: it.tokens }) %> 9 9 10 10 <script src="static/bundle.js"></script> 11 11 </head>
+16
packages/theme/deno.json
··· 1 + { 2 + "name": "@morkdeck/theme", 3 + "version": "0.0.0", 4 + "exports": { 5 + ".": "./mod.ts", 6 + "./css": "./tokens.gen.ts" 7 + }, 8 + "imports": { 9 + "@terrazzo/parser": "npm:@terrazzo/parser@^0.10.2", 10 + "@terrazzo/plugin-css": "npm:@terrazzo/plugin-css@^0.10.2", 11 + "@terrazzo/plugin-js": "npm:@terrazzo/plugin-js@^0.10.1" 12 + }, 13 + "tasks": { 14 + "build": "deno run --allow-env --allow-read --allow-write ./typescript.ts" 15 + } 16 + }
+1
packages/theme/mod.ts
··· 1 + export * from "./stylesheet.ts";
+53
packages/theme/stylesheet.ts
··· 1 + import { 2 + build, 3 + type Config, 4 + defineConfig, 5 + parse, 6 + type TokenNormalized, 7 + } from "@terrazzo/parser"; 8 + import pluginCss from "@terrazzo/plugin-css"; 9 + 10 + export function prefixToken(token: TokenNormalized) { 11 + return `--morkdeck-${token.$type}-${token.id.replace(/\./g, "-")}`; 12 + } 13 + 14 + const configBase: Config = { 15 + plugins: [ 16 + pluginCss({ 17 + variableName: prefixToken, 18 + baseSelector: ":root", 19 + }), 20 + ], 21 + }; 22 + 23 + export async function compileCss(themePath?: string) { 24 + const config = defineConfig(configBase, { 25 + cwd: new URL(import.meta.url), 26 + }); 27 + 28 + const tokensUrl = new URL("./tokens", import.meta.url); 29 + const files: Array<{ src: string; filename: URL }> = []; 30 + const tokenSources = Deno.readDir(tokensUrl); 31 + for await (const source of tokenSources) { 32 + if (source.isFile) { 33 + const filename = new URL(`tokens/${source.name}`, tokensUrl); 34 + files.push({ 35 + filename, 36 + src: await Deno.readTextFile(filename), 37 + }); 38 + } 39 + } 40 + 41 + if (themePath) { 42 + const themeUrl = new URL(themePath, Deno.cwd()); 43 + files.push({ 44 + filename: new URL(themePath, Deno.cwd()), 45 + src: await Deno.readTextFile(themeUrl), 46 + }); 47 + } 48 + 49 + const { tokens, sources } = await parse(files, { config }); 50 + const buildResult = await build(tokens, { sources, config }); 51 + 52 + return buildResult.outputFiles.map((f) => f.contents).join("\n\n"); 53 + }
+20
packages/theme/tokens.gen.ts
··· 1 + import { unsafeCSS } from "lit"; 2 + type TokenName = 3 + | "color.base" 4 + | "color.surface" 5 + | "color.overlay" 6 + | "color.muted" 7 + | "color.subtle" 8 + | "color.text" 9 + | "color.danger" 10 + | "color.warning" 11 + | "color.success" 12 + | "color.match" 13 + | "color.bright" 14 + | "color.link" 15 + | "color.highlight.low" 16 + | "color.highlight.med" 17 + | "color.highlight.high" 18 + export function token(name: TokenName) { 19 + return unsafeCSS(`var(--morkdeck-${name.replace(/\./g, "-")})`); 20 + };
+124
packages/theme/tokens/colors.json
··· 1 + { 2 + "base": { 3 + "$type": "color", 4 + "$value": { 5 + "colorSpace": "hsl", 6 + "components": [249, 22, 12], 7 + "hex": "#191724" 8 + } 9 + }, 10 + "surface": { 11 + "$type": "color", 12 + "$value": { 13 + "colorSpace": "hsl", 14 + "components": [247, 23, 15], 15 + "hex": "#1f1d2e" 16 + } 17 + }, 18 + "overlay": { 19 + "$type": "color", 20 + "$value": { 21 + "colorSpace": "hsl", 22 + "components": [248, 25, 18], 23 + "hex": "#26233a" 24 + } 25 + }, 26 + "muted": { 27 + "$type": "color", 28 + "$value": { 29 + "colorSpace": "hsl", 30 + "components": [249, 12, 47], 31 + "hex": "#6e6a86" 32 + } 33 + }, 34 + "subtle": { 35 + "$type": "color", 36 + "$value": { 37 + "colorSpace": "hsl", 38 + "components": [248, 15, 61], 39 + "hex": "#908caa" 40 + } 41 + }, 42 + "text": { 43 + "$type": "color", 44 + "$value": { 45 + "colorSpace": "hsl", 46 + "components": [245, 50, 91], 47 + "hex": "#e0def4" 48 + } 49 + }, 50 + "danger": { 51 + "$type": "color", 52 + "$value": { 53 + "colorSpace": "hsl", 54 + "components": [343, 76, 68], 55 + "hex": "#eb6f92" 56 + } 57 + }, 58 + "warning": { 59 + "$type": "color", 60 + "$value": { 61 + "colorSpace": "hsl", 62 + "components": [35, 88, 72], 63 + "hex": "#f6c177" 64 + } 65 + }, 66 + "success": { 67 + "$type": "color", 68 + "$value": { 69 + "colorSpace": "hsl", 70 + "components": [197, 49, 38], 71 + "hex": "#31748f" 72 + } 73 + }, 74 + "match": { 75 + "$type": "color", 76 + "$value": { 77 + "colorSpace": "hsl", 78 + "components": [2, 55, 83], 79 + "hex": "#ebbcba" 80 + } 81 + }, 82 + "bright": { 83 + "$type": "color", 84 + "$value": { 85 + "colorSpace": "hsl", 86 + "components": [189, 43, 73], 87 + "hex": "#9ccfd8" 88 + } 89 + }, 90 + "link": { 91 + "$type": "color", 92 + "$value": { 93 + "colorSpace": "hsl", 94 + "components": [267, 57, 78], 95 + "hex": "#c4a7e7" 96 + } 97 + }, 98 + "highlight": { 99 + "low": { 100 + "$type": "color", 101 + "$value": { 102 + "colorSpace": "hsl", 103 + "components": [244, 18, 15], 104 + "hex": "#21202e" 105 + } 106 + }, 107 + "med": { 108 + "$type": "color", 109 + "$value": { 110 + "colorSpace": "hsl", 111 + "components": [249, 15, 28], 112 + "hex": "#403d52" 113 + } 114 + }, 115 + "high": { 116 + "$type": "color", 117 + "$value": { 118 + "colorSpace": "hsl", 119 + "components": [248, 13, 36], 120 + "hex": "#524f67" 121 + } 122 + } 123 + } 124 + }
+67
packages/theme/typescript.ts
··· 1 + import { 2 + build, 3 + type Config, 4 + defineConfig, 5 + parse, 6 + type Plugin, 7 + } from "@terrazzo/parser"; 8 + 9 + function cssVariableFn() { 10 + return { 11 + name: "css-variable-fn-typescript", 12 + build({ tokens, outputFile }) { 13 + const output: string[] = []; 14 + 15 + output.push(`import { unsafeCSS } from "lit";`); 16 + output.push("type TokenName ="); 17 + 18 + for (const token of Object.values(tokens)) { 19 + output.push(` | "${token.$type}.${token.id}"`); 20 + } 21 + 22 + output.push(`export function token(name: TokenName) {`); 23 + output.push( 24 + ' return unsafeCSS(`var(--morkdeck-${name.replace(/\\./g, "-")})`);', 25 + ); 26 + output.push("};"); 27 + 28 + outputFile("tokens.gen.ts", output.join("\n")); 29 + 30 + return Promise.resolve(); 31 + }, 32 + } satisfies Plugin; 33 + } 34 + 35 + const configBase: Config = { 36 + plugins: [ 37 + cssVariableFn(), 38 + ], 39 + }; 40 + 41 + export async function compileJs() { 42 + const config = defineConfig(configBase, { 43 + cwd: new URL(import.meta.url), 44 + }); 45 + 46 + const tokensUrl = new URL("./tokens", import.meta.url); 47 + const files: Array<{ src: string; filename: URL }> = []; 48 + const tokenSources = Deno.readDir(tokensUrl); 49 + for await (const source of tokenSources) { 50 + if (source.isFile) { 51 + const filename = new URL(`tokens/${source.name}`, tokensUrl); 52 + files.push({ 53 + filename, 54 + src: await Deno.readTextFile(filename), 55 + }); 56 + } 57 + } 58 + 59 + const { tokens, sources } = await parse(files, { config }); 60 + const buildResult = await build(tokens, { sources, config }); 61 + 62 + for (const { filename, contents } of buildResult.outputFiles) { 63 + await Deno.writeTextFile(new URL(filename, import.meta.url), contents); 64 + } 65 + } 66 + 67 + if (import.meta.main) await compileJs();
+2 -1
packages/wc/components/slide.ts
··· 1 1 import { css, html } from "lit"; 2 2 import { customElement } from "lit/decorators.js"; 3 3 import { consume } from "@lit/context"; 4 + import { token } from "@morkdeck/theme/css"; 4 5 import { observerContext } from "../context.ts"; 5 6 import { MorkdeckElement } from "../element.ts"; 6 7 ··· 31 32 align-items: center; 32 33 33 34 padding: 6cqmin; 34 - background: #1f1d2e; 35 + background: ${token("color.surface")}; 35 36 } 36 37 `; 37 38
+6 -5
packages/wc/components/toolbar.ts
··· 1 + import { css, html } from "lit"; 1 2 import { customElement } from "lit/decorators.js"; 3 + import { token } from "@morkdeck/theme/css"; 2 4 import { MorkdeckElement, subscribe } from "../element.ts"; 3 - import { css, html } from "lit"; 4 5 5 6 @customElement("morkdeck-toolbar") 6 7 export class Toolbar extends MorkdeckElement { ··· 37 38 grid-row-start: 2; 38 39 align-items: center; 39 40 justify-content: space-between; 40 - background-color: #26233a; 41 - border-top: 1px solid #403d52; 41 + background-color: ${token("color.overlay")}; 42 + border-top: 1px solid ${token("color.highlight.med")}; 42 43 transition: transform var(--presentation-spring); 43 44 } 44 45 45 46 .toolset { 46 47 border-left: 1px solid; 47 48 border-right: 1px solid; 48 - border-color: #403d52; 49 + border-color: ${token("color.highlight.med")}; 49 50 display: grid; 50 51 grid-auto-columns: auto; 51 52 grid-auto-flow: column; ··· 55 56 56 57 .toolset > * + * { 57 58 border-left: 1px solid; 58 - border-color: #403d52; 59 + border-color: ${token("color.highlight.med")}; 59 60 } 60 61 61 62 .tool {