From 54020e01e97ccb58275d231acb8e157707f5c921 Mon Sep 17 00:00:00 2001 From: Ramazan Maksyutov Date: Thu, 25 Dec 2025 00:52:46 +0500 Subject: [PATCH 1/9] feat: draft commit with core logic --- index.html | 146 +++++++------- package-lock.json | 320 +++++++++++++++++++++++++++++- package.json | 12 +- src/assets/data/editor-theme.js | 0 src/assets/data/initialCode.js | 185 +++++++++++++++++ src/assets/scripts/lit-context.js | 189 ++++++++++++++++++ src/assets/style/style.scss | 5 + src/components/code-editor.js | 154 ++++++++++++++ src/components/code-preview.js | 42 ++++ src/components/main-comp.js | 54 +++++ src/components/style-tab.js | 12 +- 11 files changed, 1035 insertions(+), 84 deletions(-) create mode 100644 src/assets/data/editor-theme.js create mode 100644 src/assets/data/initialCode.js create mode 100644 src/assets/scripts/lit-context.js create mode 100644 src/components/code-editor.js create mode 100644 src/components/code-preview.js create mode 100644 src/components/main-comp.js diff --git a/index.html b/index.html index 1eb63ba..cf02094 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,16 @@ - + mlut playground + - + + +
@@ -20,7 +23,7 @@ -
-
+ +
- -
+ +
- -
- -
- HTML - -
- -
- -
-
- - -
- -
-
- - -
- -
+ +
+ +
+ HTML + +
+ +
+ +
+
- + +
+ +
-
- - -
-
+
+ + +
-
+ +
- -
- -
- -
- Preview -
- -
-
- - - -
-
-
+ + +
+ +
+ +
+ +
+ + + + + +
+ +
+ +
+ Preview +
+ +
+
+ + +
+ +
+
+
+
+ diff --git a/package-lock.json b/package-lock.json index e21a6dd..79f2154 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,17 @@ "name": "playground", "version": "0.0.0", "dependencies": { - "lit": "3.3.1" + "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-sass": "^6.0.2", + "@codemirror/theme-one-dark": "^6.1.3", + "@lit-labs/signals": "^0.1.3", + "@lit/context": "^1.1.6", + "codemirror": "^6.0.2", + "lit": "3.3.1", + "thememirror": "^2.0.1" }, "devDependencies": { + "@codemirror/lang-html": "^6.4.11", "@mlut/plugins": "^1.0.3", "eslint": "^8.56.0", "sass-embedded": "^1.93.2", @@ -25,6 +33,159 @@ "dev": true, "license": "(Apache-2.0 AND BSD-3-Clause)" }, + "node_modules/@codemirror/autocomplete": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", + "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.1.tgz", + "integrity": "sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", + "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.11", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", + "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.12" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz", + "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sass": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sass/-/lang-sass-6.0.2.tgz", + "integrity": "sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/sass": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", + "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.2.tgz", + "integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.35.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.11", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz", + "integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", + "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz", + "integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.39.4", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.4.tgz", + "integrity": "sha512-xMF6OfEAUVY5Waega4juo1QGACfNkNF+aJLqpd8oUJz96ms2zbfQ9Gh35/tI3y8akEV31FruKfj7hBnIU/nkqA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.5.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.10", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", @@ -568,12 +729,101 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@lezer/common": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.4.0.tgz", + "integrity": "sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==", + "license": "MIT" + }, + "node_modules/@lezer/css": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz", + "integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.12.tgz", + "integrity": "sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", + "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.5.tgz", + "integrity": "sha512-/YTRKP5yPPSo1xImYQk7AZZMAgap0kegzqCSYHjAL9x1AZ0ZQW+IpcEzMKagCsbTsLnVeWkxYrCNeXG8xEPrjg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/sass": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/sass/-/sass-1.1.0.tgz", + "integrity": "sha512-3mMGdCTUZ/84ArHOuXWQr37pnf7f+Nw9ycPUeKX+wu19b7pSMcZGLbaXwvD2APMBDOGxPmpK/O6S1v1EvLoqgQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lit-labs/signals": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@lit-labs/signals/-/signals-0.1.3.tgz", + "integrity": "sha512-P0yWgH5blwVyEwBg+WFspLzeu1i0ypJP1QB0l1Omr9qZLIPsUu0p4Fy2jshOg7oQyha5n163K3GJGeUhQQ682Q==", + "license": "BSD-3-Clause", + "dependencies": { + "lit": "^2.0.0 || ^3.0.0", + "signal-polyfill": "^0.2.0" + } + }, "node_modules/@lit-labs/ssr-dom-shim": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.4.0.tgz", "integrity": "sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==", "license": "BSD-3-Clause" }, + "node_modules/@lit/context": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.6.tgz", + "integrity": "sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^1.6.2 || ^2.1.0" + } + }, "node_modules/@lit/reactive-element": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.1.tgz", @@ -583,10 +833,16 @@ "@lit-labs/ssr-dom-shim": "^1.4.0" } }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "license": "MIT" + }, "node_modules/@mlut/core": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@mlut/core/-/core-2.1.3.tgz", - "integrity": "sha512-POeYni3gyzbb5UjnsK1lazYriSFnyII5ag7TXh7EvYazv39v5mlTWPn92V2fcjZNDn4i5OozvX+Szk8I+VbrCA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mlut/core/-/core-2.2.0.tgz", + "integrity": "sha512-+7v6tFQupkx/VTglgYc7RFcqxSx01eJWcbqxoiWTNO+8C7EnF2yxm/9jpJURvBa1S66A+FRtHqRjLDIlj+EqwQ==", "dev": true, "license": "MIT" }, @@ -1447,6 +1703,21 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/codemirror": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", + "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1481,6 +1752,12 @@ "dev": true, "license": "MIT" }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1852,9 +2129,9 @@ "license": "ISC" }, "node_modules/fs-extra": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", - "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", "dev": true, "license": "MIT", "dependencies": { @@ -2988,6 +3265,12 @@ "node": ">=8" } }, + "node_modules/signal-polyfill": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/signal-polyfill/-/signal-polyfill-0.2.2.tgz", + "integrity": "sha512-p63Y4Er5/eMQ9RHg0M0Y64NlsQKpiu6MDdhBXpyywRuWiPywhJTpKJ1iB5K2hJEbFZ0BnDS7ZkJ+0AfTuL37Rg==", + "license": "Apache-2.0" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3024,6 +3307,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-mod": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -3070,6 +3359,17 @@ "dev": true, "license": "MIT" }, + "node_modules/thememirror": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/thememirror/-/thememirror-2.0.1.tgz", + "integrity": "sha512-d5i6FVvWWPkwrm4cHLI3t9AT1OrkAt7Ig8dtdYSofgF7C/eiyNuq6zQzSTusWTde3jpW9WLvA9J/fzNKMUsd0w==", + "license": "MIT", + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -3326,6 +3626,12 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", diff --git a/package.json b/package.json index ab63be9..f69988e 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,20 @@ "build": "vite build", "preview": "vite preview", "mlut": "npx mlut -i src/assets/style/style.scss -w", - "lint": "npx eslint ./src/**/*.js" + "lint": "npx eslint ./src/**/*.js" }, "dependencies": { - "lit": "3.3.1" + "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-sass": "^6.0.2", + "@codemirror/theme-one-dark": "^6.1.3", + "@lit-labs/signals": "^0.1.3", + "@lit/context": "^1.1.6", + "codemirror": "^6.0.2", + "lit": "3.3.1", + "thememirror": "^2.0.1" }, "devDependencies": { + "@codemirror/lang-html": "^6.4.11", "@mlut/plugins": "^1.0.3", "eslint": "^8.56.0", "sass-embedded": "^1.93.2", diff --git a/src/assets/data/editor-theme.js b/src/assets/data/editor-theme.js new file mode 100644 index 0000000..e69de29 diff --git a/src/assets/data/initialCode.js b/src/assets/data/initialCode.js new file mode 100644 index 0000000..f1a1ab1 --- /dev/null +++ b/src/assets/data/initialCode.js @@ -0,0 +1,185 @@ +const initialCode = { +html: ` +
+ +
+ + mlut logo + + +

