From 8365385b16e7870c8351ee3246a359616b6febed Mon Sep 17 00:00:00 2001 From: Roman Nurik Date: Thu, 31 Oct 2024 10:20:03 -0400 Subject: [PATCH] Rewrite in Vite, switch to Shiki --- .eslintrc.cjs | 20 + .gitignore | 28 +- gulpfile.js | 140 - index.html | 144 +- index.js | 621 -- index.scss | 369 - package-lock.json | 9622 +++++------------ package.json | 40 +- prism.js | 280 - src/App.module.scss | 28 + src/App.tsx | 54 + src/AppState.tsx | 43 + src/Config.tsx | 156 + src/cleanup-code.ts | 54 + src/components/CustomThemeEditor.module.scss | 66 + src/components/CustomThemeEditor.tsx | 94 + src/components/Editor.module.scss | 16 + src/components/Editor.tsx | 148 + src/components/MessageList.module.scss | 21 + src/components/MessageList.tsx | 25 + src/components/Output.module.scss | 48 + src/components/Output.tsx | 283 + src/components/WarningMessages.tsx | 44 + src/components/toolbars/CustomToolbar.tsx | 14 + src/components/toolbars/InputToolbar.tsx | 58 + src/components/toolbars/OutputToolbar.tsx | 154 + src/components/toolbars/Toolbar.module.scss | 137 + src/index.scss | 36 + src/legacy-to-shiki-theme.ts | 281 + src/lib.scss | 23 + src/main.tsx | 16 + .../material-colors.scss | 3 +- material-colors.js => src/material-colors.ts | 11 +- src/shiki-themes/monospace-dark.json | 627 ++ src/shiki-themes/monospace-light.json | 627 ++ themes.js => src/themes.ts | 226 +- src/util.ts | 2 + src/vite-env.d.ts | 1 + sw-dev.js | 8 - test_code_snippets/dart.dart | 16 + test_code_snippets/js.js | 3 + tsconfig.json | 25 + tsconfig.node.json | 10 + vite.config.ts | 7 + 44 files changed, 6189 insertions(+), 8440 deletions(-) create mode 100644 .eslintrc.cjs delete mode 100644 gulpfile.js delete mode 100644 index.js delete mode 100644 index.scss delete mode 100644 prism.js create mode 100644 src/App.module.scss create mode 100644 src/App.tsx create mode 100644 src/AppState.tsx create mode 100644 src/Config.tsx create mode 100644 src/cleanup-code.ts create mode 100644 src/components/CustomThemeEditor.module.scss create mode 100644 src/components/CustomThemeEditor.tsx create mode 100644 src/components/Editor.module.scss create mode 100644 src/components/Editor.tsx create mode 100644 src/components/MessageList.module.scss create mode 100644 src/components/MessageList.tsx create mode 100644 src/components/Output.module.scss create mode 100644 src/components/Output.tsx create mode 100644 src/components/WarningMessages.tsx create mode 100644 src/components/toolbars/CustomToolbar.tsx create mode 100644 src/components/toolbars/InputToolbar.tsx create mode 100644 src/components/toolbars/OutputToolbar.tsx create mode 100644 src/components/toolbars/Toolbar.module.scss create mode 100644 src/index.scss create mode 100644 src/legacy-to-shiki-theme.ts create mode 100644 src/lib.scss create mode 100644 src/main.tsx rename _material-colors.scss => src/material-colors.scss (98%) rename material-colors.js => src/material-colors.ts (97%) create mode 100644 src/shiki-themes/monospace-dark.json create mode 100644 src/shiki-themes/monospace-light.json rename themes.js => src/themes.ts (50%) create mode 100644 src/util.ts create mode 100644 src/vite-env.d.ts delete mode 100644 sw-dev.js create mode 100644 test_code_snippets/dart.dart create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..6e4c27d --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,20 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'prefer-const': 'off', + '@typescript-eslint/no-unused-vars': 'warn', + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, +} diff --git a/.gitignore b/.gitignore index 5f6a929..35c304f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,26 @@ _sandbox -.sass-cache -.tmp + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + node_modules -bower_components dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea .DS_Store -.publish -*.sublime-workspace -*~ +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 4ccbcf1..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * 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. - */ - -const browserSync = require('browser-sync'); -const del = require('del'); - -const gulp = require('gulp'); -const $ = require('gulp-load-plugins')(); -const workbox = require('workbox-build'); -const { sassPlugin } = require('esbuild-sass-plugin'); - -const esbuild = require('esbuild'); - -let DEV_MODE = false; - - -gulp.task('service-worker', () => { - if (DEV_MODE) { - return gulp.src('sw-dev.js') - .pipe($.rename('sw.js')) - .pipe(gulp.dest('dist')); - } - - return workbox.generateSW({ - globDirectory: 'dist', - globPatterns: [ - '**/*.{html,js,css}' - ], - globIgnores: ['**/sw-dev.js'], - swDest: 'dist/sw.js', - clientsClaim: true, - skipWaiting: true - }).then(({ warnings }) => { - // In case there are any warnings from workbox-build, log them. - for (const warning of warnings) { - console.warn(warning); - } - console.info('Service worker generation completed.'); - }).catch((error) => { - console.warn('Service worker generation failed:', error); - }); -}); - - -function esBuild(extraOptions) { - return esbuild.context({ - entryPoints: ['index.js'], - bundle: true, - minify: !DEV_MODE, - loader: { - ".ttf": "file", - }, - ...extraOptions, - plugins: [ - ...(extraOptions?.plugins || []), - sassPlugin(), - ], - outfile: 'dist/index.js', - }); -} - -gulp.task('esbuild', async () => { - let ctx = await esBuild(); - ctx.rebuild(); - ctx.dispose(); -}); - - -gulp.task('copy', () => { - return gulp.src([ - 'index.html', - 'favicon.ico', - 'manifest.json', - - // libs - 'prism.js', - // 'node_modules/ace-builds/src-min-noconflict/ace.js', - // 'node_modules/ace-builds/src-min-noconflict/mode-text.js', - // 'node_modules/ace-builds/src-min-noconflict/theme-chrome.js', - // 'node_modules/webfontloader/webfontloader.js', - - // icons - 'images/**/*.png' - ]) - .pipe(gulp.dest('dist')); -}); - - -gulp.task('clean', cb => { - del.sync(['dist']); - $.cache.clearAll(); - cb(); -}); - - -gulp.task('build', gulp.series('clean', 'esbuild', 'copy', 'service-worker')); - - -gulp.task('__serve__', gulp.series('build', () => { - browserSync({ - notify: false, - server: { - baseDir: ['dist'] - } - }); - - let reload = cb => { browserSync.reload(); cb && cb(); }; - - esBuild({ - plugins: [{ - name: 'on-build-end', - setup(build) { - build.onEnd((result) => { - if (!result.errors.length) reload(); - }); - }, - }] - }).then(ctx => ctx.watch()); - - gulp.watch(['*.{html,js}'], gulp.series('copy', reload)); -})); - - -gulp.task('serve', gulp.series(cb => { DEV_MODE = true; cb(); }, '__serve__')); - - -gulp.task('default', gulp.series('clean', 'build')); diff --git a/index.html b/index.html index 3c86084..ede4a3e 100644 --- a/index.html +++ b/index.html @@ -1,134 +1,14 @@ - - - SlidesCodeHighlighter - - - - - - - - -
-
Paste code below
-
- - - -
-
-
-
-
-
Copy the formatted code below
-
- - - - - - - -
-
-
-
- For best results, copy from Safari with Keynote decks and from Chrome - with Google Slides decks. -
-
-
-
-
-
Custom theme
-
- - -
-
-
- - - - - + + + + + + + SlidesCodeHighlighter + + +
+ + diff --git a/index.js b/index.js deleted file mode 100644 index 270c379..0000000 --- a/index.js +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * 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. - */ - -import $ from 'jquery'; -import * as monaco from 'monaco-editor'; // TODO: figure out how to minify the bundle -import WebFont from 'webfontloader'; -import './index.scss'; -import { DEFAULT_THEMES, setTheme, THEME_PROPERTIES } from './themes.js'; - -const WARN_LINES = 15; -const WARN_LINE_LENGTH = 80; - -const $editor = $('#editor'); -const $output = $('#output'); - -let config = { - code: localStorage.highlighterCode || '', - theme: localStorage.highlighterTheme || 'light', - lang: localStorage.highlighterLang || '', - font: localStorage.highlighterFont || 'Roboto Mono', - tabSize: Number(localStorage.highlighterTabSize || '4'), - typeSize: Number(localStorage.highlighterTypeSize || '40'), - selectionTreatment: localStorage.highlighterSelectionTreatment || 'focus', - customTheme: JSON.parse(localStorage.customTheme || JSON.stringify(DEFAULT_THEMES['light'])), -}; - -if (!!window.location.search) { - loadConfigFromUrl(); -} - -if (config.lang == '--') { - config.lang = ''; -} - -let editor; - -setupToolbar(); -setupEditor(); -setupOutputArea(); -updateOutputArea(); -setupCustomThemeEditor(); -loadFont(); -installServiceWorker(); - - -function setupEditor() { - let updateCode_ = code => { - localStorage.highlighterCode = config.code = code; - updateOutputArea(); - }; - - if (navigator.userAgent.match(/iP(hone|od|ad)|Android/)) { - // Ace editor is pretty busted on mobile, just use a