diff --git a/sdkjs-plugins/content/lizardtypst/3rd-Party.txt b/sdkjs-plugins/content/lizardtypst/3rd-Party.txt new file mode 100644 index 000000000..a770cfab1 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/3rd-Party.txt @@ -0,0 +1,8 @@ +This plugin uses the following third-party libraries, which are included in the plugin's vendor directory: + +- **@myriaddreamin/typst.ts**: https://github.com/Myriad-Dreamin/typst.ts + - License: MIT +- **@myriaddreamin/typst-ts-web-compiler**: https://github.com/Myriad-Dreamin/typst.ts + - License: MIT +- **@myriaddreamin/typst-ts-renderer**: https://github.com/Myriad-Dreamin/typst.ts + - License: MIT diff --git a/sdkjs-plugins/content/lizardtypst/CHANGELOG.md b/sdkjs-plugins/content/lizardtypst/CHANGELOG.md new file mode 100644 index 000000000..c8838a482 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +## 0.1.0 (2025-12-17) + +- Initial release +- Allows inserting Typst mathematical formulas as SVG images +- Real-time rendering preview +- History of Typst code changes +- Added store configuration and assets +- Added localization support +- Updated plugin structure to meet marketplace requirements \ No newline at end of file diff --git a/sdkjs-plugins/content/lizardtypst/README.md b/sdkjs-plugins/content/lizardtypst/README.md new file mode 100644 index 000000000..4e7699e30 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/README.md @@ -0,0 +1,39 @@ +# LizardTypst Plugin + +A simple plugin for ONLYOFFICE that allows you to insert Typst mathematical formulas as high-quality SVG images, powered by the `typst.ts` library. + +This plugin is compatible with [self-hosted](https://github.com/ONLYOFFICE/DocumentServer) and [desktop](https://github.com/ONLYOFFICE/DesktopEditors) versions of ONLYOFFICE editors. It can be added to ONLYOFFICE instances manually. + +## Motivation + +The LizardTypst plugin draws inspiration from the existing **Iguana LaTeX** plugin. Our goal is to provide a modern and accessible solution for Typst users by leveraging the benefits of Typst directly within ONLYOFFICE, without requiring complex local setups. + +## Features + +- **Real-time Rendering**: See a live preview of the rendered Typst formula as you type. This provides an immediate and interactive editing experience. +- **No Local Installation Required**: Unlike solutions that depend on server-side rendering or local LaTeX/Typst installations, LizardTypst utilizes `typst.ts` to compile Typst code directly in your browser. This means you don't need any additional software installed on your machine to use the plugin. +- **SVG-based Rendering**: Inserts formulas as scalable vector graphics, ensuring high quality at any zoom level. + +## Powered By + +This plugin leverages the power of [typst.ts](https://github.com/myriaddreamin/typst.ts), a powerful TypeScript library for compiling and rendering Typst code directly in the browser using WebAssembly. + +## Vendored Dependencies + +This plugin uses a vendored (self-hosted) version of `typst.ts` to ensure offline functionality. +- **`@myriaddreamin/typst.ts`**: `0.6.1-rc5` + +## How to use + +1. Go to the **Plugins** tab in the ONLYOFFICE editor. +2. Click on the **LizardTypst** icon to open the plugin window. +3. Enter your Typst code in the input area on the left. A preview will be generated on the right. +4. Once you are satisfied with the result, click the **Insert** button to place the image into your document. + +## How to install + +Detailed instructions for plugin installation can be found in the official [ONLYOFFICE API documentation](https://api.onlyoffice.com/docs/plugin-and-macros/tutorials/installing/onlyoffice-docs-on-premises/). + +## User feedback and support + +To ask questions and share feedback, please use the **Issues** section in the repository where this plugin is located. \ No newline at end of file diff --git a/sdkjs-plugins/content/lizardtypst/build.bat b/sdkjs-plugins/content/lizardtypst/build.bat new file mode 100644 index 000000000..8158c1f45 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/build.bat @@ -0,0 +1,9 @@ +@echo off +set PLUGIN_NAME=lizardtypst +echo Building %PLUGIN_NAME%.plugin... +if not exist deploy mkdir deploy +if exist deploy\%PLUGIN_NAME%.plugin del deploy\%PLUGIN_NAME%.plugin +powershell -Command "Compress-Archive -Path config.json,index.html,README.md,CHANGELOG.md,scripts,resources,translations -DestinationPath deploy\%PLUGIN_NAME%.zip -Force" +move /Y deploy\%PLUGIN_NAME%.zip deploy\%PLUGIN_NAME%.plugin >nul +echo Done! Created deploy\%PLUGIN_NAME%.plugin +dir deploy\%PLUGIN_NAME%.plugin | find "%PLUGIN_NAME%" diff --git a/sdkjs-plugins/content/lizardtypst/config.json b/sdkjs-plugins/content/lizardtypst/config.json new file mode 100644 index 000000000..1127cb26a --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/config.json @@ -0,0 +1,82 @@ +{ + "name": "LizardTypst", + "nameLocale": { + "cs-CS": "LizardTypst", + "de-DE": "LizardTypst", + "en-US": "LizardTypst", + "en-ES": "LizardTypst", + "fr-FR": "LizardTypst", + "it-IT": "LizardTypst", + "ja-JA": "LizardTypst", + "pt-BR": "LizardTypst", + "ru-RU": "LizardTypst", + "zh-ZH": "LizardTypst" + }, + "guid": "asc.{F8B5E3A1-9C7D-4E2F-A1B3-5D8E9F0A1C2D}", + "version": "0.1.0", + "minVersion": "8.2.0", + "variations": [ + { + "description": "Insert Typst mathematical formulas as SVG", + "descriptionLocale": { + "cs-CS": "Insert Typst mathematical formulas as SVG", + "de-DE": "Einfügen von mathematischen Typst-Formeln als SVG", + "en-US": "Insert Typst mathematical formulas as SVG", + "en-ES": "Insert Typst mathematical formulas as SVG", + "fr-FR": "Insérer des formules mathématiques Typst sous forme de SVG", + "it-IT": "Inserisci le formule matematiche di Typst come SVG", + "ja-JA": "Typstの数学をSVGとして挿入", + "pt-BR": "Inserir fórmulas matemáticas Typst como SVG", + "ru-RU": "Вставляйте математические формулы Typst в виде SVG", + "zh-ZH": "将 Typst数学公式作为SVG插入" + }, + "url": "index.html", + "icons": "resources/%theme-type%(dark|light)/%scale%(default).%extension%(png)", + "icons2": [ + { + "style": "light", + "100%": { "normal": "resources/light/icon.png" }, + "125%": { "normal": "resources/light/icon@1.25x.png" }, + "150%": { "normal": "resources/light/icon@1.5x.png" }, + "175%": { "normal": "resources/light/icon@1.75x.png" }, + "200%": { "normal": "resources/light/icon@2x.png" } + }, + { + "style": "dark", + "100%": { "normal": "resources/dark/icon.png" }, + "125%": { "normal": "resources/dark/icon@1.25x.png" }, + "150%": { "normal": "resources/dark/icon@1.5x.png" }, + "175%": { "normal": "resources/dark/icon@1.75x.png" }, + "200%": { "normal": "resources/dark/icon@2x.png" } + } + ], + "isViewer": false, + "EditorsSupport": ["slide"], + "isVisual": true, + "isModal": true, + "initDataType": "text", + "buttons": [ + { "text": "Insert", "primary": true }, + { "text": "Cancel", "primary": false } + ], + "size": [800, 600], + "store": { + "background": { + "light": "#F5F5F5", + "dark": "#444444" + }, + "screenshots": [ + "resources/store/screenshots/screenshot1.png", + "resources/store/screenshots/screenshot2.png", + "resources/store/screenshots/screenshot3.png", + "resources/store/screenshots/screenshot4.png" + ], + "icons": { + "light": "resources/store/icons", + "dark": "resources/store/icons" + }, + "categories": ["specAbilities", "work"] + } + } + ] +} diff --git a/sdkjs-plugins/content/lizardtypst/deploy/lizardtypst.plugin b/sdkjs-plugins/content/lizardtypst/deploy/lizardtypst.plugin new file mode 100644 index 000000000..86757f410 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/deploy/lizardtypst.plugin differ diff --git a/sdkjs-plugins/content/lizardtypst/index.html b/sdkjs-plugins/content/lizardtypst/index.html new file mode 100644 index 000000000..5c9f219a7 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/index.html @@ -0,0 +1,159 @@ + + + + + Typst Math + + + + + + + + +
+
+
+ + +
+
+ +
Type formula to preview...
+
+
+ + + + + + + diff --git a/sdkjs-plugins/content/lizardtypst/licences/typst.ts.licence b/sdkjs-plugins/content/lizardtypst/licences/typst.ts.licence new file mode 100644 index 000000000..647a942a6 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/licences/typst.ts.licence @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023-2025 Myriad-Dreamin + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdkjs-plugins/content/lizardtypst/resources/dark/icon.png b/sdkjs-plugins/content/lizardtypst/resources/dark/icon.png new file mode 100644 index 000000000..6f59d0a40 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/dark/icon.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.25x.png b/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.25x.png new file mode 100644 index 000000000..4b2a9b942 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.25x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.5x.png b/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.5x.png new file mode 100644 index 000000000..043e6ef91 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.5x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.75x.png b/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.75x.png new file mode 100644 index 000000000..47722875d Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/dark/icon@1.75x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/dark/icon@2x.png b/sdkjs-plugins/content/lizardtypst/resources/dark/icon@2x.png new file mode 100644 index 000000000..be2cf99f1 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/dark/icon@2x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/icon.svg b/sdkjs-plugins/content/lizardtypst/resources/icon.svg new file mode 100644 index 000000000..7c876389d --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/resources/icon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/sdkjs-plugins/content/lizardtypst/resources/icon_lizard.png b/sdkjs-plugins/content/lizardtypst/resources/icon_lizard.png new file mode 100644 index 000000000..f07b073d7 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/icon_lizard.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/icon_row.png b/sdkjs-plugins/content/lizardtypst/resources/icon_row.png new file mode 100644 index 000000000..bcf8b058f Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/icon_row.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/light/icon.png b/sdkjs-plugins/content/lizardtypst/resources/light/icon.png new file mode 100644 index 000000000..6f59d0a40 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/light/icon.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.25x.png b/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.25x.png new file mode 100644 index 000000000..4b2a9b942 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.25x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.5x.png b/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.5x.png new file mode 100644 index 000000000..043e6ef91 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.5x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.75x.png b/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.75x.png new file mode 100644 index 000000000..47722875d Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/light/icon@1.75x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/light/icon@2x.png b/sdkjs-plugins/content/lizardtypst/resources/light/icon@2x.png new file mode 100644 index 000000000..be2cf99f1 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/light/icon@2x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon.png b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon.png new file mode 100644 index 000000000..96aebf761 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon.svg b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon.svg new file mode 100644 index 000000000..9e8fbb90f --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.25x.png b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.25x.png new file mode 100644 index 000000000..8f88f61eb Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.25x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.5x.png b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.5x.png new file mode 100644 index 000000000..95fb2dad5 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.5x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.75x.png b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.75x.png new file mode 100644 index 000000000..4dd34822a Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@1.75x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@2x.png b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@2x.png new file mode 100644 index 000000000..113dffb4a Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/icons/icon@2x.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot1.png b/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot1.png new file mode 100644 index 000000000..b64bd2206 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot1.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot2.png b/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot2.png new file mode 100644 index 000000000..24e14996e Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot2.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot3.png b/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot3.png new file mode 100644 index 000000000..45e10c020 Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot3.png differ diff --git a/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot4.png b/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot4.png new file mode 100644 index 000000000..899666d3b Binary files /dev/null and b/sdkjs-plugins/content/lizardtypst/resources/store/screenshots/screenshot4.png differ diff --git a/sdkjs-plugins/content/lizardtypst/scripts/history.js b/sdkjs-plugins/content/lizardtypst/scripts/history.js new file mode 100644 index 000000000..895e85ed1 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/scripts/history.js @@ -0,0 +1,41 @@ +(function (window) { + const HISTORY_KEY = "typst.history"; + const MAX_HISTORY_SIZE = 30; + + /** + * Loads the history from localStorage. + * @returns {string[]} An array of saved Typst code snippets. + */ + function loadHistory() { + const historyJson = localStorage.getItem(HISTORY_KEY); + return historyJson ? JSON.parse(historyJson) : []; + } + + /** + * Saves a new code snippet to the history. + * @param {string} code The Typst code to save. + */ + function saveToHistory(code) { + if (!code || !code.trim()) { + return; + } + let history = loadHistory(); + // Remove existing entry to move it to the top + const existingIndex = history.indexOf(code); + if (existingIndex > -1) { + history.splice(existingIndex, 1); + } + // Add to the top + history.unshift(code); + // Trim history to max size + if (history.length > MAX_HISTORY_SIZE) { + history = history.slice(0, MAX_HISTORY_SIZE); + } + localStorage.setItem(HISTORY_KEY, JSON.stringify(history)); + } + + window.TypstHistory = { + load: loadHistory, + save: saveToHistory, + }; +})(window); diff --git a/sdkjs-plugins/content/lizardtypst/scripts/renderer.js b/sdkjs-plugins/content/lizardtypst/scripts/renderer.js new file mode 100644 index 000000000..57c2959b6 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/scripts/renderer.js @@ -0,0 +1,131 @@ +(function (window) { + let currentSvgData = { + svg: null, + width: 0, + height: 0, + }; + let lastRequestId = 0; + + /** + * Formats and displays rendering errors. + * @param {HTMLElement} errorDiv The element to display the error in. + * @param {any} error The error object from typst. + */ + function displayRenderError(errorDiv, error) { + errorDiv.innerHTML = ''; // Clear previous errors + errorDiv.style.visibility = "visible"; // Always show the error div when there's an error + + const errorString = String(error.message || error); // Get the string representation of the error + + // Regex to extract message and hints + const messageMatch = errorString.match(/message:\s*"(.*?)(? hint.replace(/^"|"$/g, '').replace(/\\"/g, '"').trim()); + } + + if (message || hints.length > 0) { + // Display MESSAGE + if (message) { + const msgP = document.createElement('p'); + const msgB = document.createElement('b'); + msgB.textContent = 'MESSAGE: '; + msgP.appendChild(msgB); + msgP.appendChild(document.createTextNode(message)); + errorDiv.appendChild(msgP); + } + + // Display HINTS + if (hints.length > 0) { + hints.forEach(hint => { + const hintP = document.createElement('p'); + hintP.style.paddingLeft = '1em'; // Indent hints + const hintB = document.createElement('b'); + hintB.textContent = 'HINT: '; + hintP.appendChild(hintB); + hintP.appendChild(document.createTextNode(hint)); + errorDiv.appendChild(hintP); + }); + } + } else { + // Fallback if no specific message/hints are found (e.g., different error format) + const fallbackP = document.createElement('p'); + fallbackP.textContent = `Error rendering preview: ${errorString}`; + errorDiv.appendChild(fallbackP); + } + } + + /** + * Updates the preview with the new SVG and calculates its dimensions. + * @param {string} svg The SVG string from typst. + * @param {HTMLElement} preview The preview element. + */ + function updateSvgInPreview(svg, preview) { + currentSvgData.svg = svg; + preview.innerHTML = svg; + + const svgElem = preview.firstElementChild; + if (svgElem) { + const wAttr = svgElem.getAttribute("width"); + const hAttr = svgElem.getAttribute("height"); + let width = parseFloat(wAttr); + let height = parseFloat(hAttr); + const pt2px = 96 / 72; + + if (wAttr && wAttr.endsWith("pt")) width *= pt2px; + if (hAttr && hAttr.endsWith("pt")) height *= pt2px; + + currentSvgData.width = width; + currentSvgData.height = height; + } + } + + /** + * Renders the typst code and updates the preview. + * @param {HTMLTextAreaElement} input The input textarea. + * @param {HTMLElement} preview The preview element. + * @param {HTMLElement} errorDiv The error display element. + */ + async function updatePreview(input, preview, errorDiv) { + const code = input.value.trim(); + if (!code) { + preview.innerHTML = "Type formula to preview..."; + currentSvgData.svg = null; + errorDiv.style.visibility = "hidden"; + return; + } + + lastRequestId++; + const reqId = lastRequestId; + preview.innerHTML = "Loading preview..."; + errorDiv.style.visibility = "hidden"; + + try { + const typst = window.$typst || window.typst || null; + if (!typst || typeof typst.svg !== "function") { + throw new Error("Typst runtime not loaded yet."); + } + + const svg = await typst.svg({ mainContent: code }); + if (reqId !== lastRequestId) return; + + updateSvgInPreview(svg, preview); + + } catch (error) { + if (reqId !== lastRequestId) return; + currentSvgData.svg = null; + preview.innerHTML = ""; + displayRenderError(errorDiv, error); + } + } + + window.TypstRenderer = { + updatePreview: updatePreview, + getCurrentSvgData: () => currentSvgData, + }; +})(window); diff --git a/sdkjs-plugins/content/lizardtypst/scripts/script.js b/sdkjs-plugins/content/lizardtypst/scripts/script.js new file mode 100644 index 000000000..0cc006a8c --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/scripts/script.js @@ -0,0 +1,65 @@ +(function (window) { + const InitTypstCode = `#set page( + width: auto, + height: auto, + margin: .2cm, + fill: none, +) +$ + sum_(k=1)^n k = (n(n+1))/2 +$ +`; + + window.Asc.plugin.init = function (text) { + const input = document.getElementById("input"); + const preview = document.getElementById("preview"); + const errorDiv = document.getElementById("error"); + const historyContainer = document.getElementById("history-container"); + + const updatePreviewAndResize = () => { + window.TypstRenderer.updatePreview(input, preview, errorDiv); + input.style.height = "1px"; + input.style.height = input.scrollHeight + "px"; + }; + + // Initialize Typst compiler and renderer + window.$typst.setCompilerInitOptions({ + getModule: () => "scripts/vendor/typst_ts_web_compiler_bg.wasm", + }); + window.$typst.setRendererInitOptions({ + getModule: () => "scripts/vendor/typst_ts_renderer_bg.wasm", + }); + + if (text) { + input.value = text; + } else if (input.value === "") { + input.value = InitTypstCode; + } + + input.oninput = updatePreviewAndResize; + + // Initialize the UI, including the history dropdown + window.TypstUI.initialize({ + container: historyContainer, + input: input, + onSelect: updatePreviewAndResize, + }); + + updatePreviewAndResize(); + }; + + window.Asc.plugin.button = function (id) { + if (id === 0) { + const input = document.getElementById("input"); + const { svg, width, height } = window.TypstRenderer.getCurrentSvgData(); + + // Save to history before inserting + window.TypstHistory.save(input.value); + + window.SlideInserter.insert(svg, width, height); + window.Asc.plugin.executeCommand("close", ""); + } else { + window.Asc.plugin.executeCommand("close", ""); + } + }; +})(window); diff --git a/sdkjs-plugins/content/lizardtypst/scripts/slide-inserter.js b/sdkjs-plugins/content/lizardtypst/scripts/slide-inserter.js new file mode 100755 index 000000000..b3d9d3ba1 --- /dev/null +++ b/sdkjs-plugins/content/lizardtypst/scripts/slide-inserter.js @@ -0,0 +1,61 @@ +/** + * Removes