+ Make CSS exciting again! +

+ +

+ Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity +

+ +
+
+
+
+`, +css:` +.wrapper { + display: block; + max-width: 1200px; + margin: 0 auto; +} + +.wrapper { + padding-right: calc(var(--ml-gg) * 1); + padding-left: calc(var(--ml-gg) * 1); +} + +html { + --ml-heroPadding: calc(var(--ml-headerH) + 10px); + --ml-headerH: 6rem; +} +@media (prefers-color-scheme: dark) { + html { + --ml-accent900:#fff; + --ml-accent850:rgb(209,213,219,1); + --ml-core750:#121828; + --ml-core650:#251942; + --ml-core600:#321933; + } +} +@media (prefers-color-scheme: light) { + html { + --ml-accent900:rgb(17,24,39); + --ml-accent850:rgb(41,42,51,1); + --ml-core750:rgb(236, 240, 246,0.5); + --ml-core650:rgba(218,178,255,0.1); + --ml-core600:rgba(142,197,255,0.4); + } +} + +.-Gdl120d\\\,\\\$core750\\\,\\\$core650\\\,\\\$core600 { + background-image: linear-gradient(120deg, var(--ml-core750), var(--ml-core650), var(--ml-core600)); +} + +.H100vh { + height: 100vh; +} + +.D { + display: block; +} + +.P-\\\$heroPadding\\\;0\\\;5u { + padding: var(--ml-heroPadding) 0px 1.25rem; +} + +.Jc-c { + justify-content: center; +} + +.Mxw480 { + max-width: 480px; +} + +.W80p { + width: 80%; +} + +.Txa-c { + text-align: center; +} + +.C-\\\$accent900 { + color: var(--ml-accent900); +} + +.Fns8u { + font-size: 2rem; +} + +.Lnh1\\\.1 { + line-height: 1.1; +} + +.P0\\\;1u { + padding: 0px 0.25rem; +} + +.C-\\\$accent850 { + color: var(--ml-accent850); +} + +.P0\\\;2u { + padding: 0px 0.5rem; +} + +.Mxw750 { + max-width: 750px; +} + +.Fns4\\\.4u { + font-size: 1.1rem; +} + +.Fld-r { + flex-direction: row; +} + +.Flw-w { + flex-wrap: wrap; +} + +.Gap3u { + gap: 0.75rem; +} + +.P0\\\;5u { + padding: 0px 1.25rem; +} + +@media (min-width: 768px) { + .md_W100p { + width: 100%; + } +} +@media (min-width: 768px) { + .md_Fns10u { + font-size: 2.5rem; + } +} + +.M0\\\;a\\\;5u { + margin: 0px auto 1.25rem; +} +`, +sass:` +@use 'mlut' with ( + $jit:( + "output":"style.css", + "content":"index.html" + ) +); + +@media (prefers-color-scheme: dark){ + html{ + --ml-accent900:#fff; + --ml-accent850:rgb(209,213,219,1); + --ml-core750:#121828; + --ml-core650:#251942; + --ml-core600:#321933; + } +} + +@media (prefers-color-scheme: light){ + html{ + --ml-accent900:rgb(17,24,39); + --ml-accent850:rgb(41,42,51,1); + --ml-core750:rgb(236,240,246,0.5); + --ml-core650:rgba(218,178,255,0.1); + --ml-core600:rgba(142,197,255,0.4); + } +} +` +} + +export { initialCode } \ No newline at end of file diff --git a/src/assets/scripts/lit-context.js b/src/assets/scripts/lit-context.js new file mode 100644 index 0000000..278ffdb --- /dev/null +++ b/src/assets/scripts/lit-context.js @@ -0,0 +1,189 @@ +import {signal} from "@lit-labs/signals" + +const layout = signal( ` +
+ +
+ + mlut logo + + +

+ Make CSS exciting again! +

+ +

+ Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity +

+ +
+
+
+
+`); + +const styles = signal(` +.wrapper { + display: block; + max-width: 1200px; + margin: 0 auto; +} + +.wrapper { + padding-right: calc(var(--ml-gg) * 1); + padding-left: calc(var(--ml-gg) * 1); +} + +html { + --ml-heroPadding: calc(var(--ml-headerH) + 10px); + --ml-headerH: 6rem; +} +@media (prefers-color-scheme: dark) { + html { + --ml-accent900:#fff; + --ml-accent850:rgb(209,213,219,1); + --ml-core750:#121828; + --ml-core650:#251942; + --ml-core600:#321933; + } +} +@media (prefers-color-scheme: light) { + html { + --ml-accent900:rgb(17,24,39); + --ml-accent850:rgb(41,42,51,1); + --ml-core750:rgb(236, 240, 246,0.5); + --ml-core650:rgba(218,178,255,0.1); + --ml-core600:rgba(142,197,255,0.4); + } +} + +.-Gdl120d\\\,\\\$core750\\\,\\\$core650\\\,\\\$core600 { + background-image: linear-gradient(120deg, var(--ml-core750), var(--ml-core650), var(--ml-core600)); +} + +.H100vh { + height: 100vh; +} + +.D { + display: block; +} + +.P-\\\$heroPadding\\\;0\\\;5u { + padding: var(--ml-heroPadding) 0px 1.25rem; +} + +.Jc-c { + justify-content: center; +} + +.Mxw480 { + max-width: 480px; +} + +.W80p { + width: 80%; +} + +.Txa-c { + text-align: center; +} + +.C-\\\$accent900 { + color: var(--ml-accent900); +} + +.Fns8u { + font-size: 2rem; +} + +.Lnh1\\\.1 { + line-height: 1.1; +} + +.P0\\\;1u { + padding: 0px 0.25rem; +} + +.C-\\\$accent850 { + color: var(--ml-accent850); +} + +.P0\\\;2u { + padding: 0px 0.5rem; +} + +.Mxw750 { + max-width: 750px; +} + +.Fns4\\\.4u { + font-size: 1.1rem; +} + +.Fld-r { + flex-direction: row; +} + +.Flw-w { + flex-wrap: wrap; +} + +.Gap3u { + gap: 0.75rem; +} + +.P0\\\;5u { + padding: 0px 1.25rem; +} + +@media (min-width: 768px) { + .md_W100p { + width: 100%; + } +} +@media (min-width: 768px) { + .md_Fns10u { + font-size: 2.5rem; + } +} + +.M0\\\;a\\\;5u { + margin: 0px auto 1.25rem; +} +`); + +const config = signal(` +@use 'mlut' with ( + $jit:( + "output":"style.css", + "content":"index.html" + ) +); + +@media (prefers-color-scheme: dark){ + html{ + --ml-accent900:#fff; + --ml-accent850:rgb(209,213,219,1); + --ml-core750:#121828; + --ml-core650:#251942; + --ml-core600:#321933; + } +} + +@media (prefers-color-scheme: light){ + html{ + --ml-accent900:rgb(17,24,39); + --ml-accent850:rgb(41,42,51,1); + --ml-core750:rgb(236,240,246,0.5); + --ml-core650:rgba(218,178,255,0.1); + --ml-core600:rgba(142,197,255,0.4); + } +} +`); + +const count = signal(0) + +export {layout, styles, config, count} \ No newline at end of file diff --git a/src/assets/style/style.scss b/src/assets/style/style.scss index 5a97513..421aa6a 100644 --- a/src/assets/style/style.scss +++ b/src/assets/style/style.scss @@ -4,6 +4,11 @@ html { --ml-brand:#f0438c; } +* { + scrollbar-color: var(--ml-accent700) var(--ml-core800); +} + + @media (prefers-color-scheme: light){ html { --ml-core800: #f0f0f1; diff --git a/src/components/code-editor.js b/src/components/code-editor.js new file mode 100644 index 0000000..838516e --- /dev/null +++ b/src/components/code-editor.js @@ -0,0 +1,154 @@ +// Lit imports +import { LitElement, html } from 'lit'; +import { watch, SignalWatcher } from '@lit-labs/signals'; + +// General CodeMirror imports +import { basicSetup } from 'codemirror'; +import { EditorView, keymap, drawSelection} from '@codemirror/view'; +import { indentWithTab } from '@codemirror/commands'; +import { oneDark } from '@codemirror/theme-one-dark'; +import { EditorState, Prec } from '@codemirror/state'; + + +// Language CodeMirror imports +import { html as langHTML } from '@codemirror/lang-html'; +import { css as langCSS } from '@codemirror/lang-css'; +import { sass as langSASS } from '@codemirror/lang-sass'; + +// Data imports + +import { layout, styles, config } from '../assets/scripts/lit-context'; + +const customTheme = Prec.highest(EditorView.theme({ + ".cm-editor": { + backgroundColor: "transparent !important" + }, + ".cm-editor>*": { + backgroundColor: "transparent !important" + }, + ".cm-content": { + backgroundColor: "transparent !important" + }, + ".cm-selectionMatch": { + backgroundColor: "rgba(255, 200, 0, 0.2)" + }, + ".cm-line::selection": { + backgroundColor: "red !important" + } +})) + +export class CodeEditor extends LitElement { + + static properties = { + lang: { type: String }, + content: { type: Object }, + timeoutID: { type: Number, state: false }, + view: { type: Object } + }; + + createRenderRoot() { + return this; + } + + constructor() { + super(); + this.content = ''; + } + + firstUpdated() { + this.view = new EditorView(this.setEditorOptions(this.lang)); + } + + setEditorOptions(lang) { + + basicSetup.highlightSelectionMatches = false + + const editorSettings = { + parent: this.querySelector('#wrapper'), + extensions: [ + basicSetup, + EditorView.lineWrapping, + keymap.of([indentWithTab]), + drawSelection(), + this.setDocChangeHandler(), + customTheme + ] + }; + + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + editorSettings.extensions.push(oneDark); + } + + switch (lang) { + case 'html': + editorSettings.extensions.push(langHTML()); + + return { + ...editorSettings, + doc: layout.get().trim(), + }; + case 'css': + editorSettings.extensions.push( + langCSS(), + EditorState.readOnly.of(true), + EditorView.editable.of(false)); + + return { + ...editorSettings, + doc: styles.get().trim() + }; + case 'sass': + editorSettings.extensions.push(langSASS()); + + return { + ...editorSettings, + doc: config.get().trim(), + }; + } + } + + ы + + setDocChangeHandler() { + return EditorView.updateListener.of((update) => { + if (update.docChanged) { + clearTimeout(this.timeoutID); + + if (this.lang !== 'css') { + this.timeoutID = setTimeout(() => { + + this.dispatchEvent(new CustomEvent('editor-update', { + detail: { + target: this, + updatedData: update.state.doc.toString(), + lang: this.lang + }, + bubbles: true + })); + }, 1000); + } + + } + }); + } + + updateFromParent() { + const transition = this.view.state.update({ + changes: { + from: 0, + to: this.view.state.doc.length, + insert: styles.get() + } + }); + + this.view.dispatch(transition); + } + + render() { + return html` +
+ `; + } +} + +customElements.define('code-editor', CodeEditor); \ No newline at end of file diff --git a/src/components/code-preview.js b/src/components/code-preview.js new file mode 100644 index 0000000..e85b515 --- /dev/null +++ b/src/components/code-preview.js @@ -0,0 +1,42 @@ +import { LitElement, html } from 'lit'; +import { initialCode } from '../assets/data/initialCode'; +import { watch, SignalWatcher } from '@lit-labs/signals'; +import { layout, styles, config, count } from '../assets/scripts/lit-context'; + +export class CodePreview extends SignalWatcher(LitElement) { + + createRenderRoot() { + return this; + } + + static properties = { + documentContent: { type: String } + }; + + constructor() { + super(); + this.documentContent = ''; + } + + render() { + return html` + + `; + } +} + +customElements.define('code-preview', CodePreview); \ No newline at end of file diff --git a/src/components/main-comp.js b/src/components/main-comp.js new file mode 100644 index 0000000..0ce027c --- /dev/null +++ b/src/components/main-comp.js @@ -0,0 +1,54 @@ +import { LitElement, html } from 'lit'; +import { layout, styles, config } from '../assets/scripts/lit-context'; + +const cssEditor = document.querySelector('code-editor[lang="css"]'); + +export class MainComp extends LitElement { + + createRenderRoot() { + return this.querySelector('main'); + } + + constructor() { + super(); + this.addEventListener('editor-update', (event) => this.handleChildUpdate(event)); + } + + handleChildUpdate(event) { + + if (event.detail.lang === 'html') { + layout.set(event.detail.updatedData); + } else if (event.detail.lang === 'sass') { + config.set(event.detail.updatedData); + } + console.log(event.detail.lang) + + try { + this.buildStyles(layout.get(), config.get()); + cssEditor.updateFromParent(); + } catch (err) { + console.log(err.message); + layout.set(` +

+ ${err.message} +

`) + }1 + } + + buildStyles(layout, config) { + // throw new Error('Something went wrong!'); + const array = layout.split('\n'); + styles.set(array[0]); + } + + render() { + return html` +
+ +
+ `; + } + +} + +customElements.define('main-comp', MainComp); \ No newline at end of file diff --git a/src/components/style-tab.js b/src/components/style-tab.js index 949beff..19c6986 100644 --- a/src/components/style-tab.js +++ b/src/components/style-tab.js @@ -25,15 +25,15 @@ export class StyleTab extends LitElement { input.checked = this.checked; if (this.checked === 'checked') { - this.displayTextArea(); + this.displayEditor(); } } } - displayTextArea() { - const textareas = document.querySelectorAll('textarea[data-type="style"]'); - textareas.forEach((el, index) => { - if (el.id === `${this.radioId.toLowerCase()}-area`) { + displayEditor() { + const editors = document.querySelectorAll('div[data-type="style"]'); + editors.forEach((el) => { + if (el.getAttribute('data-lang') === `${this.radioId.toLowerCase()}`) { el.classList.add('D'); el.classList.remove('D-n'); } else { @@ -45,7 +45,7 @@ export class StyleTab extends LitElement { handleChange(e) { this.checked = e.target.checked; - this.displayTextArea(); + this.displayEditor(); } render() { From 0929e77185958f89164e5f160d615e6ec6d97296 Mon Sep 17 00:00:00 2001 From: Ramazan Maksyutov Date: Mon, 29 Dec 2025 00:52:10 +0500 Subject: [PATCH 2/9] feat: add loaders, error fallbacks and enhance the logic --- index.html | 147 ++++++++-------- package-lock.json | 269 +++++++++++++++++++++++++++--- package.json | 8 +- src/assets/data/editor-theme.js | 0 src/assets/data/initial-code.js | 52 ++++++ src/assets/data/initialCode.js | 185 -------------------- src/assets/img/icons.svg | 3 + src/assets/scripts/event-bus.js | 26 +++ src/assets/scripts/lit-context.js | 189 --------------------- src/assets/style/style.scss | 44 ++++- src/components/code-editor.js | 108 ++++++------ src/components/code-preview.js | 117 ++++++++++--- src/components/content-loader.js | 16 ++ src/components/copy-button.js | 55 ++++++ src/components/error-fallback.js | 23 +++ src/components/main-comp.js | 50 ++---- src/components/style-tab.js | 45 +---- src/components/tab-switch.js | 59 +++++++ vite.config.js | 2 +- 19 files changed, 770 insertions(+), 628 deletions(-) delete mode 100644 src/assets/data/editor-theme.js create mode 100644 src/assets/data/initial-code.js delete mode 100644 src/assets/data/initialCode.js create mode 100644 src/assets/scripts/event-bus.js delete mode 100644 src/assets/scripts/lit-context.js create mode 100644 src/components/content-loader.js create mode 100644 src/components/copy-button.js create mode 100644 src/components/error-fallback.js create mode 100644 src/components/tab-switch.js diff --git a/index.html b/index.html index cf02094..a10f513 100644 --- a/index.html +++ b/index.html @@ -6,13 +6,9 @@ mlut playground - - - - -
+
@@ -21,97 +17,90 @@
- + -
- - -
+
- -
- - -
- -
- HTML - -
- -
- -
-
- - -
- -
- -
- - +
+ +
+ +
+ +
+ +
+ HTML + +
+ +
+ +
- - + +
+ +
- - -
- -
- -
- -
-
- -
- - -
- -
- -
- Preview -
- + +
+ +
+ +
+ Preview +
+ +
+ +
+ + +
+ + + + + + + + + + + + - -
- -
-
-
- - diff --git a/package-lock.json b/package-lock.json index 79f2154..984eca9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,16 +9,20 @@ "version": "0.0.0", "dependencies": { "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-html": "^6.4.11", "@codemirror/lang-sass": "^6.0.2", "@codemirror/theme-one-dark": "^6.1.3", - "@lit-labs/signals": "^0.1.3", "@lit/context": "^1.1.6", + "@lit/task": "^1.0.3", + "@octokit/plugin-retry": "^8.0.3", + "@octokit/rest": "^22.0.1", + "@types/node": "^25.0.3", "codemirror": "^6.0.2", "lit": "3.3.1", + "path-browserify-esm": "^1.0.6", "thememirror": "^2.0.1" }, "devDependencies": { - "@codemirror/lang-html": "^6.4.11", "@mlut/plugins": "^1.0.3", "eslint": "^8.56.0", "sass-embedded": "^1.93.2", @@ -74,7 +78,6 @@ "version": "6.4.11", "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", - "dev": true, "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -92,7 +95,6 @@ "version": "6.2.4", "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz", "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==", - "dev": true, "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -756,10 +758,9 @@ } }, "node_modules/@lezer/html": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.12.tgz", - "integrity": "sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw==", - "dev": true, + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz", + "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==", "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -771,7 +772,6 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", - "dev": true, "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -799,16 +799,6 @@ "@lezer/lr": "^1.0.0" } }, - "node_modules/@lit-labs/signals": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@lit-labs/signals/-/signals-0.1.3.tgz", - "integrity": "sha512-P0yWgH5blwVyEwBg+WFspLzeu1i0ypJP1QB0l1Omr9qZLIPsUu0p4Fy2jshOg7oQyha5n163K3GJGeUhQQ682Q==", - "license": "BSD-3-Clause", - "dependencies": { - "lit": "^2.0.0 || ^3.0.0", - "signal-polyfill": "^0.2.0" - } - }, "node_modules/@lit-labs/ssr-dom-shim": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.4.0.tgz", @@ -833,6 +823,15 @@ "@lit-labs/ssr-dom-shim": "^1.4.0" } }, + "node_modules/@lit/task": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lit/task/-/task-1.0.3.tgz", + "integrity": "sha512-1gJGJl8WON+2j0y9xfcD+XsS1rvcy3XDgsIhcdUW++yTR8ESjZW6o7dn8M8a4SZM8NnJe6ynS2cKWwsbfLOurg==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^1.0.0 || ^2.0.0" + } + }, "node_modules/@marijn/find-cluster-break": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", @@ -896,6 +895,177 @@ "node": ">= 8" } }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", + "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.3", + "@octokit/request": "^10.0.6", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", + "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", + "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.6", + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", + "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", + "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz", + "integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-8.0.3.tgz", + "integrity": "sha512-vKGx1i3MC0za53IzYBSBXcrhmd+daQDzuZfYDd52X5S0M2otf3kVZTVP8bLA3EkU0lTvd1WEC2OlNNa4G+dohA==", + "license": "MIT", + "dependencies": { + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=7" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.7.tgz", + "integrity": "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.2", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/rest": { + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz", + "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==", + "license": "MIT", + "dependencies": { + "@octokit/core": "^7.0.6", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-request-log": "^6.0.0", + "@octokit/plugin-rest-endpoint-methods": "^17.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, "node_modules/@parcel/watcher": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", @@ -1521,6 +1691,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", + "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -1614,6 +1793,18 @@ "dev": true, "license": "MIT" }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "license": "Apache-2.0" + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -2031,6 +2222,22 @@ "node": ">=0.10.0" } }, + "node_modules/fast-content-type-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", + "integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2621,6 +2828,12 @@ "node": ">=6" } }, + "node_modules/path-browserify-esm": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-browserify-esm/-/path-browserify-esm-1.0.6.tgz", + "integrity": "sha512-9nUwYvvu/yq1PYrUyYCihNWmpzacaRYF6gGbjLWErrZ4MRDWyfPN7RpE8E7tsw8eqBU/rr7mcoTXbS+Vih8uUA==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3265,12 +3478,6 @@ "node": ">=8" } }, - "node_modules/signal-polyfill": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/signal-polyfill/-/signal-polyfill-0.2.2.tgz", - "integrity": "sha512-p63Y4Er5/eMQ9RHg0M0Y64NlsQKpiu6MDdhBXpyywRuWiPywhJTpKJ1iB5K2hJEbFZ0BnDS7ZkJ+0AfTuL37Rg==", - "license": "Apache-2.0" - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3479,6 +3686,18 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", diff --git a/package.json b/package.json index f69988e..e6b9c8d 100644 --- a/package.json +++ b/package.json @@ -12,16 +12,20 @@ }, "dependencies": { "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-html": "^6.4.11", "@codemirror/lang-sass": "^6.0.2", "@codemirror/theme-one-dark": "^6.1.3", - "@lit-labs/signals": "^0.1.3", "@lit/context": "^1.1.6", + "@lit/task": "^1.0.3", + "@octokit/plugin-retry": "^8.0.3", + "@octokit/rest": "^22.0.1", + "@types/node": "^25.0.3", "codemirror": "^6.0.2", "lit": "3.3.1", + "path-browserify-esm": "^1.0.6", "thememirror": "^2.0.1" }, "devDependencies": { - "@codemirror/lang-html": "^6.4.11", "@mlut/plugins": "^1.0.3", "eslint": "^8.56.0", "sass-embedded": "^1.93.2", diff --git a/src/assets/data/editor-theme.js b/src/assets/data/editor-theme.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/assets/data/initial-code.js b/src/assets/data/initial-code.js new file mode 100644 index 0000000..913caf0 --- /dev/null +++ b/src/assets/data/initial-code.js @@ -0,0 +1,52 @@ +const initialLayout = ` +
+ +
+ + mlut logo + + +

+ Make CSS exciting again! +

+ +

+ Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity +

+ +
+
+
+
+` +const initialConfig = ` +@use "@mlut/core/tools"; +@use "@mlut/core/dist/sass/css/styles"; + +@media (prefers-color-scheme: dark){ + html{ + --ml-accent900:#fff; + --ml-accent850:rgb(209,213,219,1); + --ml-core750:#121828; + --ml-core650:#251942; + --ml-core600:#321933; + } +} + +@media (prefers-color-scheme: light){ + html{ + --ml-accent900:rgb(17,24,39); + --ml-accent850:rgb(41,42,51,1); + --ml-core750:rgb(236,240,246,0.5); + --ml-core650:rgba(218,178,255,0.1); + --ml-core600:rgba(142,197,255,0.4); + } +} +` +const loaderStyles = ` + +` + +export {initialLayout, initialConfig} \ No newline at end of file diff --git a/src/assets/data/initialCode.js b/src/assets/data/initialCode.js deleted file mode 100644 index f1a1ab1..0000000 --- a/src/assets/data/initialCode.js +++ /dev/null @@ -1,185 +0,0 @@ -const initialCode = { -html: ` -
- -
- - mlut logo - - -

- Make CSS exciting again! -

- -

- Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity -

- -
-
-
-
-`, -css:` -.wrapper { - display: block; - max-width: 1200px; - margin: 0 auto; -} - -.wrapper { - padding-right: calc(var(--ml-gg) * 1); - padding-left: calc(var(--ml-gg) * 1); -} - -html { - --ml-heroPadding: calc(var(--ml-headerH) + 10px); - --ml-headerH: 6rem; -} -@media (prefers-color-scheme: dark) { - html { - --ml-accent900:#fff; - --ml-accent850:rgb(209,213,219,1); - --ml-core750:#121828; - --ml-core650:#251942; - --ml-core600:#321933; - } -} -@media (prefers-color-scheme: light) { - html { - --ml-accent900:rgb(17,24,39); - --ml-accent850:rgb(41,42,51,1); - --ml-core750:rgb(236, 240, 246,0.5); - --ml-core650:rgba(218,178,255,0.1); - --ml-core600:rgba(142,197,255,0.4); - } -} - -.-Gdl120d\\\,\\\$core750\\\,\\\$core650\\\,\\\$core600 { - background-image: linear-gradient(120deg, var(--ml-core750), var(--ml-core650), var(--ml-core600)); -} - -.H100vh { - height: 100vh; -} - -.D { - display: block; -} - -.P-\\\$heroPadding\\\;0\\\;5u { - padding: var(--ml-heroPadding) 0px 1.25rem; -} - -.Jc-c { - justify-content: center; -} - -.Mxw480 { - max-width: 480px; -} - -.W80p { - width: 80%; -} - -.Txa-c { - text-align: center; -} - -.C-\\\$accent900 { - color: var(--ml-accent900); -} - -.Fns8u { - font-size: 2rem; -} - -.Lnh1\\\.1 { - line-height: 1.1; -} - -.P0\\\;1u { - padding: 0px 0.25rem; -} - -.C-\\\$accent850 { - color: var(--ml-accent850); -} - -.P0\\\;2u { - padding: 0px 0.5rem; -} - -.Mxw750 { - max-width: 750px; -} - -.Fns4\\\.4u { - font-size: 1.1rem; -} - -.Fld-r { - flex-direction: row; -} - -.Flw-w { - flex-wrap: wrap; -} - -.Gap3u { - gap: 0.75rem; -} - -.P0\\\;5u { - padding: 0px 1.25rem; -} - -@media (min-width: 768px) { - .md_W100p { - width: 100%; - } -} -@media (min-width: 768px) { - .md_Fns10u { - font-size: 2.5rem; - } -} - -.M0\\\;a\\\;5u { - margin: 0px auto 1.25rem; -} -`, -sass:` -@use 'mlut' with ( - $jit:( - "output":"style.css", - "content":"index.html" - ) -); - -@media (prefers-color-scheme: dark){ - html{ - --ml-accent900:#fff; - --ml-accent850:rgb(209,213,219,1); - --ml-core750:#121828; - --ml-core650:#251942; - --ml-core600:#321933; - } -} - -@media (prefers-color-scheme: light){ - html{ - --ml-accent900:rgb(17,24,39); - --ml-accent850:rgb(41,42,51,1); - --ml-core750:rgb(236,240,246,0.5); - --ml-core650:rgba(218,178,255,0.1); - --ml-core600:rgba(142,197,255,0.4); - } -} -` -} - -export { initialCode } \ No newline at end of file diff --git a/src/assets/img/icons.svg b/src/assets/img/icons.svg index 033729c..ddde4be 100644 --- a/src/assets/img/icons.svg +++ b/src/assets/img/icons.svg @@ -13,4 +13,7 @@ + + + diff --git a/src/assets/scripts/event-bus.js b/src/assets/scripts/event-bus.js new file mode 100644 index 0000000..4062cb1 --- /dev/null +++ b/src/assets/scripts/event-bus.js @@ -0,0 +1,26 @@ +export class EventBus { + constructor() { + this.events = {} + } + + on(event, handler){ + if (!this.events[event]){ + this.events[event] = [] + } + this.events[event].push(handler) + } + + off(event, handler){ + if (!this.events[event]){ + return + } + this.events[event].filter(h => h !== handler); + } + + emit(event, data){ + if (!this.events[event]){ + throw new Error("There is no such event!") + } + this.events[event].forEach(handler => handler(data)) + } +} \ No newline at end of file diff --git a/src/assets/scripts/lit-context.js b/src/assets/scripts/lit-context.js deleted file mode 100644 index 278ffdb..0000000 --- a/src/assets/scripts/lit-context.js +++ /dev/null @@ -1,189 +0,0 @@ -import {signal} from "@lit-labs/signals" - -const layout = signal( ` -
- -
- - mlut logo - - -

- Make CSS exciting again! -

- -

- Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity -

- -
-
-
-
-`); - -const styles = signal(` -.wrapper { - display: block; - max-width: 1200px; - margin: 0 auto; -} - -.wrapper { - padding-right: calc(var(--ml-gg) * 1); - padding-left: calc(var(--ml-gg) * 1); -} - -html { - --ml-heroPadding: calc(var(--ml-headerH) + 10px); - --ml-headerH: 6rem; -} -@media (prefers-color-scheme: dark) { - html { - --ml-accent900:#fff; - --ml-accent850:rgb(209,213,219,1); - --ml-core750:#121828; - --ml-core650:#251942; - --ml-core600:#321933; - } -} -@media (prefers-color-scheme: light) { - html { - --ml-accent900:rgb(17,24,39); - --ml-accent850:rgb(41,42,51,1); - --ml-core750:rgb(236, 240, 246,0.5); - --ml-core650:rgba(218,178,255,0.1); - --ml-core600:rgba(142,197,255,0.4); - } -} - -.-Gdl120d\\\,\\\$core750\\\,\\\$core650\\\,\\\$core600 { - background-image: linear-gradient(120deg, var(--ml-core750), var(--ml-core650), var(--ml-core600)); -} - -.H100vh { - height: 100vh; -} - -.D { - display: block; -} - -.P-\\\$heroPadding\\\;0\\\;5u { - padding: var(--ml-heroPadding) 0px 1.25rem; -} - -.Jc-c { - justify-content: center; -} - -.Mxw480 { - max-width: 480px; -} - -.W80p { - width: 80%; -} - -.Txa-c { - text-align: center; -} - -.C-\\\$accent900 { - color: var(--ml-accent900); -} - -.Fns8u { - font-size: 2rem; -} - -.Lnh1\\\.1 { - line-height: 1.1; -} - -.P0\\\;1u { - padding: 0px 0.25rem; -} - -.C-\\\$accent850 { - color: var(--ml-accent850); -} - -.P0\\\;2u { - padding: 0px 0.5rem; -} - -.Mxw750 { - max-width: 750px; -} - -.Fns4\\\.4u { - font-size: 1.1rem; -} - -.Fld-r { - flex-direction: row; -} - -.Flw-w { - flex-wrap: wrap; -} - -.Gap3u { - gap: 0.75rem; -} - -.P0\\\;5u { - padding: 0px 1.25rem; -} - -@media (min-width: 768px) { - .md_W100p { - width: 100%; - } -} -@media (min-width: 768px) { - .md_Fns10u { - font-size: 2.5rem; - } -} - -.M0\\\;a\\\;5u { - margin: 0px auto 1.25rem; -} -`); - -const config = signal(` -@use 'mlut' with ( - $jit:( - "output":"style.css", - "content":"index.html" - ) -); - -@media (prefers-color-scheme: dark){ - html{ - --ml-accent900:#fff; - --ml-accent850:rgb(209,213,219,1); - --ml-core750:#121828; - --ml-core650:#251942; - --ml-core600:#321933; - } -} - -@media (prefers-color-scheme: light){ - html{ - --ml-accent900:rgb(17,24,39); - --ml-accent850:rgb(41,42,51,1); - --ml-core750:rgb(236,240,246,0.5); - --ml-core650:rgba(218,178,255,0.1); - --ml-core600:rgba(142,197,255,0.4); - } -} -`); - -const count = signal(0) - -export {layout, styles, config, count} \ No newline at end of file diff --git a/src/assets/style/style.scss b/src/assets/style/style.scss index 421aa6a..27c9149 100644 --- a/src/assets/style/style.scss +++ b/src/assets/style/style.scss @@ -8,7 +8,6 @@ html { scrollbar-color: var(--ml-accent700) var(--ml-core800); } - @media (prefers-color-scheme: light){ html { --ml-core800: #f0f0f1; @@ -25,3 +24,46 @@ html { --ml-accent700: #7f838f; } } + +.loader:before { + content: ''; + position: absolute; + z-index: 10; + bottom: 0; + left: 0; + width: 100%; + height: 100% ; + background-color: var(--ml-core800); +} + +.loader:after { + content: ''; + margin: auto; + position: absolute; + z-index: 11; + top: 0; + left: 0; + bottom: 0; + right: 0; + border: 0.5rem solid var(--ml-brand); + border-left-width:0; + border-bottom-width:0; + border-top-width:0.25rem; + border-radius:50%; + width: 150px; + aspect-ratio: 1; + animation-name: spin; + animation-duration: 1s; + animation-iteration-count: infinite; + animation-timing-function: linear; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/src/components/code-editor.js b/src/components/code-editor.js index 838516e..4ef68ef 100644 --- a/src/components/code-editor.js +++ b/src/components/code-editor.js @@ -1,70 +1,64 @@ -// Lit imports + import { LitElement, html } from 'lit'; -import { watch, SignalWatcher } from '@lit-labs/signals'; +import { ContextConsumer } from '@lit/context'; -// General CodeMirror imports import { basicSetup } from 'codemirror'; -import { EditorView, keymap, drawSelection} from '@codemirror/view'; +import { EditorView, keymap, drawSelection } from '@codemirror/view'; import { indentWithTab } from '@codemirror/commands'; import { oneDark } from '@codemirror/theme-one-dark'; import { EditorState, Prec } from '@codemirror/state'; - -// Language CodeMirror imports import { html as langHTML } from '@codemirror/lang-html'; import { css as langCSS } from '@codemirror/lang-css'; import { sass as langSASS } from '@codemirror/lang-sass'; -// Data imports - -import { layout, styles, config } from '../assets/scripts/lit-context'; +import { initialLayout, initialConfig } from '../assets/data/initial-code.js'; +import { eventBusContext } from './main-comp'; const customTheme = Prec.highest(EditorView.theme({ - ".cm-editor": { - backgroundColor: "transparent !important" - }, - ".cm-editor>*": { - backgroundColor: "transparent !important" - }, - ".cm-content": { - backgroundColor: "transparent !important" + '.cm-selectionMatch': { + backgroundColor: 'rgba(255, 200, 0, 0.2)' }, - ".cm-selectionMatch": { - backgroundColor: "rgba(255, 200, 0, 0.2)" - }, - ".cm-line::selection": { - backgroundColor: "red !important" + '.cm-line::selection': { + backgroundColor: 'red !important' } -})) +})); export class CodeEditor extends LitElement { + _eventBus = new ContextConsumer(this, { context: eventBusContext }); static properties = { lang: { type: String }, - content: { type: Object }, timeoutID: { type: Number, state: false }, - view: { type: Object } + view: { type: Object }, + inProgress: { type: Boolean } }; createRenderRoot() { return this; } - constructor() { - super(); - this.content = ''; - } - firstUpdated() { this.view = new EditorView(this.setEditorOptions(this.lang)); + + if (this.lang === 'css') { + this._eventBus.value.on('update-css', this.updateCss); + } + + this._eventBus.value.on('request-copy', this.handleCopy); } - setEditorOptions(lang) { + disconnectedCallback() { + if (this.lang === 'css') { + this._eventBus.value.off('update-css', this.updateCss); + } - basicSetup.highlightSelectionMatches = false + this._eventBus.value.off('request-copy', this.handleCopy); + } + setEditorOptions(lang) { const editorSettings = { - parent: this.querySelector('#wrapper'), + parent: this.querySelector(`#${this.lang}-editor`), extensions: [ basicSetup, EditorView.lineWrapping, @@ -85,7 +79,7 @@ export class CodeEditor extends LitElement { return { ...editorSettings, - doc: layout.get().trim(), + doc: initialLayout.trim(), }; case 'css': editorSettings.extensions.push( @@ -95,20 +89,18 @@ export class CodeEditor extends LitElement { return { ...editorSettings, - doc: styles.get().trim() + doc: '' }; case 'sass': editorSettings.extensions.push(langSASS()); return { ...editorSettings, - doc: config.get().trim(), + doc: initialConfig.trim(), }; } } - ы - setDocChangeHandler() { return EditorView.updateListener.of((update) => { if (update.docChanged) { @@ -117,14 +109,23 @@ export class CodeEditor extends LitElement { if (this.lang !== 'css') { this.timeoutID = setTimeout(() => { - this.dispatchEvent(new CustomEvent('editor-update', { - detail: { - target: this, - updatedData: update.state.doc.toString(), - lang: this.lang - }, - bubbles: true - })); + if (this.lang === 'html') { + this._eventBus.value.emit('update-html', { + detail: { + target: this, + updatedData: update.state.doc.toString(), + lang: this.lang + }, + }); + } else { + this._eventBus.value.emit('update-sass', { + detail: { + target: this, + updatedData: update.state.doc.toString(), + lang: this.lang + }, + }); + } }, 1000); } @@ -132,21 +133,28 @@ export class CodeEditor extends LitElement { }); } - updateFromParent() { + updateCss = (event) => { const transition = this.view.state.update({ changes: { from: 0, to: this.view.state.doc.length, - insert: styles.get() + insert: event.detail.updatedData } }); this.view.dispatch(transition); - } + }; + + handleCopy = async (event) => { + if (this.lang === event.detail.lang) { + await navigator.clipboard.writeText(this.view.state.doc.toString()); + } + }; render() { return html` -
+
+
`; } } diff --git a/src/components/code-preview.js b/src/components/code-preview.js index e85b515..9127434 100644 --- a/src/components/code-preview.js +++ b/src/components/code-preview.js @@ -1,41 +1,116 @@ import { LitElement, html } from 'lit'; -import { initialCode } from '../assets/data/initialCode'; -import { watch, SignalWatcher } from '@lit-labs/signals'; -import { layout, styles, config, count } from '../assets/scripts/lit-context'; +import { initialLayout, initialConfig } from '../assets/data/initial-code.js'; -export class CodePreview extends SignalWatcher(LitElement) { +import { ContextConsumer } from '@lit/context'; +import { eventBusContext } from './main-comp.js'; + +export class CodePreview extends LitElement { + _eventBus = new ContextConsumer(this, { context: eventBusContext }); createRenderRoot() { return this; } static properties = { - documentContent: { type: String } + htmlLayout: { type: String }, + cssStyles: { type: String }, + config: { type: String }, + isValid: { type: Boolean }, + inProgress: { type: Boolean }, + mlutEngine: { type: Object }, + timeoutID: { type: Number } + }; + + async firstUpdated() { + this._eventBus.value.on('update-html', this.handleUpdate); + this._eventBus.value.on('update-sass', this.handleUpdate); + const { jitEngine } = await import('https://unpkg.com/@mlut/core@latest/dist/index.js'); + await jitEngine.init(['config.scss', initialConfig]); + jitEngine.putContent('index.html', initialLayout); + this.mlutEngine = jitEngine; + await this.debounceCssUpdate(initialLayout, initialConfig); + } + + disconnectedCallback() { + this._eventBus.value.off('update-html', this.debounceHandleUpdate); + this._eventBus.value.off('update-sass', this.debounceHandleUpdate); + } + + handleUpdate = async (event) => { + if (event.detail.lang === 'html') { + this.htmlLayout = event.detail.updatedData; + } else if (event.detail.lang === 'sass') { + this.config = event.detail.updatedData; + } + + await this.debounceCssUpdate(this.htmlLayout, this.config); }; + async updateCSS(layout, config) { + await this.mlutEngine.updateSassConfig(config); + this.mlutEngine.putContent('layout.html', layout); + this.cssStyles = await this.mlutEngine.generateCss(); + console.log(this.cssStyles); + + if (this.cssStyles) { + this.isValid = true; + this._eventBus.value.emit('update-css', { + detail: { + target: this, + updatedData: this.cssStyles, + lang: 'css' + } + }); + } else { + this.isValid = false; + } + + this.inProgress = false; + } + + async debounceCssUpdate(layout, config) { + clearTimeout(this.timeoutID); + this.timeoutID = setTimeout(await this.updateCSS(layout, config), 500); + } + constructor() { super(); this.documentContent = ''; + this.htmlLayout = initialLayout; + this.config = initialConfig; + this.isValid = true; + this.inProgress = true; } render() { + if (this.inProgress) { + return html` + + `; + } else if (!this.isValid) { + return html` + + `; + } + return html` - - `; + + `; + } } diff --git a/src/components/content-loader.js b/src/components/content-loader.js new file mode 100644 index 0000000..85a09af --- /dev/null +++ b/src/components/content-loader.js @@ -0,0 +1,16 @@ +import { LitElement, html } from 'lit'; + +export class ContentLoader extends LitElement { + createRenderRoot() { + return this; + } + + render() { + return html` +
+
+ `; + } +} + +customElements.define('content-loader', ContentLoader); \ No newline at end of file diff --git a/src/components/copy-button.js b/src/components/copy-button.js new file mode 100644 index 0000000..cdeeee7 --- /dev/null +++ b/src/components/copy-button.js @@ -0,0 +1,55 @@ +import { LitElement, html } from 'lit'; +import { ContextConsumer } from '@lit/context'; +import { eventBusContext } from './main-comp'; + +export class CopyButton extends LitElement { + _eventBus = new ContextConsumer(this, { context: eventBusContext }); + + static properties = { + lang: { type: String }, + isClicked: { type: Boolean } + }; + + createRenderRoot() { + return this; + } + + constructor() { + super(); + this.isClicked = false; + } + + clickHandler() { + try { + this.isClicked = true; + this._eventBus.value.emit('request-copy', { + detail: { + lang: this.lang, + } + }); + } catch (e) { + console.log(e.message); + } + + setTimeout(() => { + this.isClicked = false; + }, 1000); + } + + render() { + return html` + + `; + } +} + +customElements.define('copy-button', CopyButton); \ No newline at end of file diff --git a/src/components/error-fallback.js b/src/components/error-fallback.js new file mode 100644 index 0000000..8db7188 --- /dev/null +++ b/src/components/error-fallback.js @@ -0,0 +1,23 @@ +import { LitElement, html } from 'lit'; + +export class ErrorFallback extends LitElement { + createRenderRoot() { + return this; + } + + render() { + return html` +
+

Ooops...

+

+ Something went wrong in your Sass-config! +

+

+ Check out the console +

+
+ `; + } +} + +customElements.define('error-fallback', ErrorFallback); \ No newline at end of file diff --git a/src/components/main-comp.js b/src/components/main-comp.js index 0ce027c..0fa98e4 100644 --- a/src/components/main-comp.js +++ b/src/components/main-comp.js @@ -1,52 +1,28 @@ import { LitElement, html } from 'lit'; -import { layout, styles, config } from '../assets/scripts/lit-context'; +import { createContext, ContextProvider } from '@lit/context'; -const cssEditor = document.querySelector('code-editor[lang="css"]'); +import { EventBus } from '../assets/scripts/event-bus.js'; + +export const eventBusContext = createContext('eventBus'); +const eventBus = new EventBus(); export class MainComp extends LitElement { - createRenderRoot() { - return this.querySelector('main'); - } + _provider = new ContextProvider(this, { + context: eventBusContext, + initialValue: eventBus + }); constructor() { super(); - this.addEventListener('editor-update', (event) => this.handleChildUpdate(event)); + this.inProgress = true; } - handleChildUpdate(event) { - - if (event.detail.lang === 'html') { - layout.set(event.detail.updatedData); - } else if (event.detail.lang === 'sass') { - config.set(event.detail.updatedData); - } - console.log(event.detail.lang) - - try { - this.buildStyles(layout.get(), config.get()); - cssEditor.updateFromParent(); - } catch (err) { - console.log(err.message); - layout.set(` -

- ${err.message} -

`) - }1 - } - - buildStyles(layout, config) { - // throw new Error('Something went wrong!'); - const array = layout.split('\n'); - styles.set(array[0]); + createRenderRoot() { + return this; } - render() { - return html` -
- -
- `; + return html``; } } diff --git a/src/components/style-tab.js b/src/components/style-tab.js index 19c6986..331ab04 100644 --- a/src/components/style-tab.js +++ b/src/components/style-tab.js @@ -1,6 +1,9 @@ import { LitElement, html } from 'lit'; +import { ContextConsumer } from '@lit/context'; +import { eventBusContext } from './main-comp'; export class StyleTab extends LitElement { + _eventBus = new ContextConsumer(this, { context: eventBusContext }); createRenderRoot() { return this; @@ -8,7 +11,7 @@ export class StyleTab extends LitElement { static properties = { checked: { type: String }, - radioId: { type: String }, + lang: { type: String }, name: { type: String }, text: { type: String } }; @@ -17,50 +20,16 @@ export class StyleTab extends LitElement { super(); } - firstUpdated() { - // если checked выставлен по атрибуту — синхронизируем с внутренним input - const input = this.renderRoot.querySelector('input'); - - if (input) { - input.checked = this.checked; - - if (this.checked === 'checked') { - this.displayEditor(); - } - } - } - - displayEditor() { - const editors = document.querySelectorAll('div[data-type="style"]'); - editors.forEach((el) => { - if (el.getAttribute('data-lang') === `${this.radioId.toLowerCase()}`) { - el.classList.add('D'); - el.classList.remove('D-n'); - } else { - el.classList.add('D-n'); - el.classList.remove('D'); - } - }); - } - - handleChange(e) { - this.checked = e.target.checked; - this.displayEditor(); - } - render() { return html` - -
-
- +
+
@@ -75,18 +75,12 @@ - + @@ -94,7 +88,6 @@ -