├── .babelrc
├── .eslintrc
├── .github
└── workflows
│ └── static.yml
├── .gitignore
├── LICENSE
├── README.md
├── deploy.ps1
├── eslint.config.mjs
├── jsconfig.json
├── languages
├── lang.yml
└── samples
│ ├── bash.txt
│ ├── batch.txt
│ ├── c.txt
│ ├── cmake.txt
│ ├── cpp.txt
│ ├── csharp.txt
│ ├── css.txt
│ ├── diff.txt
│ ├── docker.txt
│ ├── glsl.txt
│ ├── go.txt
│ ├── html.txt
│ ├── java.txt
│ ├── javascript.txt
│ ├── json.txt
│ ├── kotlin.txt
│ ├── latex.txt
│ ├── llvm.txt
│ ├── lua.txt
│ ├── makefile.txt
│ ├── markdown.txt
│ ├── matlab.txt
│ ├── nasm.txt
│ ├── perl.txt
│ ├── php.txt
│ ├── powershell.txt
│ ├── python.txt
│ ├── r.txt
│ ├── ruby.txt
│ ├── rust.txt
│ ├── scala.txt
│ ├── sql.txt
│ ├── swift.txt
│ ├── toml.txt
│ ├── typescript.txt
│ ├── verilog.txt
│ ├── xml.txt
│ └── yaml.txt
├── package-lock.json
├── package.json
├── postcss.config.js
├── posthtml.json
├── scripts
├── minify_json.py
├── post_build.py
├── pre_deploy.py
└── update_samples.py
├── src
├── css
│ ├── dark.css
│ ├── doc.css
│ ├── effect.css
│ ├── fonts.css
│ ├── index.css
│ ├── main.css
│ └── vendor
│ │ ├── barber-shop.css
│ │ └── prism.css
├── favicon.png
├── js
│ ├── .gitignore
│ ├── code.js
│ ├── events
│ │ ├── actions.js
│ │ ├── help.js
│ │ ├── listeners.js
│ │ └── options.js
│ ├── main.js
│ ├── paste.js
│ ├── state.js
│ ├── utils.js
│ ├── vendor
│ │ ├── alertify-extension.js
│ │ ├── cookie-extension.js
│ │ ├── jquery-extensions.js
│ │ └── prism-extension.js
│ └── version.js
├── res
│ ├── fonts
│ │ ├── Consolas.eot
│ │ ├── Consolas.svg
│ │ ├── Consolas.woff
│ │ ├── Consolas.woff2
│ │ ├── LucidaHandwriting-Italic.eot
│ │ ├── LucidaHandwriting-Italic.svg
│ │ ├── LucidaHandwriting-Italic.woff
│ │ └── LucidaHandwriting-Italic.woff2
│ └── logo.png
├── version.json
└── views
│ ├── components
│ ├── .gitignore
│ ├── head.html
│ └── meta.html
│ ├── index.html
│ └── parts
│ ├── banner.html
│ ├── docs.html
│ ├── footer.html
│ ├── header.html
│ ├── panel.html
│ └── toolbar.html
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | [
4 | "prismjs",
5 | {
6 | "languages": [
7 | // Programming Languages
8 | "c",
9 | "cpp",
10 | "csharp",
11 | "go",
12 | "java",
13 | "kotlin",
14 | "perl",
15 | "python",
16 | "r",
17 | "ruby",
18 | "rust",
19 | "scala",
20 | "swift",
21 | // Web Development
22 | "css",
23 | "html",
24 | "javascript",
25 | "php",
26 | "typescript",
27 | // Scripting Language
28 | "bash",
29 | "batch",
30 | "lua",
31 | "powershell",
32 | // Markup Language
33 | "json",
34 | "latex",
35 | "markdown",
36 | "toml",
37 | "xml",
38 | "yaml",
39 | // Configuration Language
40 | "cmake",
41 | "docker",
42 | "makefile",
43 | // Database
44 | "sql",
45 | // Assembly Language
46 | "llvm",
47 | "nasm",
48 | // Others
49 | "diff",
50 | "glsl",
51 | "matlab",
52 | "verilog"
53 | ],
54 | "plugins": [
55 | "line-numbers",
56 | "show-language",
57 | "normalize-whitespace",
58 | "toolbar"
59 | ]
60 | }
61 | ],
62 | [
63 | "module-resolver",
64 | {
65 | "root": [
66 | "."
67 | ],
68 | "alias": {
69 | "~": "./src/js"
70 | }
71 | }
72 | ]
73 | ]
74 | }
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": "eslint:recommended",
7 | "parserOptions": {
8 | "ecmaVersion": 6,
9 | "sourceType": "module"
10 | }
11 | }
--------------------------------------------------------------------------------
/.github/workflows/static.yml:
--------------------------------------------------------------------------------
1 | name: Deploy CodePaste
2 |
3 | on:
4 | push:
5 | branches: ["main"]
6 |
7 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
8 | permissions:
9 | contents: read
10 | pages: write
11 | id-token: write
12 |
13 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
14 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
15 | concurrency:
16 | group: "pages"
17 | cancel-in-progress: false
18 |
19 | jobs:
20 | # Build job to minify the project
21 | build:
22 | runs-on: windows-latest
23 | steps:
24 | - name: Checkout
25 | uses: actions/checkout@v4
26 |
27 | - name: Install NodeJS
28 | uses: actions/setup-node@v4
29 | with:
30 | node-version: "20.x"
31 |
32 | - name: Install Python
33 | uses: actions/setup-python@v5
34 | with:
35 | python-version: "3.x"
36 |
37 | - name: Install Dependencies
38 | run: |
39 | npm install
40 | pip install PyYAML
41 |
42 | - name: Add Secret Files
43 | env:
44 | NOTIFICATION: ${{ secrets.NOTIFICATION }}
45 | STATISTICS: ${{ secrets.STATISTICS }}
46 | SUPPORT: ${{ secrets.SUPPORT }}
47 | run: |
48 | python scripts/pre_deploy.py
49 |
50 | - name: Build Project
51 | run: |
52 | npm run build
53 |
54 | - name: Upload artifact
55 | uses: actions/upload-pages-artifact@v3
56 | with:
57 | path: 'dist'
58 |
59 | # Deploy job to GitHub Pages
60 | deploy:
61 | environment:
62 | name: github-pages
63 | url: ${{ steps.deployment.outputs.page_url }}
64 | runs-on: windows-latest
65 | needs: build
66 | steps:
67 | - name: Deploy to GitHub Pages
68 | id: deployment
69 | uses: actions/deploy-pages@v4
70 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 | node_modules/
3 | dist/
4 | config.json
5 | deploy.bat
6 | .env
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Lord Turmoil
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Code Paste
2 |
3 | Copyright © Tony's Studio 2023 - 2025
4 |
5 | ---
6 |
7 | [](https://github.com/Lord-Turmoil/CodePaste/actions/workflows/static.yml)
8 |
9 | ## Description
10 |
11 | This tool provides you the ability to create highlighted code block for Microsoft Office, mainly for Word and PowerPoint. You can use it to create a beautiful code block in your document or presentation.
12 |
13 | ### Try it now!
14 |
15 | - [Code Paste on Tony's Studio](https://codepaste.top/)
16 | - [Code Paste on GitHub Page](https://lord-turmoil.github.io/CodePaste/)
17 |
18 | ---
19 |
20 | ## Development
21 |
22 | If you find Code Paste useful and want to host it on your own, this section will be useful. By the way, feel free to contribute to this project. You can report bugs, suggest new features, or even submit a pull request. 😊
23 |
24 | ### Quick Start
25 |
26 | Code Paste is written in native HTML, CSS and JavaScript. To start development, clone the repo first, then install required packages.
27 |
28 | ```bash
29 | npm install
30 | npm run init # initialize placeholder files
31 | ```
32 |
33 | Then, you can run the project. There are three options for this.
34 |
35 | ```bash
36 | npm run build # build for production
37 | npm run dev # build for development and watch for changes
38 | ```
39 |
40 | > To preview the project locally, I recommend using [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) plugin for Visual Studio Code. Just open `dist/index.html` after your local server is on.
41 |
42 | ### Code Samples
43 |
44 | Code Paste provides sample code for each supported language. The supported languages are listed in `languages/lang.yml`, grouped by their categories. All the code samples are placed under `languages/samples/` directory.
45 |
46 | > [!NOTE]
47 | >
48 | > The display order of the language options in the final webpage is exactly the same as that in `lang.yml`.
49 |
50 | Managing language options in HTML and JavaScript is tedious, so there is a script to automatically generate related code. You should run this command after modifying the language list or adding new samples. This will generate `src/js/samples.js` and `src/views/components/languages.html`.
51 |
52 | ```bash
53 | npm run sample
54 | ```
55 |
56 | To add a new language, first add it to `languages/lang.yml`. In the suitable category, add a new list item in the format of `key value`, where `key` is the language id of [Prism.js](https://prismjs.com/#supported-languages), and the `value` is the display name of the language in the select box. Then, create a new file `{key}.txt` under `languages/samples/` and write your sample code in it. Finally, add this language to `.babelrc` so that it can be correctly loaded.
57 |
58 | ### Customization
59 |
60 | Since I removed sensitive information from the project, you need to run `npm run init` to create placeholder files even if you don't need them. These files are placed under `src/views/components/`.
61 |
62 | **Analytics**
63 |
64 | In file `statistics.html`, and place all your scripts into it. If you don't need them, just leave this file empty. Here is an example for this file.
65 |
66 | ```html
67 |
68 |
75 |
76 |
85 | ```
86 |
87 | **Notification**
88 |
89 | For users who visit your website for the first time, you may want to prompt a notice or agreement. In `notification.html`, write your custom `
` for it. The default class for it is `notification`, you can change it and add your own CSS style.
90 |
91 | ```html
92 |
93 |
Greetings from all members of Tony's Studio!
94 |
95 | ```
96 |
97 | **Support**
98 |
99 | If you want to add a support page, write it in `support.html`. Like notification, the default class for it is `coffee` and you can customize it. If you add this, there will be an extra support button in the center of the page.
100 |
101 | ```html
102 |
103 |
104 |
We appreciate your sponsorship!🌹
105 |
106 | ```
107 |
108 | ### Self-hosting
109 |
110 | There is still one step before you can host Code Paste on your website. I use [Font Awesome](https://fontawesome.com/) for lovely icons, and the linked JavaScript only works for my domain. Therefore, you have to get your kit [here](https://fontawesome.com/kits) and replace the link in `src/views/components/head.html`.
111 |
112 | After all these are done, just copy `dist` folder to your server and enjoy!🎉
113 |
114 | ---
115 |
116 | ## Sponsors 💖
117 |
118 | Here, I would like to express my sincere gratitude for all who sponsor Code Paste. THANK YOU! 🥰
119 |
120 | > I may not be able to know your GitHub account from the payment. If you bought me a coffee but are not present in the following table, feel free to contact me via E-mail.🙏
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | Pan-Pan-Pan
129 |
130 |
131 |
132 |
133 | Liu Yizhou
134 |
135 |
136 |
137 |
138 | hongshuobuaa
139 |
140 |
141 |
142 |
143 | 秋子夜
144 |
145 |
146 |
147 |
148 | GuoLan-Fruket
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/deploy.ps1:
--------------------------------------------------------------------------------
1 | # Mimic CI/CD pipeline to deploy project to remote host
2 | #
3 | # To run this script, you should have PowerShell 7.0 or later installed.
4 | # You can download it at https://github.com/PowerShell/PowerShell/releases
5 | #
6 | # To auto-deploy Hexo blog to remote host, follow these steps:
7 | #
8 | # 1. Create a .env file with the following content:
9 | # ```
10 | # username@hostname
11 | # /path/to/deploy
12 | # app-name
13 | # build folder
14 | # ```
15 | # - `username@hostname` can also be the connection name in your SSH config file.
16 | # - `app-name` is the name of the app folder on the remote host, thus the final path
17 | # will be `/path/to/deploy/app-name`.
18 | # - `build folder` is the folder to be deployed, e.g. `dist` for npm projects.
19 | #
20 | # 2. Run this script under project root directory.
21 | #
22 |
23 | # Read first and second line from .env file and raise error if not found
24 | $envFile = Get-Content .env
25 | $hostConnection = $envFile[0]
26 | if (-not $hostConnection) {
27 | Write-Host "Error: hostConnection not found in .env file" -ForegroundColor Red
28 | exit 1
29 | }
30 | $deployPath = $envFile[1]
31 | if (-not $deployPath) {
32 | Write-Host "Error: deployPath not found in .env file" -ForegroundColor Red
33 | exit 1
34 | }
35 | $tempPath = "$deployPath/tmp"
36 | $app = $envFile[2]
37 | if (-not $app) {
38 | Write-Host "Error: app not found in .env file" -ForegroundColor Red
39 | exit 1
40 | }
41 | $build = $envFile[3]
42 | if (-not $build) {
43 | Write-Host "Error: build not found in .env file" -ForegroundColor Red
44 | exit 1
45 | }
46 |
47 | # Pack build folder into tar.gz
48 | Write-Host "Packing build folder into tar.gz"
49 | $randomString = -join ((65..90) + (97..122) | Get-Random -Count 10 | % {[char]$_})
50 | $archiveName = "$randomString.tar.gz"
51 | tar -czf $archiveName $build
52 |
53 | # Copy archive to remote host
54 | Write-Host "Copying archive to remote host"
55 | scp $archiveName ${hostConnection}:/tmp/$archiveName
56 |
57 | # Execute remote commands:
58 | Write-Host "Executing deploy commands"
59 | $commands= @(
60 | " rm -rf $tempPath/$build $deployPath/$app",
61 | " && tar -xzf /tmp/$archiveName -C $tempPath --overwrite",
62 | " && mv $tempPath/$build $deployPath/$app",
63 | " && rm /tmp/$archiveName"
64 | )
65 | ssh $hostConnection $commands
66 |
67 | # Delete archive
68 | Write-Host "Finishing up"
69 | Remove-Item $archiveName
70 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import globals from "globals";
2 | import pluginJs from "@eslint/js";
3 |
4 |
5 | export default [
6 | {
7 | languageOptions: { globals: globals.browser }
8 | },
9 | pluginJs.configs.recommended,
10 | {
11 | rules: {
12 | semi: "error",
13 | quotes: ["error", "double", { "avoidEscape": true }],
14 | }
15 | }
16 | ];
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "~/*": [
5 | "./src/js/*"
6 | ]
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/languages/lang.yml:
--------------------------------------------------------------------------------
1 | Programming Languages:
2 | - c C
3 | - cpp C++
4 | - csharp C#
5 | - go Go
6 | - java Java
7 | - kotlin Kotlin
8 | - perl Perl
9 | - python Python
10 | - r R
11 | - ruby Ruby
12 | - rust Rust
13 | - scala Scala
14 | - swift Swift
15 | Web Development:
16 | - css CSS
17 | - html HTML
18 | - javascript JavaScript
19 | - php PHP
20 | - typescript TypeScript
21 | Scripting Language:
22 | - bash Bash
23 | - batch Batch
24 | - lua Lua
25 | - powershell PowerShell
26 | Markup Language:
27 | - json JSON
28 | - latex LaTeX
29 | - markdown Markdown
30 | - toml TOML
31 | - xml XML
32 | - yaml YAML
33 | Configuration Language:
34 | - cmake CMake
35 | - docker Docker
36 | - makefile Makefile
37 | Database:
38 | - sql SQL
39 | Assembly Language:
40 | - llvm LLVM
41 | - nasm NASM
42 | Others:
43 | - diff Diff
44 | - glsl GLSL
45 | - matlab MATLAB
46 | - verilog Verilog
47 |
--------------------------------------------------------------------------------
/languages/samples/bash.txt:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | name="John"
4 | age=30
5 |
6 | if [ $age -lt 18 ]; then
7 | echo "$name is a minor."
8 | else
9 | echo "$name is an adult."
10 | fi
11 |
--------------------------------------------------------------------------------
/languages/samples/batch.txt:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | set name=John
4 | set age=30
5 |
6 | if %age% lss 18 (
7 | echo %name% is a minor.
8 | ) else (
9 | echo %name% is an adult.
10 | )
11 |
--------------------------------------------------------------------------------
/languages/samples/c.txt:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main() {
4 | int num = 10;
5 | int* ptr = #
6 |
7 | printf("The value of num is %d\n", num);
8 | printf("The value of ptr is %p\n", ptr);
9 | printf("The value that ptr points to is %d\n", *ptr);
10 |
11 | return 0;
12 | }
13 |
--------------------------------------------------------------------------------
/languages/samples/cmake.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.26)
2 | project(MIoC)
3 |
4 | set(CMAKE_CXX_STANDARD 11)
5 |
6 | # Add all source files
7 | file(GLOB_RECURSE SRC_LIST CONFIGURE_DEPENDS src/*.cpp)
8 |
9 | # Add final target.
10 | add_executable(${CMAKE_PROJECT_NAME} ${SRC_LIST})
11 |
12 | # dependency
13 | add_subdirectory(mioc)
14 | target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE mioc)
15 |
--------------------------------------------------------------------------------
/languages/samples/cpp.txt:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main() {
4 | std::cout << "Hello, there!" << std::endl;
5 | std::cout << "General Grievous!" << std::endl;
6 |
7 | return 0;
8 | }
9 |
--------------------------------------------------------------------------------
/languages/samples/csharp.txt:
--------------------------------------------------------------------------------
1 | public class Startup
2 | {
3 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
4 | {
5 | app.UseRouting();
6 | app.UseCors(CorsOptions.CorsPolicyName);
7 | app.UseEndpoints(endpoints => {
8 | endpoints.MapControllers();
9 | endpoints.MapSwagger();
10 | });
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/languages/samples/css.txt:
--------------------------------------------------------------------------------
1 | .action-wrapper .action {
2 | width: 50px;
3 | height: 50px;
4 | display: flex;
5 | justify-content: center;
6 | border-radius: 50%;
7 | align-self: center;
8 | cursor: pointer;
9 | transition: 0.3s;
10 | }
11 |
--------------------------------------------------------------------------------
/languages/samples/diff.txt:
--------------------------------------------------------------------------------
1 | - Jedi Order
2 | + Sith Empire
3 | - Kamino
4 | - Alderaan
5 | + Mandalore
6 |
--------------------------------------------------------------------------------
/languages/samples/docker.txt:
--------------------------------------------------------------------------------
1 | # PatBoot Dockerfile
2 |
3 | FROM openjdk:17-jdk-slim
4 |
5 | ARG VERSION
6 |
7 | COPY target/PatBoot-${VERSION}.jar /application.jar
8 |
9 | EXPOSE 8080
10 |
11 | CMD ["java", "-jar", "/application.jar"]
12 |
--------------------------------------------------------------------------------
/languages/samples/glsl.txt:
--------------------------------------------------------------------------------
1 | #version 450 core
2 |
3 | layout(location = 0) out vec4 o_Color;
4 |
5 | struct VertexOutput
6 | {
7 | vec4 Color;
8 | };
9 |
10 | layout (location = 0) in VertexOutput Input;
11 |
12 | void main()
13 | {
14 | o_Color = Input.Color;
15 | }
16 |
--------------------------------------------------------------------------------
/languages/samples/go.txt:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func add(a int, b int) int {
6 | return a + b
7 | }
8 |
9 | func main() {
10 | sum := add(3, 4)
11 | fmt.Println("Sum:", sum)
12 | }
13 |
--------------------------------------------------------------------------------
/languages/samples/html.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello, world!
6 |
7 |
8 | Hello, world!
9 |
10 |
11 |
--------------------------------------------------------------------------------
/languages/samples/java.txt:
--------------------------------------------------------------------------------
1 | public class Main {
2 | public static void main(String[] args) {
3 | int a = 5;
4 | int b = 10;
5 | int sum = add(a, b);
6 | System.out.println("Sum: " + sum);
7 | }
8 |
9 | public static int add(int a, int b) {
10 | return a + b;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/languages/samples/javascript.txt:
--------------------------------------------------------------------------------
1 | function fibonacci(n) {
2 | let a = 0, b = 1;
3 | while (a < n) {
4 | console.log(a);
5 | [a, b] = [b, a + b];
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/languages/samples/json.txt:
--------------------------------------------------------------------------------
1 | {
2 | "name": "John Doe",
3 | "age": 30,
4 | "email": "johndoe@example.com",
5 | "address": {
6 | "street": "123 Main St",
7 | "city": "Anytown",
8 | "state": "CA",
9 | "zip": "12345"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/languages/samples/kotlin.txt:
--------------------------------------------------------------------------------
1 | fun main() {
2 | val numbers = listOf(1, 2, 3, 4, 5)
3 | val evenNumbers = numbers.map { it * 2 }.filter { it % 2 == 0 }
4 | val sumOfEvenNumbers = evenNumbers.sum()
5 |
6 | println("Original numbers: $numbers")
7 | println("Even numbers: $evenNumbers")
8 | println("Sum of even numbers: $sumOfEvenNumbers")
9 | }
10 |
11 | fun factorial(n: Int): Int {
12 | return if (n == 0) 1 else n * factorial(n - 1)
13 | }
14 |
--------------------------------------------------------------------------------
/languages/samples/latex.txt:
--------------------------------------------------------------------------------
1 | The Pythagorean theorem states that
2 | for a right triangle with legs of
3 | length $a$ and $b$ and hypotenuse of
4 | length $c$, the following equation holds:
5 |
6 | $$a^2 + b^2 = c^2$$
7 |
--------------------------------------------------------------------------------
/languages/samples/llvm.txt:
--------------------------------------------------------------------------------
1 | ; Function Attrs: noinline nounwind optnone uwtable
2 | define dso_local i32 @add(i32 %0, i32 %1) #0 {
3 | %3 = alloca i32, align 4
4 | %4 = alloca i32, align 4
5 | store i32 %0, i32* %3, align 4
6 | store i32 %1, i32* %4, align 4
7 | %5 = load i32, i32* %3, align 4
8 | %6 = load i32, i32* %4, align 4
9 | %7 = add i32 %5, %6
10 | ret i32 %7
11 | }
12 |
--------------------------------------------------------------------------------
/languages/samples/lua.txt:
--------------------------------------------------------------------------------
1 | function printNumbers(n)
2 | for i = 1, n do
3 | print(i)
4 | end
5 | end
6 |
7 | printNumbers(10)
8 |
--------------------------------------------------------------------------------
/languages/samples/makefile.txt:
--------------------------------------------------------------------------------
1 | CC = gcc
2 | CFLAGS = -Wall -Wextra -pedantic
3 |
4 | all: program
5 |
6 | program: main.o utils.o
7 | $(CC) $(CFLAGS) -o program main.o utils.o
8 |
9 | main.o: main.c utils.h
10 | $(CC) $(CFLAGS) -c main.c
11 |
12 | utils.o: utils.c utils.h
13 | $(CC) $(CFLAGS) -c utils.c
14 |
15 | clean:
16 | rm -f program *.o
17 |
--------------------------------------------------------------------------------
/languages/samples/markdown.txt:
--------------------------------------------------------------------------------
1 | # My Shopping List
2 |
3 | > This is a good list.
4 |
5 | - Apples
6 | - Bananas
7 | - Oranges
8 | - Strawberries
9 |
--------------------------------------------------------------------------------
/languages/samples/matlab.txt:
--------------------------------------------------------------------------------
1 | % Define the range of x values
2 | x = linspace(0, 2*pi, 100);
3 |
4 | % Calculate the sine of each x value
5 | y = sin(x);
6 |
7 | % Create a plot of the sine wave
8 | figure;
9 | plot(x, y);
10 |
11 | % Add title and labels
12 | title('Sine Wave');
13 | xlabel('x');
14 | ylabel('sin(x)');
15 |
16 | % Display grid
17 | grid on;
18 |
--------------------------------------------------------------------------------
/languages/samples/nasm.txt:
--------------------------------------------------------------------------------
1 | section .data
2 | msg db 'Ready, assemble!', 0xA
3 | len equ $ - msg
4 |
5 | section .text
6 | global _start
7 |
8 | _start:
9 | mov eax, 4 ; syscall number for sys_write
10 | mov ebx, 1 ; file descriptor 1 (stdout)
11 | mov ecx, msg ; pointer to the message
12 | mov edx, len ; length of the message
13 | int 0x80 ; make the syscall
14 |
15 | mov eax, 1 ; syscall number for sys_exit
16 | xor ebx, ebx ; exit status 0
17 | int 0x80 ; make the syscall
18 |
--------------------------------------------------------------------------------
/languages/samples/perl.txt:
--------------------------------------------------------------------------------
1 | sub printNumbers {
2 | my $n = shift;
3 | for (my $i = 1; $i <= $n; $i++) {
4 | print "$i\n";
5 | }
6 | }
7 |
8 | printNumbers(10);
9 |
--------------------------------------------------------------------------------
/languages/samples/php.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/languages/samples/powershell.txt:
--------------------------------------------------------------------------------
1 | $name = "John"
2 |
3 | for ($i = 1; $i -le 5; $i++) {
4 | Write-Host "Hello, $name! This is message number $i."
5 | }
6 |
--------------------------------------------------------------------------------
/languages/samples/python.txt:
--------------------------------------------------------------------------------
1 | def fibonacci(n):
2 | a, b = 0, 1
3 | while a < n:
4 | print(a)
5 | a, b = b, a + b
6 |
7 | fibonacci(100)
8 |
--------------------------------------------------------------------------------
/languages/samples/r.txt:
--------------------------------------------------------------------------------
1 | # Generate a sequence of numbers from 0 to 2*pi
2 | x <- seq(0, 2*pi, length.out = 100)
3 |
4 | # Compute the sine of each number
5 | y <- sin(x)
6 |
7 | # Plot the sine wave
8 | plot(x, y, type = "l", col = "blue", lwd = 2,
9 | main = "Sine Wave", xlab = "x", ylab = "sin(x)")
10 |
11 | # Add grid lines for better visualization
12 | grid()
13 |
--------------------------------------------------------------------------------
/languages/samples/ruby.txt:
--------------------------------------------------------------------------------
1 | name = "John"
2 | age = 30
3 |
4 | if age < 18
5 | puts "#{name} is a minor."
6 | else
7 | puts "#{name} is an adult."
8 | end
9 |
10 | 5.times do |i|
11 | puts "This is message number #{i + 1}."
12 | end
13 |
--------------------------------------------------------------------------------
/languages/samples/rust.txt:
--------------------------------------------------------------------------------
1 | fn main() {
2 | let name = "Rust";
3 | let version = 1.56;
4 |
5 | println!("Hello, {}!", name);
6 | println!("Current version: {}", version);
7 |
8 | let sum = add(5, 10);
9 | println!("Sum of 5 and 10 is: {}", sum);
10 | }
11 |
12 | fn add(a: i32, b: i32) -> i32 {
13 | a + b
14 | }
15 |
--------------------------------------------------------------------------------
/languages/samples/scala.txt:
--------------------------------------------------------------------------------
1 | val counter = Var(0)
2 |
3 | // create a counter button that increments on-click
4 | def counterButton() = button(
5 | tpe := "button",
6 | "count is ",
7 | child.text <-- counter,
8 | onClick --> { event => counter.update(c => c + 1) },
9 | )
10 | val app = dom.document.getElementById("app")
11 | render(app, counterButton())
12 |
--------------------------------------------------------------------------------
/languages/samples/sql.txt:
--------------------------------------------------------------------------------
1 | CREATE TABLE users (
2 | id INT PRIMARY KEY,
3 | name VARCHAR(50),
4 | email VARCHAR(50)
5 | );
6 |
7 | INSERT INTO users (id, name, email)
8 | VALUES (1, 'John Doe', 'johndoe@example.com'),
9 | (2, 'Jane Smith', 'janesmith@example.com'),
10 | (3, 'Bob Johnson', 'bobjohnson@example.com');
11 |
12 | SELECT * FROM users;
13 |
--------------------------------------------------------------------------------
/languages/samples/swift.txt:
--------------------------------------------------------------------------------
1 | let numbers = [1, 2, 3, 4, 5]
2 |
3 | let doubledNumbers = numbers.map { $0 * 2 }
4 |
5 | print(doubledNumbers)
6 |
--------------------------------------------------------------------------------
/languages/samples/toml.txt:
--------------------------------------------------------------------------------
1 | # This is a TOML document
2 |
3 | title = "TOML Example"
4 |
5 | [owner]
6 | name = "Tom Preston-Werner"
7 | dob = 1979-05-27T07:32:00-08:00
8 |
9 | [database]
10 | enabled = true
11 | ports = [ 8000, 8001, 8002 ]
12 | data = [ ["delta", "phi"], [3.14] ]
13 | temp_targets = { cpu = 79.5, case = 72.0 }
14 |
15 | [servers]
16 |
17 | [servers.alpha]
18 | ip = "10.0.0.1"
19 | role = "frontend"
20 |
21 | [servers.beta]
22 | ip = "10.0.0.2"
23 | role = "backend"
--------------------------------------------------------------------------------
/languages/samples/typescript.txt:
--------------------------------------------------------------------------------
1 | function fibonacci(n: number): void {
2 | let a: number = 0, b: number = 1;
3 | while (a < n) {
4 | console.log(a);
5 | [a, b] = [b, a + b];
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/languages/samples/verilog.txt:
--------------------------------------------------------------------------------
1 | module counter(
2 | input clk,
3 | input rst,
4 | output reg [7:0] count
5 | );
6 |
7 | always @(posedge clk, posedge rst) begin
8 | if (rst) begin
9 | count <= 0;
10 | end else begin
11 | count <= count + 1;
12 | end
13 | end
14 |
15 | endmodule
16 |
--------------------------------------------------------------------------------
/languages/samples/xml.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Star Wars
5 | George Lucas
6 | 10.99
7 |
8 |
9 | The Silent Spring
10 | Rachel Carson
11 | 7.99
12 |
13 |
14 |
--------------------------------------------------------------------------------
/languages/samples/yaml.txt:
--------------------------------------------------------------------------------
1 | - title: The Great Gatsby
2 | author: F. Scott Fitzgerald
3 | year: 1925
4 | publisher: Scribner
5 | - title: To Kill a Mockingbird
6 | author: Harper Lee
7 | year: 1960
8 | publisher: J. B. Lippincott & Co.
9 | - title: 1984
10 | author: George Orwell
11 | year: 1949
12 | publisher: Secker & Warburg
13 | - title: The Catcher in the Rye
14 | author: J. D. Salinger
15 | year: 1951
16 | publisher: Little, Brown and Company
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "code-paste",
3 | "version": "3.1.1",
4 | "description": "Online code highlighter for Microsoft Word and PowerPoint",
5 | "main": "index.js",
6 | "scripts": {
7 | "build:html": "posthtml -c posthtml.json",
8 | "build:js": "webpack --mode=production",
9 | "build:css": "postcss src/css -d dist/css",
10 | "build:res": "shx cp -r src/res src/favicon.png dist",
11 | "build:version": "python scripts/minify_json.py src/version.json dist/version.json",
12 | "build": "rimraf dist && npm run sample && npm-run-all build:* && python scripts/post_build.py",
13 | "build-dev:html": "posthtml -c posthtml.json",
14 | "build-dev:js": "webpack --mode=development",
15 | "build-dev:css": "postcss src/css -d dist/css",
16 | "build-dev:res": "shx cp -r src/res src/favicon.png dist",
17 | "build-dev:version": "shx cp src/version.json dist/version.json",
18 | "build-dev": "npm run sample && npm-run-all build-dev:*",
19 | "watch:html": "onchange \"src/views\" -- npm run build-dev:html",
20 | "watch:js": "onchange \"src/js\" -- npm run build-dev:js",
21 | "watch:css": "onchange \"src/css\" -- npm run build-dev:css",
22 | "watch:res": "onchange \"src/res\" -- npm run build-dev:res",
23 | "watch:samples": "onchange \"languages\" -- npm run sample",
24 | "watch:version": "onchange \"src/version.json\" -- npm run build-dev:version",
25 | "dev": "npm run build-dev && run-p watch:*",
26 | "sample": "python scripts/update_samples.py",
27 | "init": "shx touch src/views/components/notification.html src/views/components/support.html src/views/components/statistics.html",
28 | "lint": ".\\node_modules\\.bin\\eslint src\\** --fix",
29 | "deploy": "npm run build && pwsh deploy.ps1"
30 | },
31 | "keywords": [
32 | "highlighter",
33 | "code",
34 | "office",
35 | "word",
36 | "powerpoint"
37 | ],
38 | "author": "Tony Skywalker",
39 | "license": "MIT",
40 | "devDependencies": {
41 | "@babel/preset-env": "^7.25.4",
42 | "@eslint/js": "^9.11.1",
43 | "babel-loader": "^9.2.1",
44 | "babel-plugin-module-resolver": "^5.0.2",
45 | "babel-plugin-prismjs": "^2.1.0",
46 | "css-loader": "^7.1.2",
47 | "cssnano": "^7.0.6",
48 | "eslint": "^9.11.1",
49 | "eslint-config-webpack": "^1.2.5",
50 | "eslint-webpack-plugin": "^4.2.0",
51 | "globals": "^15.9.0",
52 | "htmlnano": "^2.1.1",
53 | "npm-run-all": "^4.1.5",
54 | "onchange": "^7.1.0",
55 | "postcss": "^8.4.47",
56 | "postcss-cli": "^11.0.0",
57 | "posthtml": "^0.16.6",
58 | "posthtml-cli": "^0.7.7",
59 | "posthtml-modules": "^0.9.1",
60 | "rimraf": "^6.0.1",
61 | "shx": "^0.3.4",
62 | "webpack": "^5.95.0",
63 | "webpack-cli": "^5.1.4"
64 | },
65 | "dependencies": {
66 | "alertifyjs": "^1.14.0",
67 | "jquery": "^3.7.1",
68 | "prismjs": "^1.29.0"
69 | }
70 | }
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('cssnano')({
4 | preset: 'default',
5 | }),
6 | ],
7 | };
--------------------------------------------------------------------------------
/posthtml.json:
--------------------------------------------------------------------------------
1 | {
2 | "input": "src/views/*.html",
3 | "output": "dist",
4 | "plugins": {
5 | "posthtml-modules": {
6 | "root": "./src/views",
7 | "initial": true
8 | },
9 | "htmlnano": {}
10 | }
11 | }
--------------------------------------------------------------------------------
/scripts/minify_json.py:
--------------------------------------------------------------------------------
1 | # Minify JSON
2 | # Usage: python minify_json.py
3 |
4 | import json
5 | import sys
6 |
7 |
8 | def minify_json(input_file, output_file):
9 | with open(input_file, "r") as f:
10 | data = json.load(f)
11 | with open(output_file, "w") as f:
12 | json.dump(data, f, separators=(",", ":"))
13 |
14 |
15 | if __name__ == "__main__":
16 | if len(sys.argv) != 3:
17 | print("Usage: python minify_json.py ")
18 | sys.exit(1)
19 | minify_json(sys.argv[1], sys.argv[2])
20 |
--------------------------------------------------------------------------------
/scripts/post_build.py:
--------------------------------------------------------------------------------
1 | """
2 | This script is used to auto rename bundle.js to bundle.[hash].js
3 | """
4 |
5 | import os
6 | import sys
7 |
8 | html_file = os.path.abspath("dist/index.html")
9 | bundle_file = os.path.abspath("dist/bundle.js")
10 |
11 | if not os.path.exists(html_file):
12 | print(f"Error: {html_file} not found.")
13 | sys.exit(1)
14 |
15 | if not os.path.exists(bundle_file):
16 | print(f"Error: {bundle_file} not found.")
17 | sys.exit(1)
18 |
19 | # get a random hash
20 | hash = os.urandom(4).hex()
21 |
22 | # rename bundle.js to bundle.[hash].js
23 | os.rename(bundle_file, os.path.join(os.path.dirname(bundle_file), f"bundle.{hash}.js"))
24 |
25 | # replace bundle.js with bundle.[hash].js in the HTML file
26 | with open(html_file, "r", encoding="utf-8") as f:
27 | content = f.read()
28 | content = content.replace("bundle.js", f"bundle.{hash}.js")
29 | with open(html_file, "w", encoding="utf-8") as f:
30 | f.write(content)
31 |
--------------------------------------------------------------------------------
/scripts/pre_deploy.py:
--------------------------------------------------------------------------------
1 | """
2 | This script is used to generate the private HTML files in
3 | GitHub actions. The HTML files are stored in the environment.
4 | """
5 |
6 | import os
7 |
8 | notification = os.environ["NOTIFICATION"]
9 | statistics = os.environ["STATISTICS"]
10 | support = os.environ["SUPPORT"]
11 |
12 | assert notification is not None
13 | assert statistics is not None
14 | assert support is not None
15 |
16 | print("Generating HTML files...")
17 | with open("src/views/components/notification.html", "w", encoding="utf-8") as f:
18 | f.write(notification)
19 | with open("src/views/components/statistics.html", "w", encoding="utf-8") as f:
20 | f.write(statistics)
21 | with open("src/views/components/support.html", "w", encoding="utf-8") as f:
22 | f.write(support)
23 | print("HTML files generated.")
24 |
--------------------------------------------------------------------------------
/scripts/update_samples.py:
--------------------------------------------------------------------------------
1 | """
2 | This script load all languages and generate necessary files for the app.
3 | """
4 |
5 | import json
6 | import os
7 | import yaml
8 |
9 | CONFIG_FILE = "languages/lang.yml"
10 | SAMPLES_DIR = "languages/samples"
11 | SAMPLES_JS = "src/js/samples.js"
12 | OPTIONS_HTML = "src/views/components/languages.html"
13 |
14 | with open(CONFIG_FILE, "r") as f:
15 | CONFIG = yaml.safe_load(f)
16 |
17 | LANGUAGES = []
18 | SAMPLES = {}
19 | for section in CONFIG:
20 | optgroup = {"label": section, "options": []}
21 | for language in CONFIG[section]:
22 | key, value = language.split(" ")
23 | optgroup["options"].append({"value": key, "text": value})
24 | with open(os.path.join(SAMPLES_DIR, f"{key}.txt"), "r") as f:
25 | SAMPLES[key] = f.read()
26 | LANGUAGES.append(optgroup)
27 |
28 | # Generate samples.js
29 | with open(SAMPLES_JS, "w") as f:
30 | # write the list of languages
31 | f.write("const CODE_SET = {\n")
32 | for sample in SAMPLES:
33 | f.write(f" {sample}: {json.dumps(SAMPLES[sample])},\n")
34 | f.write("};\n")
35 | f.write("export default CODE_SET;\n")
36 |
37 | # Generate languages.html
38 | with open(OPTIONS_HTML, "w") as f:
39 | for optgroup in LANGUAGES:
40 | f.write(f"\n")
41 | for option in optgroup["options"]:
42 | f.write(
43 | f" {option['text']} \n"
44 | )
45 | f.write(" \n")
46 |
--------------------------------------------------------------------------------
/src/css/dark.css:
--------------------------------------------------------------------------------
1 | /*
2 | _______
3 | / \
4 | .==. .==.
5 | (( ))==(( ))
6 | / "==" "=="\
7 | /____|| || ||___\
8 | ________ ____ ________ ___ ___
9 | | ___ \ / \ | ___ \ | | / /
10 | | | \ \ / /\ \ | | \ \| |_/ /
11 | | | ) / /__\ \ | |__/ /| ___ \
12 | | |__/ / ______ \| ____ \| | \ \
13 | _______|_______/__/ ____ \__\__|___\__\__|___\__\____
14 | | ___ \ | ____/ / \ | ___ \ | ____| ___ \
15 | | | \ \| |___ / /\ \ | | \ \| |___| | \ \
16 | | |__/ /| ____/ /__\ \ | | ) | ____| |__/ /
17 | | ____ \| |__/ ______ \| |__/ /| |___| ____ \
18 | |__| \__\____/__/ \__\_______/ |______|__| \__\
19 | https://darkreader.org
20 | */
21 |
22 | /*! Dark reader generated CSS | Licensed under MIT https://github.com/darkreader/darkreader/blob/main/LICENSE */
23 |
24 | /* User-Agent Style */
25 | @layer {
26 | html {
27 | background-color: #181a1b !important;
28 | filter: brightness(0.85) !important;
29 | }
30 |
31 | html {
32 | color-scheme: dark !important;
33 | }
34 |
35 | iframe {
36 | color-scheme: initial;
37 | }
38 |
39 | html,
40 | body {
41 | background-color: #181a1b;
42 | }
43 |
44 | html,
45 | body {
46 | border-color: #736b5e;
47 | color: #e8e6e3;
48 | }
49 |
50 | a {
51 | color: #3391ff;
52 | }
53 |
54 | table {
55 | border-color: #545b5e;
56 | }
57 |
58 | mark {
59 | color: #e8e6e3;
60 | }
61 |
62 | ::placeholder {
63 | color: #b2aba1;
64 | }
65 |
66 | input:-webkit-autofill,
67 | textarea:-webkit-autofill,
68 | select:-webkit-autofill {
69 | background-color: #404400 !important;
70 | color: #e8e6e3 !important;
71 | }
72 |
73 | ::-webkit-scrollbar {
74 | background-color: #202324 !important;
75 | color: #aba499 !important;
76 | }
77 |
78 | ::-webkit-scrollbar-thumb {
79 | background-color: #454a4d !important;
80 | }
81 |
82 | ::-webkit-scrollbar-thumb:hover {
83 | background-color: #575e62 !important;
84 | }
85 |
86 | ::-webkit-scrollbar-thumb:active {
87 | background-color: #484e51 !important;
88 | }
89 |
90 | ::-webkit-scrollbar-corner {
91 | background-color: #181a1b !important;
92 | }
93 |
94 | ::selection {
95 | background-color: #004daa !important;
96 | color: #e8e6e3 !important;
97 | }
98 |
99 | ::-moz-selection {
100 | background-color: #004daa !important;
101 | color: #e8e6e3 !important;
102 | }
103 | }
104 |
105 | /* Invert Style */
106 | .jfk-bubble.gtx-bubble,
107 | .captcheck_answer_label>input+img,
108 | span#closed_text>img[src^="https://www.gstatic.com/images/branding/googlelogo"],
109 | span[data-href^="https://www.hcaptcha.com/"]>#icon,
110 | ::-webkit-calendar-picker-indicator,
111 | img.Wirisformula {
112 | filter: invert(100%) hue-rotate(180deg) contrast(90%) !important;
113 | }
114 |
115 | /* Variables Style */
116 | :root {
117 | --darkreader-neutral-background: #131516;
118 | --darkreader-neutral-text: #d8d4cf;
119 | --darkreader-selection-background: #004daa;
120 | --darkreader-selection-text: #e8e6e3;
121 | }
122 |
123 | /* Modified CSS */
124 |
125 | .pace {
126 | background-color: rgb(24, 26, 27);
127 | background-image: initial;
128 | }
129 |
130 | .pace .pace-progress {
131 | background-color: rgb(154, 0, 0);
132 | }
133 |
134 | .pace .pace-activity {
135 | background-image: linear-gradient(45deg, rgba(24, 26, 27, 0.2) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(24, 26, 27, 0.2) 50%, rgba(24, 26, 27, 0.2) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0));
136 | }
137 |
138 | :root {
139 | --animate-delay: 1s;
140 | --animate-duration: 1s;
141 | --animate-repeat: 1;
142 | }
143 |
144 | :focus {
145 | outline-color: initial;
146 | }
147 |
148 | li {
149 | list-style-image: initial;
150 | }
151 |
152 | a {
153 | text-decoration-color: initial;
154 | }
155 |
156 | hr {
157 | background-image: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgb(47, 51, 53) 50%, rgba(0, 0, 0, 0) 100%);
158 | border-color: initial;
159 | border-style: none;
160 | border-width: initial;
161 | }
162 |
163 | .flip-wrapper .flip-inner .flip-front,
164 | .flip-wrapper .flip-inner .flip-back {
165 | box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 2px 1px;
166 | }
167 |
168 | .flip-wrapper .flip-inner .flip-front {
169 | background-color: rgb(62, 68, 70);
170 | color: rgb(232, 230, 227);
171 | }
172 |
173 | .flip-wrapper .flip-inner .flip-back {
174 | background-color: rgb(141, 0, 71);
175 | color: rgb(232, 230, 227);
176 | }
177 |
178 | .checkbox-wrapper-8 .tgl,
179 | .checkbox-wrapper-8 .tgl::after,
180 | .checkbox-wrapper-8 .tgl::before,
181 | .checkbox-wrapper-8 .tgl *,
182 | .checkbox-wrapper-8 .tgl ::after,
183 | .checkbox-wrapper-8 .tgl ::before,
184 | .checkbox-wrapper-8 .tgl+.tgl-btn {
185 | box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 2px 1px;
186 | }
187 |
188 | .checkbox-wrapper-8 .tgl+.tgl-btn {
189 | outline-color: initial;
190 | }
191 |
192 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn {
193 | background-color: rgb(91, 99, 103);
194 | background-image: initial;
195 | }
196 |
197 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn::after,
198 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn::before {
199 | color: rgb(232, 230, 227);
200 | text-shadow: rgba(0, 0, 0, 0.4) 0px 1px 0px;
201 | }
202 |
203 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn:active {
204 | background-color: rgb(91, 99, 103);
205 | background-image: initial;
206 | }
207 |
208 | .checkbox-wrapper-8 .tgl-skewed:checked+.tgl-btn {
209 | background-color: rgba(0, 164, 0, 0.8);
210 | background-image: initial;
211 | }
212 |
213 | .select-wrapper {
214 | --select-height: 40px;
215 | }
216 |
217 | .select {
218 | box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 2px 1px;
219 | }
220 |
221 | .select select {
222 | background-color: rgb(27, 54, 35);
223 | background-image: linear-gradient(-45deg, rgb(37, 71, 48) 0%, rgb(37, 53, 30) 100%);
224 | border-color: initial;
225 | border-style: none;
226 | border-width: initial;
227 | box-shadow: none;
228 | color: rgb(192, 187, 179);
229 | outline-color: initial;
230 | }
231 |
232 | .select::before {
233 | background-color: rgba(24, 26, 27, 0.1);
234 | color: rgba(107, 255, 107, 0.5);
235 | }
236 |
237 | .select:hover::before {
238 | background-color: rgba(24, 26, 27, 0.2);
239 | color: rgba(107, 255, 107, 0.8);
240 | }
241 |
242 | .glow-on-hover::before {
243 | background-color: initial;
244 | background-image: linear-gradient(45deg, rgb(204, 0, 0), rgb(204, 92, 0), rgb(153, 151, 0), rgb(94, 204, 0), rgb(0, 204, 179), rgb(0, 34, 204), rgb(98, 0, 204), rgb(204, 0, 160), rgb(204, 0, 0));
245 | }
246 |
247 | .glow-on-hover::after {
248 | background-color: rgb(62, 68, 70);
249 | }
250 |
251 | .glow-on-hover:hover::after {
252 | background-color: transparent;
253 | }
254 |
255 | .doc-wrapper {
256 | --h1-font-size: 1.6em;
257 | --h2-font-size: 1.3em;
258 | --h3-font-size: 1.1em;
259 | --p-font-size: 1em;
260 | }
261 |
262 | /* .doc-hr {
263 | background-image: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgb(47, 51, 53) 50%, rgba(0, 0, 0, 0) 100%);
264 | border-color: initial;
265 | border-style: none;
266 | border-width: initial;
267 | } */
268 |
269 | .alertify .ajs-dimmer {
270 | background-color: rgb(28, 30, 31);
271 | }
272 |
273 | .alertify .ajs-dialog {
274 | background-color: rgb(24, 26, 27);
275 | outline-color: initial;
276 | }
277 |
278 | .alertify .ajs-commands button {
279 | background-color: transparent;
280 | border-color: initial;
281 | border-style: initial;
282 | border-width: 0px;
283 | }
284 |
285 | .alertify .ajs-commands button.ajs-close {
286 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAh0lEQVQYlY2QsQ0EIQwEB9cBAR1CJUaI/gigDnwR6NBL/7/xWLNrZ2b8EwGotVpr7eOitWa1VjugiNB7R1UPrKrWe0dEAHBbXUqxMQbeewDmnHjvyTm7C3zDwAUd9c63YQdUVdu6EAJzzquz7HXvTiklt+H9DQFYaxFjvDqllFyMkbXWvfpXHjJrWFgdBq/hAAAAAElFTkSuQmCC");
287 | }
288 |
289 | .alertify .ajs-commands button.ajs-maximize {
290 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAOUlEQVQYlWP8//8/AzGAhYGBgaG4uBiv6t7eXkYmooxjYGAgWiELsvHYFMCcRX2rSXcjoSBiJDbAAeD+EGu+8BZcAAAAAElFTkSuQmCC");
291 | }
292 |
293 | .alertify .ajs-header {
294 | background-color: rgb(24, 26, 27);
295 | }
296 |
297 | .alertify .ajs-footer {
298 | background-color: rgb(24, 26, 27);
299 | }
300 |
301 | .alertify .ajs-handle {
302 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMS8xNEDQYmMAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAQ0lEQVQYlaXNMQoAIAxD0dT7H657l0KX3iJuUlBUNOsPPCGJm7VDp6ryeMxMuDsAQH7owW3pyn3RS26iKxERMLN3ugOaAkaL3sWVigAAAABJRU5ErkJggg==");
303 | }
304 |
305 | .alertify.ajs-maximized .ajs-commands button.ajs-maximize {
306 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAASklEQVQYlZWQ0QkAMQhDtXRincOZX78KVtrDCwgqJNEoIB3MPLj7lRUROlpyVXGzby6zWuY+kz6tj5sBMTMAyVV3/595RbOh3cAXsww1raeiOcoAAAAASUVORK5CYII=");
307 | }
308 |
309 | .alertify.ajs-modeless.ajs-pinnable .ajs-commands button.ajs-pin {
310 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAQklEQVQYlcWPMQ4AIAwCqU9u38GbcbHRWN1MvKQDhQFMEpKImGJA0gCgnYw0V0rwxseg5erT4oSkQVI5d9f+e9+xA0NbLpWfitPXAAAAAElFTkSuQmCC");
311 | }
312 |
313 | .alertify.ajs-modeless.ajs-unpinned .ajs-commands button.ajs-pin {
314 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAO0lEQVQYlWP8//8/AzGAiShV6AqLi4txGs+CLoBLMYbC3t5eRmyaWfBZhwwYkX2NTxPRvibKjRhW4wMAhxkYGbLu3pEAAAAASUVORK5CYII=");
315 | }
316 |
317 | .ajs-no-overflow {
318 | outline-color: initial;
319 | }
320 |
321 | .alertify-notifier .ajs-message.ajs-success {
322 | background-color: rgba(54, 135, 89, 0.95);
323 | background-image: initial;
324 | }
325 |
326 | .alertify-notifier .ajs-message.ajs-error {
327 | background-color: rgba(139, 32, 32, 0.95);
328 | background-image: initial;
329 | }
330 |
331 | .alertify-notifier .ajs-message.ajs-warning {
332 | background-color: rgba(146, 104, 0, 0.9);
333 | background-image: initial;
334 | }
335 |
336 | .alertify-notifier .ajs-message .ajs-close {
337 | background-color: rgba(0, 0, 0, 0.5);
338 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAABGdBTUEAALGPC/xhBQAAAFBJREFUGBl1j0EKADEIA+ve/P9f9bh1hEihNBfjVCO1v7RKVqJK4h8gM5cAPR42AkQEpSXPwMTyoi13n5N9YqJehm3Fnr7nL1D0ZEbD5OubGyC7a9gx+9eNAAAAAElFTkSuQmCC");
339 | }
340 |
341 | .border {
342 | background-image: linear-gradient(135deg, rgb(28, 31, 32) 0%, rgb(49, 53, 55) 100%);
343 | }
344 |
345 | .wrapper {
346 | --code-font-size: 14px;
347 | --panel-border-radius: 10px;
348 | --panel-max-height: 600px;
349 | --panel-min-height: 400px;
350 | }
351 |
352 | .wrapper .action-wrapper {
353 | --animate-duration: 1s;
354 | }
355 |
356 | #source {
357 | border-color: initial;
358 | border-style: none;
359 | border-width: initial;
360 | }
361 |
362 | #source:focus {
363 | box-shadow: rgba(8, 30, 51, 0.35) 0px 0px 6px 0px inset;
364 | }
365 |
366 | .panel .cover {
367 | --animate-duration: 0.3s;
368 | background-image: linear-gradient(45deg, rgb(20, 94, 92) 0%, rgb(74, 2, 25) 100%);
369 | box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 10px 2px inset;
370 | }
371 |
372 | .footer .copyright:hover {
373 | text-decoration-color: initial;
374 | }
375 |
376 | .doc-wrapper .bubble:hover {
377 | color: rgb(222, 219, 215);
378 | text-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;
379 | }
380 |
381 | .alertify-notifier .ajs-message.ajs-success {
382 | background-color: rgba(74, 147, 14, 0.9);
383 | background-image: initial;
384 | }
385 |
386 | .alertify-notifier .ajs-message.ajs-warning {
387 | background-color: rgba(146, 104, 0, 0.9);
388 | background-image: initial;
389 | }
390 |
391 | .alertify-notifier .ajs-message.ajs-error {
392 | background-color: rgba(203, 21, 0, 0.9);
393 | background-image: initial;
394 | }
395 |
396 | .alertify .ajs-dialog .ajs-button {
397 | background-color: rgba(6, 154, 77);
398 | border-color: initial;
399 | border-style: none;
400 | border-width: initial;
401 | box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 3px 2px;
402 | color: rgb(232, 230, 227);
403 | }
404 |
405 | .alertify .ajs-dialog .ajs-button:hover {
406 | box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 3px 2px;
407 | }
408 |
409 | .action i {
410 | color: #c5c3c1;
411 | }
412 |
413 | .expand {
414 | background-color: rgb(62, 68, 70);
415 | }
416 | .expand:hover {
417 | background-color: rgb(72, 78, 81);
418 | box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 5px 2px;
419 | }
420 | .expand:active {
421 | background-color: rgb(82, 88, 92);
422 | }
423 |
424 | .code {
425 | filter: brightness(0.85);
426 | }
--------------------------------------------------------------------------------
/src/css/doc.css:
--------------------------------------------------------------------------------
1 | .doc-wrapper {
2 | --h1-font-size: 1.6em;
3 | --h2-font-size: 1.3em;
4 | --h3-font-size: 1.1em;
5 | --p-font-size: 1em;
6 | width: 80%;
7 | max-width: 1000px;
8 | margin: 10px auto;
9 | }
10 |
11 | .doc-wrapper .bubble {
12 | padding: 2px 8px;
13 | white-space: nowrap;
14 | /* it's a trick to make pill shape */
15 | border-radius: 100px;
16 | }
17 |
18 | .doc-wrapper .bubble:hover {
19 | color: #efefef;
20 | text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.5);
21 | }
22 |
23 | .doc-align-center {
24 | text-align: center;
25 | }
26 |
27 | .doc-align-left {
28 | text-align: left;
29 | }
30 |
31 | .doc-align-right {
32 | text-align: right;
33 | }
34 |
35 | .doc-align-justify {
36 | text-align: justify;
37 | }
38 |
39 | .doc-wrapper .doc-chapter {
40 | margin: 14px auto 10px auto;
41 | }
42 |
43 | .doc-wrapper .doc-chapter h1 {
44 | font-size: var(--h1-font-size);
45 | font-family: 'Lucida Handwriting';
46 | }
47 |
48 | .doc-wrapper .doc-section {
49 | margin: 10px auto 6px auto;
50 | }
51 |
52 | .doc-wrapper .doc-section h2 {
53 | font-size: var(--h2-font-size);
54 | }
55 |
56 | .doc-wrapper .doc-section .doc-indent {
57 | text-indent: calc(var(--h2-font-size) * 2);
58 | }
59 |
60 | .doc-wrapper .doc-entry {
61 | margin: 8px auto 16px auto;
62 | }
63 |
64 | .doc-wrapper .doc-entry h3 {
65 | font-size: var(--h3-font-size);
66 | }
67 |
68 | .doc-wrapper .doc-entry.doc-indent {
69 | text-indent: calc(var(--h3-font-size) * 2);
70 | }
71 |
72 | .doc-wrapper .doc-text {
73 | margin: 4px auto;
74 | }
75 |
76 | .doc-wrapper .doc-text p {
77 | margin: 8px auto;
78 | }
79 |
80 | .doc-wrapper .doc-text p {
81 | font-size: var(--p-font-size);
82 | }
83 |
84 | .doc-wrapper .doc-text .doc-indent {
85 | text-indent: calc(var(--p-font-size) * 2);
86 | }
87 |
88 | .doc-hr {
89 | width: 80%;
90 | margin: 5px auto;
91 | height: 1px;
92 | border: none;
93 | background-image: linear-gradient(90deg, transparent 0%, #3f3f3f 50%, transparent 100%);
94 | }
95 |
96 | .doc-badge-base {
97 | position: relative;
98 | display: inline-block;
99 | }
100 |
101 | .doc-badge {
102 | position: absolute;
103 | right: 0;
104 | top: 0;
105 | transform: translate(100%, -30%);
106 | }
--------------------------------------------------------------------------------
/src/css/effect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --mode-transition: 0.2s;
3 | }
4 |
5 | html,
6 | body,
7 | .border,
8 | .border textarea,
9 | .tool *,
10 | .code * {
11 | transition: var(--mode-transition);
12 | }
13 |
14 | /* flip badge */
15 | .flip-wrapper {
16 | width: 2em;
17 | height: 2em;
18 | line-height: 2em;
19 | text-align: center;
20 | transition: opacity 0.2s;
21 | padding: 5px;
22 | cursor: pointer;
23 | }
24 |
25 | .flip-wrapper:hover {
26 | opacity: 80%;
27 | }
28 |
29 | .flip-inner {
30 | position: relative;
31 | width: 100%;
32 | height: 100%;
33 | text-align: center;
34 | transition: transform 0.3s;
35 | transform-style: preserve-3d;
36 | }
37 |
38 | .flip-wrapper .active {
39 | transform: rotateY(180deg);
40 | }
41 |
42 | .flip-wrapper .flip-inner .flip-front,
43 | .flip-wrapper .flip-inner .flip-back {
44 | position: absolute;
45 | width: 100%;
46 | height: 100%;
47 | -webkit-backface-visibility: hidden;
48 | backface-visibility: hidden;
49 | border-radius: 50%;
50 | overflow: hidden;
51 | box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
52 | }
53 |
54 | .flip-wrapper .flip-inner .flip-front {
55 | background-color: #bbb;
56 | color: black;
57 | }
58 |
59 | .flip-wrapper .flip-inner .flip-back {
60 | background-color: #FF69B4;
61 | color: white;
62 | transform: rotateY(180deg);
63 | }
64 |
65 | /* checkbox */
66 | .checkbox-wrapper-8 .tgl {
67 | display: none;
68 | }
69 |
70 | .checkbox-wrapper-8 .tgl,
71 | .checkbox-wrapper-8 .tgl:after,
72 | .checkbox-wrapper-8 .tgl:before,
73 | .checkbox-wrapper-8 .tgl *,
74 | .checkbox-wrapper-8 .tgl *:after,
75 | .checkbox-wrapper-8 .tgl *:before,
76 | .checkbox-wrapper-8 .tgl+.tgl-btn {
77 | box-sizing: border-box;
78 | box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
79 | }
80 |
81 | .checkbox-wrapper-8 .tgl::-moz-selection,
82 | .checkbox-wrapper-8 .tgl:after::-moz-selection,
83 | .checkbox-wrapper-8 .tgl:before::-moz-selection,
84 | .checkbox-wrapper-8 .tgl *::-moz-selection,
85 | .checkbox-wrapper-8 .tgl *:after::-moz-selection,
86 | .checkbox-wrapper-8 .tgl *:before::-moz-selection,
87 | .checkbox-wrapper-8 .tgl+.tgl-btn::-moz-selection,
88 | .checkbox-wrapper-8 .tgl::selection,
89 | .checkbox-wrapper-8 .tgl:after::selection,
90 | .checkbox-wrapper-8 .tgl:before::selection,
91 | .checkbox-wrapper-8 .tgl *::selection,
92 | .checkbox-wrapper-8 .tgl *:after::selection,
93 | .checkbox-wrapper-8 .tgl *:before::selection,
94 | .checkbox-wrapper-8 .tgl+.tgl-btn::selection {
95 | background: none;
96 | }
97 |
98 | .checkbox-wrapper-8 .tgl+.tgl-btn {
99 | outline: 0;
100 | display: block;
101 | width: 4em;
102 | height: 2em;
103 | position: relative;
104 | cursor: pointer;
105 | -webkit-user-select: none;
106 | -moz-user-select: none;
107 | -ms-user-select: none;
108 | user-select: none;
109 | }
110 |
111 | .checkbox-wrapper-8 .tgl+.tgl-btn:after,
112 | .checkbox-wrapper-8 .tgl+.tgl-btn:before {
113 | position: relative;
114 | display: block;
115 | content: "";
116 | width: 50%;
117 | height: 100%;
118 | }
119 |
120 | .checkbox-wrapper-8 .tgl+.tgl-btn:after {
121 | left: 0;
122 | }
123 |
124 | .checkbox-wrapper-8 .tgl+.tgl-btn:before {
125 | display: none;
126 | }
127 |
128 | .checkbox-wrapper-8 .tgl:checked+.tgl-btn:after {
129 | left: 50%;
130 | }
131 |
132 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn {
133 | overflow: hidden;
134 | /* transform: skew(-10deg); */
135 | -webkit-backface-visibility: hidden;
136 | backface-visibility: hidden;
137 | transition: all 0.2s ease;
138 | font-family: sans-serif;
139 | background: #888;
140 | border-radius: 10px;
141 | }
142 |
143 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn:after,
144 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn:before {
145 | /* transform: skew(10deg); */
146 | display: inline-block;
147 | transition: all 0.2s ease;
148 | width: 100%;
149 | text-align: center;
150 | position: absolute;
151 | line-height: 2em;
152 | font-weight: bold;
153 | color: #fff;
154 | text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
155 | }
156 |
157 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn:after {
158 | left: 100%;
159 | content: attr(data-tg-on);
160 | }
161 |
162 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn:before {
163 | left: 0;
164 | content: attr(data-tg-off);
165 | }
166 |
167 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn:active {
168 | background: #888;
169 | }
170 |
171 | .checkbox-wrapper-8 .tgl-skewed+.tgl-btn:active:before {
172 | left: -10%;
173 | }
174 |
175 | .checkbox-wrapper-8 .tgl-skewed:checked+.tgl-btn {
176 | background: #00CD00;
177 | }
178 |
179 | .checkbox-wrapper-8 .tgl-skewed:checked+.tgl-btn:before {
180 | left: -100%;
181 | }
182 |
183 | .checkbox-wrapper-8 .tgl-skewed:checked+.tgl-btn:after {
184 | left: 0;
185 | }
186 |
187 | .checkbox-wrapper-8 .tgl-skewed:checked+.tgl-btn:active:after {
188 | left: 10%;
189 | }
190 |
191 | /* select */
192 |
193 | .select-wrapper {
194 | --select-height: 40px;
195 | }
196 |
197 | .select {
198 | position: relative;
199 | border-radius: 10px;
200 | overflow: hidden;
201 | height: var(--select-height);
202 | box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
203 | }
204 |
205 | .select select {
206 | background-image: linear-gradient(-45deg, #c1dfc4 0%, #deecdd 100%);
207 | background-color: #ddeede;
208 | color: #3f3f3f;
209 | padding: 12px;
210 | width: 250px;
211 | border: none;
212 | font-size: 16px;
213 | box-shadow: none;
214 | -webkit-appearance: none;
215 | appearance: none;
216 | outline: none;
217 | cursor: pointer;
218 | }
219 |
220 | .select::before {
221 | content: "\f13a";
222 | font-family: FontAwesome;
223 | position: absolute;
224 | top: 0;
225 | right: 0;
226 | height: 100%;
227 | aspect-ratio: 1;
228 | text-align: center;
229 | font-size: 28px;
230 | line-height: var(--select-height);
231 | color: rgba(0, 139, 0, 1.0);
232 | background-color: rgba(255, 255, 255, 0.1);
233 | pointer-events: none;
234 | transition: 0.3s;
235 | }
236 |
237 | .select:hover::before {
238 | color: rgba(0, 139, 0, 0.8);
239 | background-color: rgba(255, 255, 255, 0.2);
240 | }
241 |
242 | .select select option {
243 | padding: 30px;
244 | }
245 |
246 | /* glow button */
247 | .glow-on-hover {
248 | cursor: default;
249 | position: absolute;
250 | z-index: 0;
251 | border-radius: 10px;
252 | }
253 |
254 | .glow-on-hover::before {
255 | content: '';
256 | background: linear-gradient(45deg, #ff0000, #ff7300, #fffb00, #48ff00, #00ffd5, #002bff, #7a00ff, #ff00c8, #ff0000);
257 | position: absolute;
258 | top: -1px;
259 | left: -1px;
260 | background-size: 400%;
261 | z-index: -1;
262 | filter: blur(5px);
263 | width: calc(100% + 2px);
264 | height: calc(100% + 2px);
265 | animation: glowing 30s linear infinite;
266 | opacity: 0;
267 | transition: opacity .3s ease-in-out;
268 | border-radius: 10px;
269 | }
270 |
271 | .glow-on-hover:hover::before {
272 | opacity: 1;
273 | }
274 |
275 | .glow-on-hover::after {
276 | z-index: -1;
277 | content: '';
278 | position: absolute;
279 | width: 100%;
280 | height: 100%;
281 | background-color: #bbb;
282 | border-radius: 100px;
283 | left: 0;
284 | top: 0;
285 | transition: background-color 0.3s;
286 | }
287 |
288 | .glow-on-hover:hover::after {
289 | background-color: transparent;
290 | }
291 |
292 |
293 | @keyframes glowing {
294 | 0% {
295 | background-position: 0 0;
296 | }
297 |
298 | 50% {
299 | background-position: 400% 0;
300 | }
301 |
302 | 100% {
303 | background-position: 0 0;
304 | }
305 | }
306 |
307 | /* light theme scroll bar */
308 | ::-webkit-scrollbar {
309 | background-color: #fcfcfc;
310 | }
311 |
312 | ::-webkit-scrollbar-thumb {
313 | background-color: #8b8b8b;
314 | }
315 |
316 | ::-webkit-scrollbar-thumb:hover {
317 | background-color: #636363;
318 | }
319 |
320 | ::-webkit-scrollbar-thumb:active {
321 | background-color: #484e51
322 | }
323 |
324 | ::-webkit-scrollbar-corner {
325 | background-color: #181a1b;
326 | }
327 |
328 | .action i {
329 | color: #181a1b;
330 | }
--------------------------------------------------------------------------------
/src/css/fonts.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Lucida Handwriting';
3 | src: url('../res/fonts/LucidaHandwriting-Italic.eot');
4 | src: url('../res/fonts/LucidaHandwriting-Italic.eot?#iefix') format('embedded-opentype'),
5 | url('../res/fonts/LucidaHandwriting-Italic.woff2') format('woff2'),
6 | url('../res/fonts/LucidaHandwriting-Italic.woff') format('woff'),
7 | url('../res/fonts/LucidaHandwriting-Italic.svg#LucidaHandwriting-Italic') format('svg');
8 | font-weight: normal;
9 | font-style: italic;
10 | font-display: swap;
11 | }
12 |
13 | @font-face {
14 | font-family: 'Consolas';
15 | src: url('../res/fonts/Consolas.eot');
16 | src: url('../res/fonts/Consolas.eot?#iefix') format('embedded-opentype'),
17 | url('../res/fonts/Consolas.woff2') format('woff2'),
18 | url('../res/fonts/Consolas.woff') format('woff'),
19 | url('../res/fonts/Consolas.svg#Consolas') format('svg');
20 | font-weight: normal;
21 | font-style: normal;
22 | font-display: swap;
23 | }
24 |
--------------------------------------------------------------------------------
/src/css/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | *:focus {
7 | outline: none;
8 | }
9 |
10 | li {
11 | list-style: none;
12 | }
13 |
14 | .clearfix:before,
15 | .clearfix::after {
16 | content: "";
17 | display: table;
18 | }
19 |
20 | .clearfix::after {
21 | clear: both;
22 | }
23 |
24 | .clearfix {
25 | zoom: 1;
26 | }
27 |
28 | a {
29 | text-decoration: none;
30 | }
31 |
32 | /* common styles */
33 | body {
34 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
35 | }
36 |
37 | hr {
38 | width: 90%;
39 | margin: 0px auto;
40 | height: 2px;
41 | border: none;
42 | background-image: linear-gradient(90deg, transparent 0%, #3f3f3f 50%, transparent 100%);
43 | }
44 |
45 | html,
46 | body {
47 | height: 100%;
48 | width: 100%;
49 | overflow-x: auto;
50 | }
51 |
52 | .border {
53 | width: 100%;
54 | min-width: 600px;
55 | min-height: 100%;
56 | overflow-x: hidden;
57 | background-color: rgb(228, 233, 240);
58 | }
59 |
60 | /* header */
61 | .header {
62 | padding: 10px;
63 | text-align: center;
64 | }
65 |
66 | .header span {
67 | font-family: 'Lucida Handwriting';
68 | font-size: 3em;
69 | font-weight: bold;
70 | }
71 |
72 | .header span img {
73 | height: 1.7em;
74 | vertical-align: middle;
75 | margin: 0 5px;
76 | }
77 |
78 | #logo {
79 | cursor: pointer;
80 | }
81 |
82 | /* marquee */
83 | .banner {
84 | margin: 5px 0;
85 | }
86 |
87 | /* tool bar */
88 | .tools-wrapper {
89 | display: flex;
90 | flex-direction: row;
91 | justify-content: center;
92 | margin: 10px;
93 | }
94 |
95 | .tools-wrapper .tools {
96 | display: flex;
97 | flex-direction: row;
98 | justify-content: center;
99 | justify-self: start;
100 | }
101 |
102 | .tools-wrapper .tools .tool {
103 | align-self: center;
104 | display: flex;
105 | flex-direction: row;
106 | margin: 5px;
107 | }
108 |
109 | .tools-wrapper .tools .tool>div {
110 | margin: 0 5px;
111 | align-self: center;
112 | }
113 |
114 | .tools-wrapper .flip-wrapper {
115 | align-self: center;
116 | margin-left: 10px;
117 | }
118 |
119 | /* code panel */
120 | .wrapper {
121 | --panel-min-height: 400px;
122 | --panel-max-height: 600px;
123 | --panel-border-radius: 10px;
124 | --code-font-size: 14px;
125 | box-sizing: border-box;
126 | display: flex;
127 | flex-direction: row;
128 | width: 95%;
129 | margin: 10px auto;
130 | }
131 |
132 | .wrapper .panel {
133 | position: relative;
134 | width: 50%;
135 | align-self: flex-start;
136 | min-height: var(--panel-min-height);
137 | max-height: var(--panel-max-height);
138 | flex-grow: 0;
139 | overflow: hidden;
140 | overflow-y: overlay;
141 | }
142 |
143 | .wrapper .action-wrapper {
144 | --animate-duration: 1s;
145 | display: flex;
146 | flex-direction: column;
147 | align-self: center;
148 | }
149 |
150 | .action-wrapper .action {
151 | width: 50px;
152 | height: 50px;
153 | display: flex;
154 | justify-content: center;
155 | border-radius: 50%;
156 | align-self: center;
157 | cursor: pointer;
158 | transition: 0.3s;
159 | }
160 |
161 | .action-wrapper .action:hover {
162 | opacity: 80%;
163 | transform: scale(1.1);
164 | }
165 |
166 | .action-wrapper .action i {
167 | align-self: center;
168 | font-size: 30px;
169 | }
170 |
171 | .wrapper .action-wrapper .animate__spin i {
172 | animation: spin 0.5s ease 0s forwards;
173 | }
174 |
175 | @keyframes spin {
176 | 0% {
177 | -webkit-transform: rotate(0);
178 | transform: rotate(0);
179 | }
180 |
181 | 100% {
182 | -webkit-transform: rotate(360deg);
183 | transform: rotate(360deg);
184 | }
185 | }
186 |
187 | .wrapper .action-wrapper .animate__grow i {
188 | animation: grow 0.5s ease 0s forwards;
189 | }
190 |
191 | @keyframes grow {
192 | 0% {
193 | -webkit-transform: scale(1.0);
194 | transform: scale(1.0);
195 | }
196 |
197 | 20% {
198 | -webkit-transform: scale(0.8);
199 | transform: scale(0.8);
200 | }
201 |
202 | 60% {
203 | -webkit-transform: scale(1.2);
204 | transform: scale(1.2);
205 | }
206 |
207 | 100% {
208 | -webkit-transform: scale(1.0);
209 | transform: scale(1.0);
210 | }
211 | }
212 |
213 | .wrapper .action-wrapper .animate__shake i {
214 | animation: shake 0.5s ease 0s forwards;
215 | }
216 |
217 | @keyframes shake {
218 |
219 | 0%,
220 | to {
221 | -webkit-transform: translateZ(0);
222 | transform: translateZ(0)
223 | }
224 |
225 | 20%,
226 | 60% {
227 | -webkit-transform: translate3d(-5px, 0, 0);
228 | transform: translate3d(-5px, 0, 0)
229 | }
230 |
231 |
232 | 40%,
233 | 80% {
234 | -webkit-transform: translate3d(5px, 0, 0);
235 | transform: translate3d(5px, 0, 0)
236 | }
237 | }
238 |
239 | .wrapper .action-wrapper .animate__rubber i {
240 | animation: rubber 0.5s ease 0s forwards;
241 | }
242 |
243 | @keyframes rubber {
244 | 0% {
245 | -webkit-transform: scaleX(1);
246 | transform: scaleX(1)
247 | }
248 |
249 | 30% {
250 | -webkit-transform: scale3d(1.25, .75, 1);
251 | transform: scale3d(1.25, .75, 1)
252 | }
253 |
254 | 40% {
255 | -webkit-transform: scale3d(.75, 1.25, 1);
256 | transform: scale3d(.75, 1.25, 1)
257 | }
258 |
259 | 50% {
260 | -webkit-transform: scale3d(1.15, .85, 1);
261 | transform: scale3d(1.15, .85, 1)
262 | }
263 |
264 | 65% {
265 | -webkit-transform: scale3d(.95, 1.05, 1);
266 | transform: scale3d(.95, 1.05, 1)
267 | }
268 |
269 | 75% {
270 | -webkit-transform: scale3d(1.05, .95, 1);
271 | transform: scale3d(1.05, .95, 1)
272 | }
273 |
274 | to {
275 | -webkit-transform: scale(1);
276 | transform: scale(1)
277 | }
278 | }
279 |
280 | .wrapper .action-wrapper .animate__blink i {
281 | animation: tada 0.5s ease 0s forwards;
282 | }
283 |
284 | @keyframes tada {
285 | 0% {
286 | -webkit-transform: scaleX(1);
287 | transform: scaleX(1.1)
288 | }
289 |
290 | 10%,
291 | 20% {
292 | -webkit-transform: scale3d(1.0, 1.0, 1.0) rotate(-3deg);
293 | transform: scale3d(1.0, 1.0, 1.0) rotate(-3deg)
294 | }
295 |
296 | 30%,
297 | 50%,
298 | 70%,
299 | 90% {
300 | -webkit-transform: scale3d(1.2, 1.2, 1.2) rotate(3deg);
301 | transform: scale3d(1.2, 1.2, 1.2) rotate(3deg)
302 | }
303 |
304 | 40%,
305 | 60%,
306 | 80% {
307 | -webkit-transform: scale3d(1.2, 1.2, 1.2) rotate(-3deg);
308 | transform: scale3d(1.2, 1.2, 1.2) rotate(-3deg)
309 | }
310 |
311 | to {
312 | -webkit-transform: scaleX(1.1);
313 | transform: scaleX(1.1)
314 | }
315 | }
316 |
317 | /* input text area */
318 | .wrapper .panel {
319 | min-height: var(--panel-min-height);
320 | }
321 |
322 | .wrapper .panel .code {
323 | box-sizing: border-box;
324 | width: 100%;
325 | min-height: var(--panel-min-height);
326 | max-height: var(--panel-max-height);
327 | border-radius: var(--panel-border-radius);
328 | overflow: hidden;
329 | }
330 |
331 | #source {
332 | box-sizing: border-box;
333 | width: 100%;
334 | resize: none;
335 | border: none;
336 | padding: 8px 10px;
337 | font-size: var(--code-font-size);
338 | border-radius: var(--panel-border-radius);
339 | z-index: 5;
340 | }
341 |
342 | #source:focus {
343 | box-shadow: 0px 0px 6px 0px inset rgba(10, 37, 64, 0.35);
344 | }
345 |
346 | .panel .cover {
347 | --animate-duration: 0.3s;
348 | position: absolute;
349 | left: 0;
350 | top: 0;
351 | width: 100%;
352 | height: 100%;
353 | display: flex;
354 | flex-direction: column;
355 | min-height: var(--panel-min-height);
356 | border-radius: var(--panel-border-radius);
357 | background-image: linear-gradient(45deg, #a8edea 0%, #fed6e3 100%);
358 | z-index: 5;
359 | text-align: center;
360 | overflow: auto;
361 | box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.1) inset;
362 | }
363 |
364 | .panel .cover p {
365 | align-self: center;
366 | width: 90%;
367 | margin: auto;
368 | }
369 |
370 | /* footer */
371 | .footer {
372 | width: 100%;
373 | text-align: center;
374 | }
375 |
376 | .footer .badge-wrapper {
377 | width: 100%;
378 | display: flex;
379 | flex-direction: row;
380 | justify-content: center;
381 | align-items: center;
382 | margin: 10px auto;
383 | }
384 |
385 | .footer .badge-wrapper .badge {
386 | margin: 0 5px;
387 | }
388 |
389 | .footer .copyright {
390 | display: inline-block;
391 | margin: auto;
392 | margin-bottom: 20px;
393 | text-align: center;
394 | font-family: 'Lucida Handwriting';
395 | }
396 |
397 | .footer .copyright:hover {
398 | text-decoration: underline;
399 | }
400 |
401 | @media screen and (max-width: 950px) {
402 | .tools-wrapper .tools {
403 | flex-direction: column;
404 | justify-content: flex-start;
405 | }
406 |
407 | .tools-wrapper .tools .tool {
408 | align-self: flex-start;
409 | }
410 |
411 | .tools-wrapper .tools .tool .prompt {
412 | width: 8em;
413 | text-align: right;
414 | }
415 | }
416 |
417 | @media screen and (max-width: 768px) {
418 | .wrapper {
419 | flex-direction: column;
420 | }
421 |
422 | .wrapper .panel {
423 | width: 100%;
424 | }
425 |
426 | .wrapper .action-wrapper {
427 | flex-direction: row;
428 | }
429 |
430 | .footer .badge-wrapper {
431 | flex-direction: column;
432 | }
433 | }
434 |
435 | /* alertify */
436 | .alertify-notifier .ajs-message {
437 | border-radius: 100px;
438 | text-align: center;
439 | text-shadow: 0 0 10px rgba(255, 255, 255, 1.0);
440 | box-shadow: 0 0 10px 1px rgba(255, 255, 255, 0.3);
441 | }
442 |
443 | .alertify-notifier .ajs-message.ajs-success {
444 | background: rgba(92, 184, 17, 0.9);
445 | }
446 |
447 | .alertify-notifier .ajs-message.ajs-warning {
448 | background: rgba(251, 192, 45, 0.9);
449 | }
450 |
451 | .alertify-notifier .ajs-message.ajs-error {
452 | background: rgba(254, 26, 0, 0.9);
453 | }
454 |
455 | .alertify .ajs-dialog {
456 | border-radius: 20px;
457 | overflow: hidden;
458 | }
459 |
460 | .alertify .ajs-dialog .ajs-header {
461 | font-family: 'Lucida Handwriting';
462 | font-size: large;
463 | }
464 |
465 | .alertify .ajs-dialog .ajs-button {
466 | border-radius: 10px;
467 | background-color: #07C160;
468 | border: none;
469 | cursor: pointer;
470 | box-shadow: 0 0 3px 2px rgba(0, 0, 0, 0.1);
471 | color: white;
472 | transition: 0.3s;
473 | }
474 |
475 | .alertify .ajs-dialog .ajs-button:hover {
476 | opacity: 0.9;
477 | box-shadow: 0 0 3px 2px rgba(0, 0, 0, 0.3);
478 | }
479 |
480 | .coffee {
481 | width: 80%;
482 | margin: auto;
483 | font-family: 'Lucida Handwriting';
484 | }
485 |
486 | .coffee img {
487 | width: 100%;
488 | }
489 |
490 | .notification {
491 | width: 80%;
492 | margin: auto;
493 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
494 | }
495 |
496 | /* Prism */
497 | /* Override default Prism theme */
498 | pre {
499 | box-sizing: border-box !important;
500 | margin: 0 !important;
501 | max-height: var(--panel-max-height);
502 | overflow-x: hidden;
503 | overflow-y: auto;
504 | padding: 8px 10px !important;
505 | min-height: 400px !important;
506 | }
507 |
508 | pre.line-numbers {
509 | padding-left: 50px !important;
510 | }
511 |
512 | pre code {
513 | display: block !important;
514 | box-sizing: border-box !important;
515 | border-radius: var(--panel-border-radius);
516 | font-size: var(--code-font-size) !important;
517 | width: max-content;
518 | min-width: 100% !important;
519 | }
520 |
521 | pre code .token {
522 | font-size: var(--code-font-size);
523 | }
524 |
525 | pre code table {
526 | font-family: inherit;
527 | border-collapse: collapse;
528 | }
529 |
530 | pre code table tr .lineno {
531 | text-align: right;
532 | padding-right: 5px;
533 | --color: #ccc;
534 | border-right: 0.5px solid var(--color);
535 | }
536 |
537 | pre code table tr .line {
538 | padding-left: 5px;
539 | }
540 |
541 | /* on copy overload */
542 | .code.pre-copy>.code-toolbar>pre[class*=language-] {
543 | transition: background 1s;
544 | }
545 |
546 | .code.copy>.code-toolbar>pre[class*=language-] {
547 | background: transparent !important;
548 | }
549 |
550 | .code>.code-toolbar>pre[class*=language-]>code * {
551 | background: transparent !important;
552 | }
553 |
554 | .expand {
555 | display: inline-block;
556 | padding: 5px 15px;
557 | background-color: #bbb;
558 | border-radius: 1000px;
559 | cursor: pointer;
560 | }
561 |
562 | .expand.hidden {
563 | display: none;
564 | }
565 |
566 | .expand i {
567 | margin-left: 5px;
568 | }
569 |
570 | .expand:hover {
571 | background-color: #aaa;
572 | box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1);
573 | transform: scale(1.05);
574 | }
575 |
576 | .expand:active {
577 | background-color: #999;
578 | }
579 |
580 | #previous.hidden {
581 | height: 0;
582 | overflow: hidden;
583 | transition: height 0.5s;
584 | }
--------------------------------------------------------------------------------
/src/css/main.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/css/main.css
--------------------------------------------------------------------------------
/src/css/vendor/barber-shop.css:
--------------------------------------------------------------------------------
1 | .pace {
2 | -webkit-pointer-events: none;
3 | pointer-events: none;
4 |
5 | -webkit-user-select: none;
6 | -moz-user-select: none;
7 | user-select: none;
8 |
9 | overflow: hidden;
10 | position: fixed;
11 | top: 0;
12 | left: 0;
13 | z-index: 2000;
14 | width: 100%;
15 | height: 12px;
16 | background: #fff;
17 | }
18 |
19 | .pace-inactive {
20 | display: none;
21 | }
22 |
23 | .pace .pace-progress {
24 | background-color: #c00000;
25 | position: fixed;
26 | top: 0;
27 | bottom: 0;
28 | right: 100%;
29 | width: 100%;
30 | overflow: hidden;
31 | height: 12px;
32 | }
33 |
34 | .pace .pace-activity {
35 | position: fixed;
36 | top: 0;
37 | right: -32px;
38 | bottom: 0;
39 | left: 0;
40 | height: 12px;
41 |
42 | -webkit-transform: translate3d(0, 0, 0);
43 | -moz-transform: translate3d(0, 0, 0);
44 | -ms-transform: translate3d(0, 0, 0);
45 | -o-transform: translate3d(0, 0, 0);
46 | transform: translate3d(0, 0, 0);
47 |
48 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.2)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.2)), color-stop(0.75, rgba(255, 255, 255, 0.2)), color-stop(0.75, transparent), to(transparent));
49 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
50 | background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
51 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
52 | background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
53 | -webkit-background-size: 32px 32px;
54 | -moz-background-size: 32px 32px;
55 | -o-background-size: 32px 32px;
56 | background-size: 32px 32px;
57 |
58 | -webkit-animation: pace-theme-barber-shop-motion 500ms linear infinite;
59 | -moz-animation: pace-theme-barber-shop-motion 500ms linear infinite;
60 | -ms-animation: pace-theme-barber-shop-motion 500ms linear infinite;
61 | -o-animation: pace-theme-barber-shop-motion 500ms linear infinite;
62 | animation: pace-theme-barber-shop-motion 500ms linear infinite;
63 | }
64 |
65 | @-webkit-keyframes pace-theme-barber-shop-motion {
66 | 0% { -webkit-transform: none; transform: none; }
67 | 100% { -webkit-transform: translate(-32px, 0); transform: translate(-32px, 0); }
68 | }
69 | @-moz-keyframes pace-theme-barber-shop-motion {
70 | 0% { -moz-transform: none; transform: none; }
71 | 100% { -moz-transform: translate(-32px, 0); transform: translate(-32px, 0); }
72 | }
73 | @-o-keyframes pace-theme-barber-shop-motion {
74 | 0% { -o-transform: none; transform: none; }
75 | 100% { -o-transform: translate(-32px, 0); transform: translate(-32px, 0); }
76 | }
77 | @-ms-keyframes pace-theme-barber-shop-motion {
78 | 0% { -ms-transform: none; transform: none; }
79 | 100% { -ms-transform: translate(-32px, 0); transform: translate(-32px, 0); }
80 | }
81 | @keyframes pace-theme-barber-shop-motion {
82 | 0% { transform: none; transform: none; }
83 | 100% { transform: translate(-32px, 0); transform: translate(-32px, 0); }
84 | }
--------------------------------------------------------------------------------
/src/css/vendor/prism.css:
--------------------------------------------------------------------------------
1 | pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}
2 | div.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none}
--------------------------------------------------------------------------------
/src/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/favicon.png
--------------------------------------------------------------------------------
/src/js/.gitignore:
--------------------------------------------------------------------------------
1 | samples.js
2 |
--------------------------------------------------------------------------------
/src/js/code.js:
--------------------------------------------------------------------------------
1 | import CODE_SET from "~/samples.js";
2 |
3 | class CodeSet {
4 | constructor(code) {
5 | this.code = code;
6 | this.count = Object.keys(code).length;
7 | }
8 |
9 | /**
10 | * Get a random language code.
11 | * @param {string} avoid the language to avoid
12 | */
13 | getRandomLanguage(avoid) {
14 | if (avoid === null) {
15 | avoid = "";
16 | }
17 | var lang = this.nextRandomLanguage();
18 | while (lang === avoid) {
19 | lang = this.nextRandomLanguage();
20 | }
21 | return lang;
22 | }
23 |
24 | /**
25 | * Get the code for the given language.
26 | * @param {string} lang the language of the code
27 | * @returns the code, or dummy if language not available
28 | */
29 | getCode(lang) {
30 | if (this.hasLanguage(lang)) {
31 | return this.code[lang];
32 | }
33 | return "Oops, write your own code!";
34 | }
35 |
36 | hasLanguage(lang) {
37 | return Object.prototype.hasOwnProperty.call(this.code, lang);
38 | }
39 |
40 | nextRandomLanguage() {
41 | const target = Math.floor(Math.random() * this.count);
42 | var i = 0;
43 | for (const key of Object.keys(this.code)) {
44 | if (i === target) {
45 | return key;
46 | }
47 | i++;
48 | }
49 | }
50 | };
51 |
52 | const codeset = new CodeSet(CODE_SET);
53 |
54 | export default codeset;
55 |
--------------------------------------------------------------------------------
/src/js/events/actions.js:
--------------------------------------------------------------------------------
1 | import $ from "~/vendor/jquery-extensions";
2 | import alertify from "~/vendor/alertify-extension";
3 | import { toggleHelp, closeHelp } from "~/events/help";
4 | import paste from "~/paste";
5 | import codeset from "~/code";
6 |
7 | var issueLock = false;
8 |
9 | function registerActions() {
10 | $("div.action").each(function () {
11 | $(this).on("animationend", () => {
12 | $(this).removeClassRegex("animate__*");
13 | });
14 | });
15 |
16 | var convertButton = $("#convert");
17 | convertButton.on("click", () => {
18 | convertButton.addClass("animate__animated animate__spin");
19 |
20 | updateLanguage(true);
21 | paste.dispatch("make");
22 | closeHelp();
23 | toggleHelp();
24 | });
25 |
26 | var eraseButton = $("#erase");
27 | eraseButton.on("click", () => {
28 | eraseButton.addClass("animate__animated animate__shake");
29 | paste.dispatch("erase");
30 | toggleHelp();
31 | });
32 |
33 | var copyButton = $("#copy");
34 | copyButton.on("click", () => {
35 | copyButton.addClass("animate__animated animate__grow");
36 | paste.dispatch("copy");
37 | });
38 |
39 | var randomButton = $("#random");
40 | randomButton.on("click", () => {
41 | randomButton.addClass("animate__animated animate__rubber");
42 | makeRandomPaste(null);
43 | });
44 |
45 | var issueButton = $("#issue");
46 | issueButton.on("click", () => {
47 | issueButton.addClass("animate__animated animate__tada");
48 |
49 | if (issueLock) {
50 | alertify.error("Issue page is already opening... ⌛");
51 | return;
52 | }
53 | issueLock = true;
54 |
55 | var duration = 3;
56 | var notification = alertify.success(`Opening issue page in ${duration}... 📝`, duration, function () { clearInterval(interval); });
57 | var interval = setInterval(function () {
58 | notification.setContent(`Opening issue page in ${--duration}... 📝`);
59 | }, 1000);
60 |
61 | setTimeout(() => {
62 | window.open("https://github.com/Lord-Turmoil/CodePaste/issues/new", "_blank");
63 | issueLock = false;
64 | }, duration * 1000);
65 | });
66 |
67 | $("#logo").on("click", () => {
68 | promptNotification();
69 | });
70 |
71 | registerSupport();
72 | }
73 |
74 | function updateLanguage(persist) {
75 | const optionSelected = $("#lang").find("option:selected");
76 | updateActiveLanguage(optionSelected.val(), persist);
77 | updateLanguageTip(optionSelected.text());
78 | }
79 |
80 | function updateActiveLanguage(lang, persist) {
81 | $("#code").removeClass().addClass("language-" + lang);
82 | if (persist) {
83 | localStorage.setItem("language", lang);
84 | }
85 | }
86 |
87 | function updateLanguageTip(lang) {
88 | var tip = $("div.toolbar-item span");
89 | if (tip.length) {
90 | tip.text(lang);
91 | }
92 | }
93 |
94 | function registerSupport() {
95 | var supportButton = $("#coffee");
96 | var support = $("#support");
97 | if (support.children().length !== 1) {
98 | supportButton.remove();
99 | return;
100 | }
101 | const html = support.html();
102 | supportButton.on("click", () => {
103 | supportButton.addClass("animate__animated animate__grow");
104 | alertify.alert("Buy me a coffee 🍵", html);
105 | });
106 | }
107 |
108 | function makeRandomPaste(lang) {
109 | if (lang === null) {
110 | const optionSelected = $("#lang").find("option:selected");
111 | const current = optionSelected.val();
112 | lang = codeset.getRandomLanguage(current);
113 | }
114 | paste.setInput(codeset.getCode(lang));
115 |
116 | $("option[value=\"" + lang + "\"]").prop("selected", true);
117 | updateLanguage(false);
118 |
119 | paste.dispatch("random");
120 | closeHelp();
121 | toggleHelp();
122 | }
123 |
124 | function promptNotification() {
125 | const agreement = $("#notification");
126 | if (agreement.children().length === 1) {
127 | const html = agreement.html();
128 | alertify.alert("Notification 🔔", html);
129 | }
130 | }
131 |
132 | export { registerActions, makeRandomPaste, promptNotification };
133 |
--------------------------------------------------------------------------------
/src/js/events/help.js:
--------------------------------------------------------------------------------
1 | import $ from "~/vendor/jquery-extensions";
2 | import paste from "~/paste";
3 |
4 | var help = $("#help");
5 | var isHelpOn = false; // used in help
6 | help.click(function () {
7 | help.toggleClass("active");
8 | isHelpOn = !isHelpOn;
9 | toggleHelp();
10 | });
11 |
12 | var cover = $("div.cover");
13 | var showHelp = true;
14 | var interval = null;
15 | function toggleHelp() {
16 | var show = (paste.isEmpty() || isHelpOn);
17 | if (show === showHelp) {
18 | return;
19 | }
20 |
21 | showHelp = show;
22 | if (interval !== null) {
23 | clearInterval(interval);
24 | interval = null;
25 | }
26 | cover.removeClassRegex("animate__*");
27 | if (showHelp) {
28 | cover.addClass("animate__animated animate__fadeIn");
29 | cover.show();
30 | } else {
31 | cover.addClass("animate__animated animate__fadeOut");
32 | interval = setTimeout(function () {
33 | cover.hide();
34 | }, 500);
35 | }
36 | }
37 |
38 | // Close help if it is on when paste is made.
39 | function closeHelp() {
40 | if (isHelpOn) {
41 | help.click();
42 | }
43 | }
44 |
45 | export { toggleHelp, closeHelp };
--------------------------------------------------------------------------------
/src/js/events/listeners.js:
--------------------------------------------------------------------------------
1 | import $ from "~/vendor/jquery-extensions";
2 |
3 | // auto-fit text area
4 | // Reference: https://stackoverflow.com/questions/454202/creating-a-textarea-with-auto-resize
5 | const MIN_HEIGHT = 400;
6 | const MAX_HEIGHT = 600;
7 |
8 | function registerOnTextAreaChange() {
9 | $("textarea").each(function () {
10 | this.setAttribute("style", "height:" + (MIN_HEIGHT) + "px;");
11 | }).on("input", function () {
12 | this.style.height = "auto";
13 | var targetHeight = this.scrollHeight;
14 | if (targetHeight > MAX_HEIGHT) {
15 | $(this).addClass("full");
16 | targetHeight = MAX_HEIGHT;
17 | } else {
18 | $(this).removeClass("full");
19 | if (targetHeight < MIN_HEIGHT) {
20 | targetHeight = MIN_HEIGHT;
21 | }
22 | }
23 | this.style.height = (targetHeight) + "px";
24 | });
25 | }
26 |
27 | function prepareIndentation(textarea) {
28 | const start = textarea.selectionStart;
29 | const end = textarea.selectionEnd;
30 | const lines = textarea.value.split("\n");
31 |
32 | let affectedLines = [];
33 | let count = 0;
34 |
35 | for (let i = 0; i < lines.length; i++) {
36 | const lstart = count;
37 | const lend = count + lines[i].length + 1;
38 | if (lstart <= end && lend > start) {
39 | affectedLines.unshift({ line: i, start: lstart, end: lend });
40 | }
41 | count = lend;
42 | }
43 |
44 | return { start: start, end: end, affectedLines: affectedLines };
45 | }
46 |
47 | function registerEditListeners() {
48 | $("textarea").on("keydown", function (e) {
49 | if (e.key == "Tab") {
50 | e.preventDefault();
51 | $(this).trigger(e.shiftKey ? "unindent" : "indent", [prepareIndentation(this)]);
52 | }
53 | }).on("indent", function (event, data) {
54 | if (data.start == data.end) {
55 | document.execCommand("insertText", false, " ");
56 | this.setSelectionRange(data.start + 4, data.start + 4);
57 | return;
58 | }
59 |
60 | for (let i = 0; i < data.affectedLines.length; i++) {
61 | const line = data.affectedLines[i];
62 | this.setSelectionRange(line.start, line.start);
63 | document.execCommand("insertText", false, " ");
64 | }
65 | this.setSelectionRange(data.start + 4, data.end + 4 * data.affectedLines.length);
66 | }).on("unindent", function (event, data) {
67 | let newStart = data.start;
68 | let newEnd = data.end;
69 |
70 | for (let i = 0; i < data.affectedLines.length; i++) {
71 | const line = data.affectedLines[i];
72 | const start = line.start;
73 | let end = start;
74 | while (((end < line.end) && (end - start < 4)) && (this.value[end] == " ")) {
75 | end++;
76 | }
77 |
78 | if (i == data.affectedLines.length - 1) {
79 | newStart -= end - start;
80 | newStart = Math.max(newStart, line.start);
81 | }
82 | newEnd -= end - start;
83 | console.log(newStart, newEnd, line.start, end - start);
84 |
85 | if (end > start) {
86 | this.setSelectionRange(start, end);
87 | document.execCommand("delete");
88 | }
89 | }
90 | this.setSelectionRange(newStart, Math.max(newStart, newEnd));
91 | }).on("paste", function (e) {
92 | e.preventDefault();
93 | // This is a bug when copying from PowerPoint, where '\n' is
94 | // replaced with '\v' (vertical tab) and ' ' is replaced with '\xa0' (non-breaking space)
95 | const text = e.originalEvent.clipboardData.getData("text")
96 | .replaceAll(String.fromCharCode(11), "\n")
97 | .replaceAll(String.fromCharCode(160), " ");
98 | document.execCommand("insertText", false, text);
99 | });
100 | }
101 |
102 | function registerListeners() {
103 | registerOnTextAreaChange();
104 | registerEditListeners();
105 | }
106 |
107 | export { registerListeners };
--------------------------------------------------------------------------------
/src/js/events/options.js:
--------------------------------------------------------------------------------
1 | import $ from "~/vendor/jquery-extensions";
2 | import paste from "~/paste";
3 | import { closeHelp, toggleHelp } from "~/events/help";
4 | import { setTheme } from "~/vendor/prism-extension";
5 |
6 | var isDark = false;
7 |
8 | function registerOptions() {
9 | $("#cb3-8").on("change", function () {
10 | updateLineNumber(this.checked);
11 | paste.dispatch("refresh");
12 | closeHelp();
13 | toggleHelp();
14 | });
15 |
16 | $("#theme-selector").on("change", function () {
17 | setTheme(this.value);
18 | });
19 |
20 | var mode = $("#mode");
21 | mode.on("click", function () {
22 | setMode(!isDark);
23 | });
24 | }
25 |
26 | function updateLineNumber(enable) {
27 | if (enable) {
28 | $("#pre").addClass("line-numbers");
29 | $("#cb3-8").get(0).checked = true;
30 | } else {
31 | $("#pre").removeClass("line-numbers");
32 | }
33 | paste.enableLineNumber(enable);
34 | localStorage.setItem("line-number", enable);
35 | }
36 |
37 | function setMode(dark) {
38 | isDark = dark;
39 | if (isDark) {
40 | $("#mode").addClass("active");
41 | } else {
42 | $("#mode").removeClass("active");
43 | }
44 | applyMode();
45 | }
46 |
47 | function applyMode() {
48 | if (isDark) {
49 | $("#mode-css").attr("href", "css/dark.css");
50 | localStorage.setItem("mode", "dark");
51 | } else {
52 | $("#mode-css").attr("href", "");
53 | localStorage.setItem("mode", "light");
54 | }
55 | }
56 |
57 | export { registerOptions, updateLineNumber, setMode };
58 |
--------------------------------------------------------------------------------
/src/js/main.js:
--------------------------------------------------------------------------------
1 | import { registerListeners } from "~/events/listeners";
2 | import { registerActions } from "~/events/actions";
3 | import { registerOptions } from "~/events/options";
4 | import { loadVersion } from "~/version";
5 | import { restoreUserPreferences } from "~/state";
6 | import $ from "~/vendor/jquery-extensions";
7 |
8 | registerListeners();
9 | registerActions();
10 | registerOptions();
11 | loadVersion();
12 |
13 | restoreUserPreferences();
14 |
15 | const currentYear = new Date().getFullYear();
16 | $("#year").text((currentYear > 2023) ? "2023 - " + currentYear : 2023);
17 |
--------------------------------------------------------------------------------
/src/js/paste.js:
--------------------------------------------------------------------------------
1 | import Prism from "prismjs";
2 | import $ from "~/vendor/jquery-extensions";
3 | import alertify from "~/vendor/alertify-extension";
4 | import { normalizeString, copyHTMLElement } from "~/utils";
5 |
6 | Prism.manual = true;
7 |
8 | function copyPasteImpl(element, enableLineNumber) {
9 | const backupElem = element.innerHTML;
10 |
11 | var target = element;
12 | if (enableLineNumber) {
13 | target = transformPaste(element);
14 | }
15 | if (!copyHTMLElement(target)) {
16 | element.innerHTML = backupElem;
17 | return false;
18 | }
19 | element.innerHTML = backupElem;
20 |
21 | return true;
22 | }
23 |
24 | // Transform paste into table.
25 | function transformPaste(element) {
26 | var content = element.innerHTML;
27 | // Remove last element.
28 | var pos = content.lastIndexOf("");
29 | content = content.substring(0, pos);
30 |
31 | // Split content by
32 | var lines = content.split(" ");
33 | var table = "";
34 | for (var i = 0; i < lines.length; i++) {
35 | table += "" + (i + 1) + " " + lines[i] + " ";
36 | }
37 | table += "
";
38 |
39 | // Get dynamic styles.
40 | var height = window.getComputedStyle($("code[class*=language-] .line-numbers-rows span").get(0), null).getPropertyValue("height");
41 | var fontStyle = window.getComputedStyle($("code[class*=language-], pre[class*=language-]").get(0), null).getPropertyValue("font-family");
42 | var tableElement = element.cloneNode(false);
43 | tableElement.innerHTML = table;
44 | element.innerHTML = table;
45 |
46 | $("pre code table tr td").css("font-family", fontStyle);
47 | $("pre code table tr").css("height", height);
48 |
49 | return element;
50 | }
51 |
52 | async function overloadStyle() {
53 | $(".code").addClass("pre-copy");
54 | $(".code").addClass("copy");
55 | await new Promise(r => setTimeout(r, 256));
56 | }
57 |
58 | function restoreStyle() {
59 | $(".code").removeClass("copy");
60 | $(".code").removeClass("pre-copy");
61 | }
62 |
63 | class Paste {
64 | constructor(input, output) {
65 | this.map = {
66 | "make": this.make.bind(this),
67 | "copy": this.copy.bind(this),
68 | "erase": this.erase.bind(this),
69 | "random": this.random.bind(this),
70 | "refresh": this.refresh.bind(this),
71 | };
72 | this.inputSelector = input;
73 | this.outputSelector = output;
74 | this.withLineNumber = false;
75 | this.update();
76 | }
77 |
78 | update() {
79 | this.input = $(this.inputSelector);
80 | this.output = $(this.outputSelector);
81 | }
82 |
83 | hasInput() {
84 | return this.input.val() !== "";
85 | }
86 |
87 | /**
88 | * We have to expose this to let outside world set the random language.
89 | * @returns the input object
90 | */
91 | setInput(text) {
92 | this.input.val(text);
93 | this.input.get(0).dispatchEvent(new Event("input"));
94 | }
95 |
96 | isEmpty() {
97 | return (this.output.get(0).textContent.trim() === "") && (this.output.get(0).childElementCount === 0);
98 | }
99 |
100 | hasOutput() {
101 | return !this.isEmpty();
102 | }
103 |
104 | enableLineNumber(enabled) {
105 | this.withLineNumber = enabled;
106 | }
107 |
108 | /**
109 | * Dispatch command to the paste engine.
110 | * @param {string} type action type for the reducer
111 | * make
112 | * copy
113 | * erase
114 | * random
115 | */
116 | async dispatch(type) {
117 | this.map[type]();
118 | }
119 |
120 | async make() {
121 | if (this.hasInput()) {
122 | this.highlight();
123 | alertify.success("Code paste ready to go 😋");
124 | } else {
125 | alertify.warning("The ingredient, please 🤧");
126 | }
127 | return Promise.resolve();
128 | }
129 |
130 | async copy() {
131 | if (this.isEmpty()) {
132 | alertify.warning("Make your code paste first 😨");
133 | } else {
134 | await overloadStyle();
135 | if (copyPasteImpl(this.output.get(0), this.withLineNumber)) {
136 | alertify.success("Code paste copied to clipboard 🤩");
137 | } else {
138 | alertify.error("Oops! Something went wrong 🤯");
139 | }
140 | restoreStyle();
141 | }
142 | return Promise.resolve();
143 | }
144 |
145 | async erase() {
146 | this.input.val("");
147 | this.input.get(0).dispatchEvent(new Event("input"));
148 |
149 | if (this.isEmpty()) {
150 | alertify.warning("You haven't made any paste yet 😅");
151 | }
152 | else {
153 | this.highlight();
154 | alertify.success("Code paste cleared 🥹");
155 | if (this.hasOutput()) {
156 | alertify.error("The paste is too good to be erased 😅");
157 | }
158 | }
159 |
160 | return Promise.resolve();
161 | }
162 |
163 | /**
164 | * Same as make, but different success message.
165 | */
166 | async random() {
167 | if (this.hasInput()) {
168 | this.highlight();
169 | alertify.success("You like the random paste? 🙃");
170 | } else {
171 | alertify.error("The ingredient, please 🫨");
172 | }
173 | return Promise.resolve();
174 | }
175 |
176 | /**
177 | * Just refresh the output with no message.
178 | */
179 | async refresh() {
180 | this.highlight();
181 | return Promise.resolve();
182 | }
183 |
184 | highlight() {
185 | // FIXME: Currently will ignore the whitespace at the beginning.
186 | this.output.html("");
187 | this.output.text(this.input.val().trim());
188 | Prism.highlightAll();
189 | var corrected = this.output.html().toString().replaceAll("\n", " ");
190 | this.output.html(normalizeString(corrected));
191 | this.update();
192 | }
193 | }
194 |
195 | // Because Prism will insert parent element for the code block, we have to
196 | // re-select the input and output element.
197 | const paste = new Paste("#source", "pre>code");
198 |
199 | export default paste;
200 |
--------------------------------------------------------------------------------
/src/js/state.js:
--------------------------------------------------------------------------------
1 | import { makeRandomPaste, promptNotification } from "~/events/actions";
2 | import { setMode, updateLineNumber } from "~/events/options";
3 | import { getCookie, setCookie } from "./vendor/cookie-extension";
4 | import { setTheme } from "~/vendor/prism-extension";
5 |
6 | function restoreUserPreferences() {
7 | restoreColorMode();
8 | restoreLanguage();
9 | restoreLineNumber();
10 | restoreTheme();
11 | restoreNotification();
12 | }
13 |
14 | function restoreLanguage() {
15 | const lang = localStorage.getItem("language");
16 | if (lang) {
17 | setTimeout(function () {
18 | makeRandomPaste(lang);
19 | }, 1000);
20 | } else {
21 | setTimeout(function () {
22 | makeRandomPaste(null);
23 | }, 1000);
24 | }
25 | }
26 |
27 | function restoreLineNumber() {
28 | const enableLineNumber = localStorage.getItem("line-number");
29 | if (enableLineNumber !== null) {
30 | updateLineNumber(enableLineNumber === "true");
31 | }
32 | }
33 |
34 | function restoreColorMode() {
35 | const mode = localStorage.getItem("mode");
36 | if (mode !== null) {
37 | const isDark = localStorage.getItem("mode") === "dark";
38 | setMode(isDark);
39 | }
40 | }
41 |
42 | function restoreTheme() {
43 | const theme = localStorage.getItem("theme");
44 | if (theme !== null) {
45 | setTheme(theme);
46 | }
47 | }
48 |
49 | function restoreNotification() {
50 | const cookie = getCookie("notification");
51 | if (cookie !== "") {
52 | return;
53 | }
54 | setCookie("notification", "notified", 24 * 7); // one week
55 |
56 | promptNotification();
57 | }
58 |
59 | export { restoreUserPreferences };
60 |
--------------------------------------------------------------------------------
/src/js/utils.js:
--------------------------------------------------------------------------------
1 | // replace spaces with in string form html while skipping tags
2 | // here we assume that the string is legal
3 | function normalizeString(str) {
4 | var res = "";
5 | var length = str.length;
6 | var cnt = 0;
7 |
8 | for (var i = 0; i < length; i++) {
9 | if (str[i] === " ") {
10 | res += (cnt === 0) ? " " : " ";
11 | } else {
12 | res += str[i];
13 | if (str[i] === "<") {
14 | cnt++;
15 | } else if (str[i] === ">") {
16 | cnt--;
17 | }
18 | }
19 | }
20 |
21 | return res;
22 | }
23 |
24 | // copy html element while preserving the format and style
25 | // Reference: https://htmldom.dev/copy-highlighted-code-to-the-clipboard/
26 | function copyHTMLElement(elem) {
27 | // Create new selection
28 | const selection = window.getSelection();
29 |
30 | // Save the current selection
31 | const currentRange = (selection.rangeCount === 0) ? null : selection.getRangeAt(0);
32 |
33 | // Select the text content of code element
34 | const range = document.createRange();
35 | range.selectNodeContents(elem);
36 | selection.removeAllRanges();
37 | selection.addRange(range);
38 |
39 | // Copy to the clipboard
40 | var hasError = false;
41 | try {
42 | document.execCommand("copy");
43 | } catch (err) {
44 | // Unable to copy
45 | console.log(err);
46 | hasError = true;
47 | } finally {
48 | // Restore the previous selection
49 | selection.removeAllRanges();
50 | currentRange && selection.addRange(currentRange);
51 | }
52 |
53 | return !hasError;
54 | };
55 |
56 | export { normalizeString, copyHTMLElement };
57 |
--------------------------------------------------------------------------------
/src/js/vendor/alertify-extension.js:
--------------------------------------------------------------------------------
1 | import alertify from "alertifyjs";
2 |
3 | alertify.set("notifier", "delay", 1.5);
4 | alertify.set("notifier", "position", "bottom-left");
5 |
6 | export default alertify;
--------------------------------------------------------------------------------
/src/js/vendor/cookie-extension.js:
--------------------------------------------------------------------------------
1 | // Reference: https://www.w3schools.com/js/js_cookies.asp
2 |
3 | /**
4 | * Set a cookie.
5 | * @param {string} name name of the cookie
6 | * @param {string} value value of the cookie
7 | * @param {number} hours hours to expire
8 | */
9 | function setCookie(name, value, hours) {
10 | const expireDate = new Date();
11 | expireDate.setTime(expireDate.getTime() + (hours * 60 * 60 * 1000));
12 | let expires = "expires=" + expireDate.toUTCString();
13 | document.cookie = name + "=" + value + ";" + expires + ";path=/";
14 | }
15 |
16 | function getCookie(name) {
17 | name = name + "=";
18 | let decodedCookie = decodeURIComponent(document.cookie);
19 | let ca = decodedCookie.split(";");
20 | for (let i = 0; i < ca.length; i++) {
21 | let c = ca[i];
22 | while (c.charAt(0) == " ") {
23 | c = c.substring(1);
24 | }
25 | if (c.indexOf(name) == 0) {
26 | return c.substring(name.length, c.length);
27 | }
28 | }
29 | return "";
30 | }
31 |
32 | export { setCookie, getCookie };
33 |
--------------------------------------------------------------------------------
/src/js/vendor/jquery-extensions.js:
--------------------------------------------------------------------------------
1 | import $ from "jquery";
2 |
3 | $.fn.removeClassRegex = function (pattern) {
4 | var element = $(this);
5 | var classNames = element.attr("class").split(" ");
6 | $(classNames).each(function (key, value) {
7 | if (value.match(pattern)) {
8 | element.removeClass(value);
9 | }
10 | });
11 | };
12 |
13 | export default $;
--------------------------------------------------------------------------------
/src/js/vendor/prism-extension.js:
--------------------------------------------------------------------------------
1 | import $ from "~/vendor/jquery-extensions";
2 |
3 | const themes = {
4 | "https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/themes/{id}.min.css": [
5 | "prism",
6 | "prism-dark",
7 | "prism-funky",
8 | "prism-okaidia",
9 | "prism-twilight",
10 | "prism-solarizedlight",
11 | "prism-tomorrow"
12 | ],
13 | "https://cdnjs.cloudflare.com/ajax/libs/prism-themes/1.9.0/prism-{id}.min.css": [
14 | "a11y-dark",
15 | "atom-dark",
16 | "base16-ateliersulphurpool.light",
17 | "cb",
18 | "coldark-cold",
19 | "coldark-dark",
20 | "coy-without-shadows",
21 | "darcula",
22 | "dracula",
23 | "duotone-dark",
24 | "duotone-earth",
25 | "duotone-forest",
26 | "duotone-light",
27 | "duotone-sea",
28 | "duotone-space",
29 | "ghcolors",
30 | "gruvbox-dark",
31 | "gruvbox-light",
32 | "holi-theme",
33 | "hopscotch",
34 | "lucario",
35 | "material-dark",
36 | "material-light",
37 | "material-oceanic",
38 | "night-owl",
39 | "nord",
40 | "one-dark",
41 | "one-light",
42 | "pojoaque",
43 | "shades-of-purple",
44 | "solarized-dark-atom",
45 | "synthwave84",
46 | "vs",
47 | "vsc-dark-plus",
48 | "xonokai",
49 | "z-touch"
50 | ]
51 | };
52 |
53 |
54 | //url for id from dictionary
55 | function getThemeUrl(id) {
56 | for (const [key, value] of Object.entries(themes)) {
57 | if (value.includes(id)) return key;
58 | }
59 | return null;
60 | }
61 |
62 | function setTheme(id) {
63 | let url = getThemeUrl(id);
64 | if (url == null) {
65 | console.error("Theme not found: " + id);
66 | return null;
67 | }
68 | if ($("#theme-selector").val() !== id) {
69 | $("#theme-selector").val(id);
70 | }
71 |
72 | let theme_url = url.replace(/\{id}/g, id);
73 | $("#theme").attr("href", theme_url);
74 |
75 | localStorage.setItem("theme", id);
76 | };
77 |
78 | export { setTheme };
79 |
--------------------------------------------------------------------------------
/src/js/version.js:
--------------------------------------------------------------------------------
1 | import alertify from "~/vendor/alertify-extension";
2 | import $ from "~/vendor/jquery-extensions";
3 |
4 | function render(versions) {
5 | var options = { year: "numeric", month: "long", day: "numeric" };
6 | var latest = "";
7 | var previous = "";
8 | versions.forEach((version, index) => {
9 | var html = "";
10 | html += '';
11 | html += "
Version " + version.version + " ";
12 | html += '
';
13 | html += "
" + new Date(version.date).toLocaleDateString("en-US", options) + "
";
14 | html += "
";
15 | html += "
";
16 | html += '';
17 | version.entries.forEach((entry) => {
18 | html += "
" + entry.title + " ";
19 | html += '
';
20 | entry.items.forEach((item) => {
21 | html += "
" + item + "
";
22 | });
23 | html += "
";
24 | });
25 | html += "
";
26 | if (index == 0) {
27 | latest = html;
28 | } else {
29 | previous += html;
30 | }
31 | });
32 | $("#latest").html(latest);
33 | $("#previous").html(previous);
34 | }
35 |
36 | const expandMore = $("#expand-more");
37 | const expandLess = $("#expand-less");
38 | const previous = $("#previous");
39 |
40 | function expand() {
41 | previous.removeClass("hidden");
42 | previous.height(previous[0].scrollHeight);
43 | expandMore.addClass("hidden");
44 | expandLess.removeClass("hidden");
45 | setTimeout(() => {
46 | $("#more-anchor").get(0).scrollIntoView({ behavior: "smooth" });
47 | }, 150);
48 | }
49 |
50 | function collapse() {
51 | previous.addClass("hidden");
52 | previous.height(0);
53 | expandMore.removeClass("hidden");
54 | expandLess.addClass("hidden");
55 | setTimeout(() => {
56 | $("#less-anchor").get(0).scrollIntoView({ behavior: "smooth" });
57 | }, 150);
58 | }
59 |
60 | function loadVersion() {
61 | fetch("./version.json")
62 | .then((res) => {
63 | if (!res.ok) {
64 | throw new Error("Cannot find \"data.json\".");
65 | }
66 | return res.json();
67 | })
68 | .then((data) => render(data))
69 | .catch((error) => {
70 | console.log(error);
71 | alertify.error("Failed to load version data 😰");
72 | });
73 |
74 | expandMore.on("click", expand);
75 | expandLess.on("click", collapse);
76 | }
77 |
78 | export { loadVersion };
79 |
--------------------------------------------------------------------------------
/src/res/fonts/Consolas.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/res/fonts/Consolas.eot
--------------------------------------------------------------------------------
/src/res/fonts/Consolas.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/res/fonts/Consolas.woff
--------------------------------------------------------------------------------
/src/res/fonts/Consolas.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/res/fonts/Consolas.woff2
--------------------------------------------------------------------------------
/src/res/fonts/LucidaHandwriting-Italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/res/fonts/LucidaHandwriting-Italic.eot
--------------------------------------------------------------------------------
/src/res/fonts/LucidaHandwriting-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/res/fonts/LucidaHandwriting-Italic.woff
--------------------------------------------------------------------------------
/src/res/fonts/LucidaHandwriting-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/res/fonts/LucidaHandwriting-Italic.woff2
--------------------------------------------------------------------------------
/src/res/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lord-Turmoil/CodePaste/7ea55da35e3c73b3bd1b348aba5ca95379d564db/src/res/logo.png
--------------------------------------------------------------------------------
/src/version.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "version": "3.1.1",
4 | "date": "2025.1.18",
5 | "entries": [
6 | {
7 | "title": "Changes",
8 | "items": [
9 | "Add support for more languages",
10 | "Use Tab or Shift + Tab to indent or unindent",
11 | "Minor adjustments to the layout"
12 | ]
13 | },
14 | {
15 | "title": "Fixes",
16 | "items": [
17 | "Tab key will no longer clear input history",
18 | "Compatibility issue with Microsoft PowerPoint"
19 | ]
20 | }
21 | ]
22 | },
23 | {
24 | "version": "3.1.0",
25 | "date": "2024.10.3",
26 | "entries": [
27 | {
28 | "title": "Refactor",
29 | "items": [
30 | "Refactored project with npm package"
31 | ]
32 | },
33 | {
34 | "title": "Changes",
35 | "items": [
36 | "Minor updates to the style"
37 | ]
38 | },
39 | {
40 | "title": "Fixes",
41 | "items": [
42 | "Fixed the bug that input box cannot auto-shrink"
43 | ]
44 | }
45 | ]
46 | },
47 | {
48 | "version": "3.0.1",
49 | "date": "2024.7.25",
50 | "entries": [
51 | {
52 | "title": "Changes",
53 | "items": [
54 | "Introduced native dark mode",
55 | "Improved animation effects",
56 | "Disabled spell check and completion for input box",
57 | "Copy code with line numbers (Experimental)"
58 | ]
59 | },
60 | {
61 | "title": "Fixes",
62 | "items": [
63 | "Removed the annoying text shadow"
64 | ]
65 | },
66 | {
67 | "title": "Notice",
68 | "items": [
69 | "You may need to manually adjust font and column width after pasting"
70 | ]
71 | }
72 | ]
73 | },
74 | {
75 | "version": "2.2.3",
76 | "date": "2023.12.31",
77 | "entries": [
78 | {
79 | "title": "Changes",
80 | "items": [
81 | "Can use Tab key to indent 4 spaces",
82 | "Can remember history language and theme",
83 | "Add prompt for the use of Microsoft Clarity"
84 | ]
85 | },
86 | {
87 | "title": "Fixes",
88 | "items": [
89 | "Bad URL links"
90 | ]
91 | }
92 | ]
93 | },
94 | {
95 | "version": "2.0.3",
96 | "date": "2023.10.6",
97 | "entries": [
98 | {
99 | "title": "Changes",
100 | "items": [
101 | "More highlight color schemes!",
102 | "Provide random code sample",
103 | "Add language hint in the code block",
104 | "Better animation effects",
105 | "Remove line number option"
106 | ]
107 | },
108 | {
109 | "title": "Fixes",
110 | "items": [
111 | "Some visual glitches"
112 | ]
113 | },
114 | {
115 | "title": "Bug",
116 | "items": [
117 | "Layout may still have bug for certain browsers"
118 | ]
119 | }
120 | ]
121 | },
122 | {
123 | "version": "1.2.x",
124 | "date": "2023.10.4",
125 | "entries": [
126 | {
127 | "title": "Changes",
128 | "items": [
129 | "Support for one-click copy",
130 | "Add beautiful alertify dialogs",
131 | "Adapt to new Edge UI",
132 | "Fix typo",
133 | "Reorder action buttons"
134 | ]
135 | }
136 | ]
137 | },
138 | {
139 | "version": "1.1.x",
140 | "date": "2023.6.26",
141 | "entries": [
142 | {
143 | "title": "General",
144 | "items": [
145 | "First stable version",
146 | "Primary features realized"
147 | ]
148 | },
149 | {
150 | "title": "Fixes",
151 | "items": [
152 | "Fix potential format error",
153 | "Fix compatibility with Microsoft PowerPoint"
154 | ]
155 | }
156 | ]
157 | }
158 | ]
--------------------------------------------------------------------------------
/src/views/components/.gitignore:
--------------------------------------------------------------------------------
1 | notification.html
2 | statistics.html
3 | support.html
4 | languages.html
5 |
--------------------------------------------------------------------------------
/src/views/components/head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/views/components/meta.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Code Paste | Syntax Highlight for Office
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/views/parts/banner.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Welcome to Tony's Code Paste!
4 |
5 |
--------------------------------------------------------------------------------
/src/views/parts/docs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Why Code Paste?
4 |
5 |
6 |
7 |
8 | Adding code snippets to Office documents like Word or PowerPoint could be a challenge,
9 | especially when you want to preserve the syntax highlighting. 😢 Furthermore, the typical dark
10 | themes of most IDEs doesn't work well for presentations. While converting code into images is an
11 | option, it often suffers from non-transparent background, and apparently not as flexible or
12 | crystal clear as text. 😖
13 |
14 |
15 | So, is there a better way to embed highlighted code snippets in these documents? 🤔
16 | Absolutely, and that's where Code Paste comes in! 😆 Simply paste your code into the left
17 | panel, choose your preferred language and color scheme. With a few clicks, you'll have a
18 | beautifully highlighted code snippet ready to go. 😋
19 |
20 |
21 | Can't find the language you need? 🫨 Well, don't be shy! Open an
22 | issue
23 | and I will add it for you! 😘
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
Show more
33 |
Show less
34 |
--------------------------------------------------------------------------------
/src/views/parts/footer.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/parts/header.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/parts/panel.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
Step 1 Select the language of your code 🧐
31 |
Step 2 Paste your code to the input panel 🤨
32 |
Step 3 Click the circle with arrow to make yummy code paste 😋
33 |
Step 4 Change the color scheme to meet your taste 😆
34 |
Step 5 Click the clipboard-like button to copy the code 😁
35 |
Step 6 Paste the code to your document and be professional! 😍
36 |
37 |
40 |
41 |
--------------------------------------------------------------------------------
/src/views/parts/toolbar.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | module.exports = {
3 | entry: './src/js/main.js',
4 | output: {
5 | path: __dirname + '/dist',
6 | filename: 'bundle.js'
7 | },
8 | module: {
9 | rules: [
10 | {
11 | test: /\.m?js$/,
12 | exclude: /node_modules/,
13 | use: {
14 | loader: 'babel-loader',
15 | options: {
16 | presets: ['@babel/preset-env']
17 | }
18 | }
19 | },
20 | {
21 | test: /\.css$/,
22 | use: ['css-loader']
23 | }
24 | ]
25 | }
26 | };
--------------------------------------------------------------------------------