ots-animate 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/404.html ADDED
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Redirecting...</title>
7
+ <script>
8
+ (function () {
9
+ var target = "/#" + window.location.pathname + window.location.search;
10
+ window.location.replace(target);
11
+ })();
12
+ </script>
13
+ </head>
14
+ <body></body>
15
+ </html>
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dharmesh
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.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # oat-animate
package/build.mjs ADDED
@@ -0,0 +1,97 @@
1
+ import { readFileSync, writeFileSync, statSync, createReadStream, createWriteStream } from 'fs';
2
+ import { createGzip } from 'zlib';
3
+ import { pipeline } from 'stream/promises';
4
+ import { promisify } from 'util';
5
+ import fs from 'fs';
6
+
7
+ // Simple CSS minifier
8
+ function minifyCSS(css) {
9
+ return css
10
+ .replace(/\/\*[\s\S]*?\*\//g, '') // Remove comments
11
+ .replace(/\s+/g, ' ') // Collapse whitespace
12
+ .replace(/\s*([{}:;,])\s*/g, '$1') // Remove spaces around delimiters
13
+ .replace(/;\s}/g, '}') // Remove trailing semicolons
14
+ .trim();
15
+ }
16
+
17
+ // Simple JS minifier
18
+ function minifyJS(js) {
19
+ return js
20
+ .replace(/\/\/.*$/gm, '') // Remove single-line comments
21
+ .replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
22
+ .replace(/\s+/g, ' ') // Collapse whitespace
23
+ .replace(/\s*([{}()=+\-*/<>!&|,;:])\s*/g, '$1') // Remove spaces around operators
24
+ .trim();
25
+ }
26
+
27
+ // Gzip file
28
+ async function gzipFile(inputPath, outputPath) {
29
+ const gzip = createGzip({ level: 9 });
30
+ const source = createReadStream(inputPath);
31
+ const destination = createWriteStream(outputPath);
32
+ await pipeline(source, gzip, destination);
33
+ }
34
+
35
+ // Get file size
36
+ function getFileSize(filePath) {
37
+ const stats = statSync(filePath);
38
+ return stats.size;
39
+ }
40
+
41
+ async function build() {
42
+ console.log('🚀 Starting build process...\n');
43
+
44
+ // File paths
45
+ const cssInput = 'public/assets/oat-animate.css';
46
+ const jsInput = 'public/assets/oat-animate.js';
47
+ const cssMinOutput = 'public/assets/oat-animate.min.css';
48
+ const jsMinOutput = 'public/assets/oat-animate.min.js';
49
+ const cssGzipOutput = 'public/assets/oat-animate.min.css.gz';
50
+ const jsGzipOutput = 'public/assets/oat-animate.min.js.gz';
51
+
52
+ // Read source files
53
+ console.log('📄 Reading source files...');
54
+ const cssContent = readFileSync(cssInput, 'utf8');
55
+ const jsContent = readFileSync(jsInput, 'utf8');
56
+
57
+ // Minify CSS
58
+ console.log('🎨 Minifying CSS...');
59
+ const minifiedCSS = minifyCSS(cssContent);
60
+ writeFileSync(cssMinOutput, minifiedCSS);
61
+ const cssOriginalSize = getFileSize(cssInput);
62
+ const cssMinSize = getFileSize(cssMinOutput);
63
+ console.log(` Original: ${cssOriginalSize} bytes → Minified: ${cssMinSize} bytes (${((1 - cssMinSize/cssOriginalSize) * 100).toFixed(1)}% reduction)`);
64
+
65
+ // Minify JS
66
+ console.log('⚡ Minifying JavaScript...');
67
+ const minifiedJS = minifyJS(jsContent);
68
+ writeFileSync(jsMinOutput, minifiedJS);
69
+ const jsOriginalSize = getFileSize(jsInput);
70
+ const jsMinSize = getFileSize(jsMinOutput);
71
+ console.log(` Original: ${jsOriginalSize} bytes → Minified: ${jsMinSize} bytes (${((1 - jsMinSize/jsOriginalSize) * 100).toFixed(1)}% reduction)`);
72
+
73
+ // Gzip CSS
74
+ console.log('📦 Gzipping CSS...');
75
+ await gzipFile(cssMinOutput, cssGzipOutput);
76
+ const cssGzipSize = getFileSize(cssGzipOutput);
77
+ console.log(` Gzipped: ${cssGzipSize} bytes`);
78
+
79
+ // Gzip JS
80
+ console.log('📦 Gzipping JavaScript...');
81
+ await gzipFile(jsMinOutput, jsGzipOutput);
82
+ const jsGzipSize = getFileSize(jsGzipOutput);
83
+ console.log(` Gzipped: ${jsGzipSize} bytes`);
84
+
85
+ // Summary
86
+ console.log('\n✅ Build complete!\n');
87
+ console.log('📁 Output files:');
88
+ console.log(` - ${cssMinOutput} (${cssMinSize} bytes)`);
89
+ console.log(` - ${cssGzipOutput} (${cssGzipSize} bytes)`);
90
+ console.log(` - ${jsMinOutput} (${jsMinSize} bytes)`);
91
+ console.log(` - ${jsGzipOutput} (${jsGzipSize} bytes)`);
92
+ console.log(`\n📊 Total savings:`);
93
+ console.log(` CSS: ${cssOriginalSize} → ${cssGzipSize} bytes (${((1 - cssGzipSize/cssOriginalSize) * 100).toFixed(1)}% reduction with gzip)`);
94
+ console.log(` JS: ${jsOriginalSize} → ${jsGzipSize} bytes (${((1 - jsGzipSize/jsOriginalSize) * 100).toFixed(1)}% reduction with gzip)`);
95
+ }
96
+
97
+ build().catch(console.error);
package/index.html ADDED
@@ -0,0 +1,20 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Animations | Oat Animate</title>
7
+ <link rel="stylesheet" href="./node_modules/@knadh/oat/oat.min.css" />
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css" />
9
+ <link rel="stylesheet" href="./public/assets/global.css" />
10
+ <link rel="stylesheet" href="./public/assets/oat-animate.css" />
11
+ </head>
12
+ <body>
13
+ <div id="app"></div>
14
+ <script src="./node_modules/@knadh/oat/oat.min.js" defer></script>
15
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
16
+ <script type="module" src="./src/main.js"></script>
17
+ <script src="./public/assets/global.js"></script>
18
+ <script src="./public/assets/oat-animate.js"></script>
19
+ </body>
20
+ </html>
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "ots-animate",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "src/main.js",
7
+ "author": "dharmesh gurnani (https://dharmeshgurnani.com)",
8
+ "scripts": {
9
+ "start": "npx serve -s .",
10
+ "build": "node build.mjs",
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [],
14
+ "license": "MIT",
15
+ "dependencies": {
16
+ "@knadh/oat": "^0.3.0",
17
+ "@knadh/tinyrouter": "^1.2.0",
18
+ "highlight.js": "^11.11.1",
19
+ "microlight": "^0.0.7"
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="#333333" d="M7.999,0.431c-4.285,0-7.76,3.474-7.76,7.761 c0,3.428,2.223,6.337,5.307,7.363c0.388,0.071,0.53-0.168,0.53-0.374c0-0.184-0.007-0.672-0.01-1.32 c-2.159,0.469-2.614-1.04-2.614-1.04c-0.353-0.896-0.862-1.135-0.862-1.135c-0.705-0.481,0.053-0.472,0.053-0.472 c0.779,0.055,1.189,0.8,1.189,0.8c0.692,1.186,1.816,0.843,2.258,0.645c0.071-0.502,0.271-0.843,0.493-1.037 C4.86,11.425,3.049,10.76,3.049,7.786c0-0.847,0.302-1.54,0.799-2.082C3.768,5.507,3.501,4.718,3.924,3.65 c0,0,0.652-0.209,2.134,0.796C6.677,4.273,7.34,4.187,8,4.184c0.659,0.003,1.323,0.089,1.943,0.261 c1.482-1.004,2.132-0.796,2.132-0.796c0.423,1.068,0.157,1.857,0.077,2.054c0.497,0.542,0.798,1.235,0.798,2.082 c0,2.981-1.814,3.637-3.543,3.829c0.279,0.24,0.527,0.713,0.527,1.437c0,1.037-0.01,1.874-0.01,2.129 c0,0.208,0.14,0.449,0.534,0.373c3.081-1.028,5.302-3.935,5.302-7.362C15.76,3.906,12.285,0.431,7.999,0.431z"/></svg>
@@ -0,0 +1,13 @@
1
+
2
+ /* Swap theme icons */
3
+ html[data-theme="dark"] .icon-dark {
4
+ display: none;
5
+ }
6
+ html:not([data-theme="dark"]) .icon-light {
7
+ display: none;
8
+ }
9
+
10
+ code {
11
+ border-radius: 8px;
12
+ max-width: 60vw;
13
+ }
@@ -0,0 +1,5 @@
1
+ function toggleTheme() {
2
+ var theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
3
+ document.documentElement.setAttribute('data-theme', theme);
4
+ localStorage.setItem('theme', theme);
5
+ }
@@ -0,0 +1,12 @@
1
+ <svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 403 188" width="403" height="188">
2
+ <defs>
3
+ <image width="60" height="82" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAABSCAYAAAAIArdYAAAKZUlEQVR4AdRbeWwcVxn/vtkdr/fwem3HuZom5Gpz1XYlBK0AQSROKSk0KetQED0ElP4FQSpFKKlKBSWcgQq1EQgi0aDGS5uQpBIFiQahICK1tLEjh7ZpEudqYsfxsbuz673m8X1jz2p3vLvenXlru6P37Zt3fL/3/ea9ede8VWCWr2RvZGW8L/Jg/FTPL8n/W7yvpz/e2zNMIqZklPwzJEe1Uz3f1N54YalME2eFsOj9o1/rPfg1rbfnRA7EeRBiPyDsJP/TIGADEWojMV2IbtaTbBUIzwmXcpXIvxLvjXyW4hy7uhIe74+0xvoO/kADzyUB+DsB8BGbFn8GQPyViJ+OvtljF8Moum6E46ci33NlxWUU+ASV1Eoiw21SFDih9fa8ONb3pxY7gNIJcw1QTZwHFD8mg3wk0h21lO1u4T4T64t8vFZwqYRjvZFHqQaOkxErSertFqMQ/6BX5ou1FCSNcKyvZx+CeJYKV0lmy7nolYnwg662QMeExfHjbq03EkEBj1RbqOx89KB/Q8PbJ6vBdUw43jr0kgBRsVnpeg5SiShoo9dh/PoAjFx5B4YvnoEbF04bMnL5LUhGh6uxt1wehYa3P/MYXy6DGW+bsBACjZoFuMcEK/TTyThoI9dh9OpZuEnkooMXITF2A9LJGOQyKRD0EMz8uWwG4jevQWz4ihllxw/RGH9I9EcaKinbJkxk91hrNpuegOjQJRge6KeavACJ8RvAcZUMKEybiI0WPYjCtCrvu7SM2FMpry3C8b6DDwHCd01grrHo0EWjNlPaOAihm0k1+YgKoOKqSWdaZoSdib7I3dPipyKUKb9qL3b64HoQ+Bwr5DJpo0b5nUxpUY5yJL5QO8i4dAH7RCRS8snVRFi8fsyHOhwhozzcXEeuvA1coxR27AKtS8AXWugYZxJAdMRv10uOGjUR1tTEs7lMZu3Ye+eMDmkS3Nmv6vFB67LbwNu8wBmQRRsBnxIX9jdaoqFqwjR/3UqdygPc62ZSCSuOrTCTDC1dDS7VY0t/BqU2Lerbac1TFeHYG5H22M1rER427HZI1oKZbICasTVecthKGKoiPD747kmaGExrHnaNC7QthUD9ybJ57TR8Fs0TZiQ8cOyJV6kJr2JtGdK0YBl4g4XrfRmo5TFogHy4MLUi4YEju46JnL65UMHJvTe4ABqbbC1jbRdL8+wtN08eCJoAZQlf+MuuPULAFjOjU7/BG4BA2xKnMHb0XR5fQ55HScLnDu3iDI/bQS+lgzSD4qZcKm024mjdvM0sZxrhc5HHm2kR/3szgwyfa1Zxz+Yyudhq2gz8lBBPGlyNn8JkxeP+KYVlTXnA7fHSeytrS4sss+MEBLXTGzayahHhgUO776Z58jc4QZb4pU0XwdGFujB2O4sIgyJ+6wjVouxuaIQGX76DtKTObpA2/j7EJeYJ0xC0jSI3caQsme0hqKLdChjc8oRpCHqsooKNRI8/ZEOrTioCOhjZIHzx6G5+oe/iCFmiNvpBcbllwcnA8ST7I8sNwrRB8aAMxEIMlZZ9heH5cC+y+tJJwqjnB2ZZhnENy8KShUPj8SLl0uFdq2kokrY4MI1zqRU3D81ss+vruETJAX6sHqW66rOod2aqAgsUROAOyxmQRRsVlyVmfgSFgJBCe8u3yTYHEWVDSsITIe605I8d85QwAjYzYUlP7/0Bw++wLt1UmrZJx5QASMPShEK79OMSsIog9Fy2KDxfAlQPSWrSeLEeBum5TD1gHWEiihg1af0dRyhllOdnLeMQ7eYo75ax2VF0Lp1ypF8fZRxUMjnX2XqA1/JduB7ll8TU9feUNdueHKLEMRKpLksfx6UCSgBzoXKWOi1CQvg7/Up1mZQmFU8CWMrbGb5gEKbp5YsSAIsghK5DNpUsipvTgIC3uHyDsJpKvAyIOY6QKemJuEw4Z1gIZxjAIHxreG9SVb1XOUKmpCUcg5BmD8JrjGUQ5htPU6iffZlCXx1Bz86PCYgCeJK5KfzD4m1u7XXTVwK+lymyzoA4tCnjTY++zhh5wkLgNX/LIo6TKsnYTal4dsBQ4Gv4wUcyQMp5wiBwsMHbBKrk3cZcJg18Ko/KmjMnFHHULDxPmL46GJ2Wv3WxmSbNT0bntpazKPLDbp4weNz/Y4YqbaD7JH8ASyeixvlKxp91oeEodMeOc2a5ecLB9du4GgY5gd9ltdHHt9IkMXZDGlYtQCggUpg/T3gq8vSUD8GFK0CRuPs4oY3BXKyRM4o4YHJi30rYGJyNBPouFFy0gm/liBCgjRgNSA5eNSg02ShszqxSRBgRTnCkKSq9z80SSU/ERyEzIecUn2ljJV/o4nlrehHhiUSmiDBn5g/afJCM72UIn+YDoDFBBlgFDASIJ1VlvzVLEeG2u74SBWoG1kzeYBv4QnKO9vLZ6tnowGhz8lcLN4anrV6KCANfAg6zZxV/y2II8HFBavfWtFrD2tgQDVPpWtVqyZ/MioZflFKYRlgHPFQqI8fxgdDQ4lXg+EO3EBC9cZkh6yMCnmm5896SuzjTCAc7w28D4JtQ5lIbfdByy1pQqUMrk6Wq6GwqAQmq6aoy15IJIZqayDxdTkUplSCEPu1lL8zHNRxashL8vNhw0MS10UHqtbVCaBn3Txt9URmkkoRzSq5osC6ti+CjKWiLwwPe/PceiWvmAX9T4tel7Z2MLUk41PHlUUD4w2SWyr/uBq/RxL3Uk1fOWTpV13PS3mf6dvQArnxoonRJk7ElCXOSroufkK+TzOgQEXisbrllDXj8zTPmt2bITGjUazvcuEc40NTR/S8rtjVclnCwawd/gumxKlQKc20HFy4H/tNGY6C2c9EOP81c11X125Vs4zSWsoSNREXnI8Q1P3o+39HUvgzabl0HvuZ2mGkR4nKr4KDXzyLilqnVHptdUSoS9t3xJf6Hd9kuviIyJSpuFXhDoW3FBlp9LQfVGwDr5VIbILjoA9boGsL4fX9H+L/VKlQkzCD+rvBTAOh4R5Pf7dDilbCAyIeWrAIWbvqty24Hd0Mj2LvE84HO8M9q0Z2RMIPldOVe8iv2fpRelUNaY6uNfmBxqZ6qdMpketU/sqjoDxxl8hVFV0W4+c77zoKArxdpzmGA1lr/8UPqHty8ueajBlURZm6Bru4DCLiL7+dSBOCRgBs/gZ1ftTVFq5owk/R3hn9ENb2X7+dCaM3xw6bO8BdwYzhtt/yaCHMhVNPfAUD+77CA2bs0FGJrU1f3bqdF1kyYC+SeURG4naafUQ7XV7BPiNyH/V07XpZRji3CXLCvK3xYQX0TIP6Tw3WQYUDxMD3czqau+x0Pi6Z9tgkzAE9MAh3hzUKI7QiQ3+zmNAfCM7ufJz2NqwIdOyouU+2U4YiwWWBT145D/s7uNRS+n4j/m/yaHenxA3tGUfS1gc7ux9rXfT5WM0gVClIIm+WQoS8Q8Y+60b0aEKhzg1cojXZQYPppP9qZIJIvoYBHXYCrSG8N6X+LWw3p1M1JJWxa2dix/Xygo3svEfgcyTqSEAkWSUd3M5G8z9/VvY8Pm5i69fb/DwAA///vLFrpAAAABklEQVQDALLGQdIVhMoxAAAAAElFTkSuQmCC"/>
4
+ </defs>
5
+ <style>
6
+ .s0 { fill: #574747 }
7
+ </style>
8
+ <use href="#img1" transform="matrix(.572,.661,-0.661,.572,271.912,21.329)"/>
9
+ <use id="Layer copy" href="#img1" transform="matrix(.994,.296,-0.296,.994,42.821,14.45)"/>
10
+ <path class="s0" d="m58.36 95.63q-6.65 0-12.26-2.26-5.55-2.26-9.57-6.28-4.02-4.08-6.27-9.69-2.26-5.61-2.26-12.38 0-3.65 0.61-7.01 0.67-3.41 1.77-6.34 0.49-1.15 0.49-1.64 0-0.61-0.31-1.16-0.3-0.55-0.67-1.16-0.37-0.61-0.67-1.28-0.3-0.67-0.3-1.52 0-2.56 2.92-5 2.93-2.5 7.74-4.39 4.82-1.95 10.91-3.11 6.1-1.22 12.5-1.22 7.86 0 14.14 2.01 6.34 2.02 10.73 5.8 4.45 3.72 6.83 9.08 2.38 5.36 2.38 12.07 0 7.5-2.99 14.02-2.98 6.46-8.23 11.22-5.18 4.75-12.25 7.49-7.07 2.75-15.24 2.75zm26.45-33.11q0-4.75-1.64-8.53-1.65-3.78-4.76-6.34-3.11-2.62-7.68-3.96-4.51-1.4-10.24-1.4-10.06 0-15.18 5.12-5.05 5.05-5.05 15.11 0 4.88 1.52 8.97 1.52 4.02 4.27 6.95 2.74 2.86 6.52 4.51 3.84 1.58 8.41 1.58 5.24 0 9.63-1.58 4.39-1.65 7.5-4.57 3.17-2.93 4.94-6.95 1.77-4.09 1.76-8.91zm58.21-27.79q3.36 0 6.47 1.04 3.11 1.03 5.48 2.86 2.38 1.83 3.78 4.39 1.46 2.56 1.46 5.67 0 1.28-0.61 2.5-0.54 1.15-1.52 2.07-0.98 0.85-2.26 1.4-1.21 0.49-2.56 0.49-0.12 0-0.24 0.06-0.06 0-0.18 0-0.12 0.06-0.25 0.06l0.25 4.88q0.24 8.71 2.44 12.74 2.25 4.02 5.85 4.02 1.28 0 2.25-0.24 1.04-0.25 1.89-0.55 0.92-0.37 1.71-0.61 0.79-0.24 1.59-0.24 1.4 0 2.43 1.21 1.1 1.22 1.1 2.93 0 1.71-1.34 3.41-1.28 1.71-3.41 3.11-2.13 1.34-4.82 2.2-2.68 0.85-5.42 0.85-4.76 0-8.35-3.9-3.6-3.96-5.12-11.58-0.37-1.22-0.98-1.22-0.73 0-1.28 0.73-6.04 7.63-12.86 11.47-6.83 3.78-13.47 3.78-3.11 0-5.61-0.92-2.5-0.91-4.27-2.56-1.71-1.71-2.68-4.08-0.92-2.44-0.92-5.43 0-4.2 1.83-8.83 1.89-4.64 5.06-9.15 3.17-4.51 7.31-8.59 4.21-4.09 8.78-7.2 4.63-3.11 9.39-4.94 4.75-1.82 9.08-1.83zm-2.01 21.09q1.1-2.07 2.01-2.98 0.92-0.98 2.63-1.29 1.34-0.18 1.34-0.85 0-0.49-0.37-1.04-1.16-1.58-2.44-2.74-1.28-1.22-3.41-1.22-2.32 0-5.18 1.34-2.87 1.34-5.85 3.6-2.93 2.2-5.8 5.06-2.8 2.8-4.99 5.79-2.2 2.99-3.54 5.91-1.34 2.93-1.34 5.24 0 2.08 1.09 3.23 1.16 1.16 3.11 1.16 5 0 10.91-5.3 5.92-5.31 11.83-15.91zm38.72-38.22q0-3.23 1.82-4.51 1.83-1.34 6.04-1.34 1.53 0 2.56 0.3 1.1 0.24 1.83 0.97 0.79 0.73 1.22 1.96 0.48 1.15 0.79 2.98 0.73 5.67 1.58 11.71 0.92 6.03 1.89 12.13 0.37 2.74 2.87 2.74 0.67 0 2.19-0.12 1.59-0.18 3.73-0.37 2.13-0.24 4.57-0.48 2.49-0.25 4.93-0.43 2.5-0.24 4.7-0.37 2.25-0.18 3.96-0.18 1.34 0 2.13 0.55 0.8 0.48 1.22 1.34 0.49 0.79 0.61 1.83 0.19 0.97 0.19 2.01 0 0.91-0.37 1.89-0.3 0.97-0.92 1.76-0.54 0.73-1.4 1.22-0.85 0.49-1.95 0.49-5.3 0-10.73 0.37-5.36 0.3-10.73 0.85-2.74 0.37-2.74 2.74 0 0.19 0.06 0.49 0.06 0.24 0.06 0.43 0.73 5.3 1.34 9.93 0.67 4.64 1.1 8.29 0.48 3.6 0.73 6.04 0.3 2.38 0.3 3.17 0 2.19-0.43 3.66-0.42 1.52-1.4 2.44-0.97 0.97-2.62 1.34-1.58 0.42-4.02 0.42-2.32 0-3.42-1.09-1.09-1.1-1.21-3.36-0.37-7.19-1.16-14.44-0.8-7.32-1.83-14.57-0.55-2.63-2.74-2.63-0.19 0-0.43 0.06-0.24 0.06-0.43 0.06-3.78 0.86-7.13 1.71-3.35 0.86-6.28 1.83-1.64 0.55-2.93 0.79-1.28 0.19-2.31 0.19-1.4 0-2.07-1.22-0.67-1.28-0.67-3.17 0-0.67 0.12-1.53 0.12-0.91 0.48-1.76 0.31-0.92 0.98-1.65 0.61-0.79 1.71-1.28 2.55-1.04 6.82-2.13 4.27-1.16 9.63-2.13 1.22-0.31 1.89-0.98 0.73-0.73 0.73-2.13 0-0.3 0-0.61 0-0.37-0.12-0.73-0.97-5.61-1.88-10.18-0.86-4.63-1.53-7.92-0.61-3.3-0.97-5.19-0.37-1.88-0.36-2.19z"/>
11
+ <path id="animate" class="s0" aria-label="animate" d="m56.6 161.5q1.1 2.6 3.4 3.7 2.1 1.1 4.9 0.5 2.3-0.5 3.4-2.3 1.1-1.7 0.7-4-0.4-1.9-1.8-4.3-2.3-4.1-2.1-14.4 0.2-13.4 1.2-18.9 0.6-3.5-0.2-4.7-0.7-1.3-1.5-2.5-0.7-1.2-4.1-2-2.8-0.7-5 0.3-14-3.5-26.6 5.8-9.9 8.3-9.8 23.4 0.1 11.5 5.7 17.6 5.7 6 18 6 4.6 0 13.8-4.2zm-16.1-6.6q-4.3-0.2-5.4-1.8-1.1-1.6-2.2-3.2-1-1.5-1.1-8.5 0.4-10.4 8.6-16.1 1.9-1.4 5.3-2.2 3.8-0.9 7.4 0.7-1.9 8.4-0.3 27-3.6 2.7-4.9 3.2-3.4 1.2-7.4 0.9zm42-45.3q-2.8 0-3.6 0.9-0.8 0.8-1.7 1.8-0.9 0.8-1 3.5l-1 42q0 3 1.5 4.9 1.6 2.1 4.4 2.2 3 0 5-1.9 2.2-2.1 2.3-5.4l0.8-26.1q7.5-6.5 13.7-6.1 3.2 0.1 4.1 1.5 0.8 1.4 1.6 2.8 0.9 1.3 0.7 7.6l-0.7 20.6q-0.1 3.2 0.8 4.3 0.9 1.1 1.8 2.2 0.9 1 3.7 1.1 0.5 0 1.1-0.1 2.9-0.3 3.7-1.4 0.8-1.1 1.6-2.3 0.7-1.1 0.8-4.2l0.4-22.5q0.1-10.9-2.3-13.7-2.4-3-4.7-5.9-2.4-2.9-13.3-2.9-7.2 0-12.7 2.8-0.3-2.6-2.4-4.2-2-1.5-4.6-1.5zm51.2 4.6q-1.9 2.1-2 5.6l-0.8 37.8q-0.1 3.4 1.8 5.5 1.8 2.3 5.3 2.3 3.3 0 5-2.4 1.8-2.2 1.8-5.7l0.7-37.5q0-3.3-1.6-5.5-1.7-2.4-5-2.4-3.4-0.1-5.2 2.3zm5.8-24.6h-0.2q-2.2 0-4.2 1.2-1.6 1.2-2.7 3-1.1 1.8-1.1 3.9 0 2.3 1.2 4.2 1.1 1.7 2.8 2.8 1.8 1.1 3.8 1.2h0.3q2.1 0 3.7-0.9 1.7-0.7 2.9-2.4 1.4-1.9 1.6-4.2v-0.1-0.6q0-2-0.8-3.7-1.1-2.2-3.2-3.4-1.8-1-4.1-1zm23.4 20q-2.8 0-3.7 0.9-0.8 0.8-1.7 1.8-0.9 0.8-1 3.5l-1 41.9q-0.1 3 1.5 4.9 1.7 2.1 4.5 2.1 3.1 0.1 5.1-1.9 2-2.1 2.1-5.3l0.8-23.7q1.3-4.5 2.4-5.4 1.1-1 2.3-1.9 1.1-1 4.7-0.9 1.3 0.1 1.8 0.4 0.5 0.3 0.9 0.6 0.5 0.3 0.9 1 0.4 0.6 0.8 1.3 0.3 0.7 0.7 3 0.4 2.5 0.3 5.8l-0.5 19.3q-0.1 3.3 1.6 5.5 1.7 2.1 4.8 2.2 0.5 0 1.1-0.1 3.2-0.3 4.1-1.4 0.8-1.1 1.7-2.3 0.9-1.1 1-4.6l0.6-21.9q0.1-2 0.1-2.4 1.5-3.6 2.8-4.4 1.2-0.8 2.5-1.6 1.3-0.8 5.3-0.7 1.3 0.1 1.8 0.3 0.5 0.3 1 0.7 0.5 0.3 0.9 1 0.5 0.6 0.9 1.4 0.4 0.7 0.7 3.1 0.4 2.6 0.4 6.1l-0.3 19.9q0 3.3 1.7 5.4 1.6 2.1 4.6 2.1 0.5 0 1 0 3-0.3 3.9-1.4 0.8-1.2 1.6-2.3 0.8-1.1 0.9-4.2l0.3-22.4q0.2-10.9-2.3-13.7-2.4-3-4.9-5.9-2.5-2.9-12.9-2.9-9.7-0.1-15.4 5.7-4.7-5.8-14.5-5.7-5 0-9 2.1-0.5-2.4-1.5-3.1-1-0.6-1.9-1.3-1-0.6-3.5-0.6zm107.7 51.9q1.1 2.6 3.4 3.7 2.1 1.1 4.9 0.5 2.3-0.5 3.4-2.3 1.1-1.7 0.7-4-0.4-1.9-1.8-4.3-2.3-4.1-2.1-14.4 0.2-13.4 1.2-18.9 0.6-3.5-0.2-4.7-0.7-1.3-1.5-2.5-0.7-1.2-4.1-2-2.8-0.7-5 0.3-14-3.5-26.6 5.8-9.9 8.3-9.8 23.4 0.1 11.5 5.7 17.6 5.7 6 18 6 4.6 0 13.8-4.2zm-16.1-6.6q-4.3-0.2-5.4-1.8-1.1-1.6-2.2-3.2-1-1.5-1.1-8.5 0.4-10.4 8.6-16.1 1.9-1.4 5.3-2.2 3.8-0.9 7.4 0.7-1.9 8.4-0.3 27-3.6 2.7-4.9 3.2-3.4 1.2-7.4 0.9zm54.7-70.5q-3.1 0-4 0.9-1 0.9-1.9 1.8-0.9 0.9-1 3.9l-0.5 21q-4.7 0.1-8.7 0.1-2.8 0-3.6 0.9-0.7 1-1.6 2-0.8 0.9-0.8 4.1 0 3 1.6 4.9 1.4 1.9 4 1.9h8.8l-0.9 32.3q-0.1 2.9 1.7 4.8 1.7 2.1 4.9 2.1 3.5 0 5.6-1.9 2.1-1.8 2.2-4.8l0.8-32.5h8.1q3 0 3.9-0.9 1-1 1.9-1.9 1-0.9 1-2.6 0-1.6 0-3.3 0-1.7-1-2.6-1-0.9-2-1.8-1-0.9-4.1-0.9l-7.4 0.1q0.2-9.5 0.3-20.7 0-3.2-1-4.1-1-1-2-1.9-1-0.9-4.3-0.9zm36.6 59.3l30.9-4.6q3-0.4 3.8-1.5 0.8-1.1 1.6-2.2 0.9-1.1 1-4.4 0.3-7.9-5.7-13.8-6.5-6.4-19.1-5.7-12.1 0.7-18.8 10.5-5.3 7.7-5.3 17.8 0.1 12.5 8.5 19.4 7 5.8 17.6 5.9 13.8 0.1 21.3-6.8 2.3-2.2 2.6-3.5 0.3-1.3 0.6-2.6 0.4-1.4-0.9-4.1-0.7-1.5-1.4-1.8-0.6-0.3-1.3-0.6-0.7-0.3-2.3 0-1.4 0.3-2.1 0.8-0.6 0.6-1.3 1.2-0.7 0.5-2.5 2.4-2.7 2.9-12.1 3-6.1 0-11.1-4-3.4-2.8-4-5.4zm3.8-16.1q3.8-5.2 10.2-5.2 4.3 0 8.2 2.3 2 1.3 3 3.2l-23.4 3.5q1.4-2.9 2-3.8z"/>
12
+ </svg>
@@ -0,0 +1,164 @@
1
+ /* Base styles */
2
+ [ot-animate] {
3
+ will-change: transform, opacity;
4
+ }
5
+
6
+ /* Reduced motion support */
7
+ @media (prefers-reduced-motion: reduce) {
8
+ [ot-animate] {
9
+ animation: none !important;
10
+ transform: none !important;
11
+ opacity: 1 !important;
12
+ transition: none !important;
13
+ }
14
+ }
15
+
16
+ /* All Animations And Keyframes */
17
+ /* Keyframes */
18
+ @keyframes ot-fade-up {
19
+ from { opacity: 0.5; transform: translateY(18px); }
20
+ to { opacity: 1; transform: translateY(0); }
21
+ }
22
+
23
+ @keyframes ot-fade-down {
24
+ from { opacity: 0.5; transform: translateY(-18px); }
25
+ to { opacity: 1; transform: translateY(0); }
26
+ }
27
+
28
+ @keyframes ot-zoom-in {
29
+ from { transform: scale(0.94); }
30
+ to { transform: scale(1); }
31
+ }
32
+
33
+ @keyframes ot-slide-left {
34
+ from { transform: translateX(24px); }
35
+ to { transform: translateX(0); }
36
+ }
37
+
38
+ @keyframes ot-slide-right {
39
+ from { transform: translateX(-24px); }
40
+ to { transform: translateX(0); }
41
+ }
42
+
43
+ @keyframes ot-pop {
44
+ 0% { transform: scale(0.85); }
45
+ 80% { transform: scale(1.04); }
46
+ 100% { transform: scale(1); }
47
+ }
48
+
49
+ @keyframes ot-bounce {
50
+ 0%, 100% { transform: translateY(0); }
51
+ 50% { transform: translateY(-8px); }
52
+ }
53
+
54
+ @keyframes ot-flip-in {
55
+ from { opacity: 0.5; transform: perspective(480px) rotateX(30deg); }
56
+ to { opacity: 1; transform: perspective(480px) rotateX(0deg); }
57
+ }
58
+
59
+ @keyframes ot-pulse {
60
+ 0%, 100% { transform: scale(1); }
61
+ 50% { transform: scale(1.03); }
62
+ }
63
+
64
+ @keyframes ot-shake {
65
+ 0%, 100% { transform: translateX(0); }
66
+ 25% { transform: translateX(-4px); }
67
+ 75% { transform: translateX(4px); }
68
+ }
69
+
70
+ @keyframes ot-shift-up-2 {
71
+ from { opacity: 0.5; transform: translateY(12px); }
72
+ to { opacity: 1; transform: translateY(-8px); }
73
+ }
74
+
75
+ /* ============================================
76
+ ON-LOAD ANIMATIONS (Pure CSS)
77
+ ============================================ */
78
+
79
+ [ot-animate="fade-up"],
80
+ [ot-animate~="fade-up"] {
81
+ animation: ot-fade-up 0.6s ease forwards;
82
+ }
83
+
84
+ [ot-animate="fade-down"],
85
+ [ot-animate~="fade-down"]{
86
+ animation: ot-fade-down 0.6s ease forwards;
87
+ }
88
+
89
+ [ot-animate="zoom-in"],
90
+ [ot-animate~="zoom-in"] {
91
+ animation: ot-zoom-in 0.6s ease forwards;
92
+ }
93
+
94
+ [ot-animate="slide-left"],
95
+ [ot-animate~="slide-left"]{
96
+ animation: ot-slide-left 0.6s ease forwards;
97
+ }
98
+
99
+ [ot-animate="slide-right"],
100
+ [ot-animate~="slide-right"]{
101
+ animation: ot-slide-right 0.6s ease forwards;
102
+ }
103
+
104
+ [ot-animate="pop"],
105
+ [ot-animate~="pop"]{
106
+ animation: ot-pop 0.6s ease forwards;
107
+ }
108
+
109
+ [ot-animate="bounce"],
110
+ [ot-animate~="bounce"] {
111
+ animation: ot-bounce 0.6s ease forwards;
112
+ }
113
+
114
+ [ot-animate="flip-in"],
115
+ [ot-animate~="flip-in"] {
116
+ animation: ot-flip-in 0.6s ease forwards;
117
+ }
118
+
119
+ [ot-animate="pulse"],
120
+ [ot-animate~="pulse"] {
121
+ animation: ot-pulse 1s ease infinite;
122
+ }
123
+
124
+ [ot-animate="shake"],
125
+ [ot-animate~="shake"] {
126
+ animation: ot-shake 0.4s ease forwards;
127
+ }
128
+
129
+ [ot-animate="shift-up-2"],
130
+ [ot-animate~="shift-up-2"] {
131
+ animation: ot-shift-up-2 0.6s ease forwards;
132
+ }
133
+
134
+
135
+ /* All Hover Animataions */
136
+ /*ot-animate="hover:fade-up" */
137
+ [ot-animate*="hover:fade-up"]:hover {
138
+ transform: translateY(-4px);
139
+ animation: ot-fade-up 0.6s ease forwards;
140
+ }
141
+
142
+ [ot-animate*="hover:fade-down"]:hover {
143
+ animation: ot-fade-down 0.6s ease forwards;
144
+ }
145
+
146
+ [ot-animate*="hover:zoom-in"]:hover {
147
+
148
+ animation: ot-zoom-in 0.6s ease forwards;
149
+ }
150
+
151
+ [ot-animate*="hover:slide-left"]:hover {
152
+
153
+ animation: ot-slide-left 0.6s ease forwards;
154
+ }
155
+
156
+ [ot-animate*="hover:slide-right"]:hover {
157
+
158
+ animation: ot-slide-right 0.6s ease forwards;
159
+ }
160
+
161
+ [ot-animate*="hover:pop"]:hover {
162
+ animation: ot-pop 0.6s ease forwards;
163
+ }
164
+
@@ -0,0 +1,39 @@
1
+ /*
2
+ ** ---------------------------------------------------------------------
3
+ ** Oat Animate Library
4
+ ** ---------------------------------------------------------------------
5
+ ** Author: Dharmesh Gurnani
6
+ ** This file contains the JavaScript code for the OT Animate library, which
7
+ ** provides scroll-based animations for web elements. It uses the Intersection
8
+ ** Observer API to detect when elements with the "ot-animate" attribute come
9
+ ** into view and applies the specified animation classes to them.
10
+ */
11
+ function observeOTAnimateView() {
12
+ const observer = new IntersectionObserver(
13
+ (entries) => {
14
+ entries.forEach((entry) => {
15
+ if (entry.isIntersecting) {
16
+ setTimeout(() => {
17
+ const el = entry.target;
18
+ el.setAttribute(
19
+ "ot-animate",
20
+ `${el.getAttribute("ot-animate").replace("view:", "")}`,
21
+ );
22
+ el.classList.add(`ot-animated`);
23
+ observer.unobserve(el);
24
+ }, 100);
25
+ }
26
+ });
27
+ },
28
+ { rootMargin: "-3px 0px -3px 0px", threshold: 0.3 },
29
+ );
30
+
31
+ document.querySelectorAll('[ot-animate*="view:"]').forEach((el) => {
32
+ if (el.getAttribute("ot-animate").startsWith("view:")) {
33
+ observer.observe(el);
34
+ }
35
+ });
36
+ }
37
+
38
+ // initialize on DOMContentLoaded
39
+ document.addEventListener("DOMContentLoaded", observeOTAnimateView);
@@ -0,0 +1 @@
1
+ [ot-animate]{will-change:transform,opacity;}@media (prefers-reduced-motion:reduce){[ot-animate]{animation:none !important;transform:none !important;opacity:1 !important;transition:none !important;}}@keyframes ot-fade-up{from{opacity:0.5;transform:translateY(18px);}to{opacity:1;transform:translateY(0);}}@keyframes ot-fade-down{from{opacity:0.5;transform:translateY(-18px);}to{opacity:1;transform:translateY(0);}}@keyframes ot-zoom-in{from{transform:scale(0.94);}to{transform:scale(1);}}@keyframes ot-slide-left{from{transform:translateX(24px);}to{transform:translateX(0);}}@keyframes ot-slide-right{from{transform:translateX(-24px);}to{transform:translateX(0);}}@keyframes ot-pop{0%{transform:scale(0.85);}80%{transform:scale(1.04);}100%{transform:scale(1);}}@keyframes ot-bounce{0%,100%{transform:translateY(0);}50%{transform:translateY(-8px);}}@keyframes ot-flip-in{from{opacity:0.5;transform:perspective(480px) rotateX(30deg);}to{opacity:1;transform:perspective(480px) rotateX(0deg);}}@keyframes ot-pulse{0%,100%{transform:scale(1);}50%{transform:scale(1.03);}}@keyframes ot-shake{0%,100%{transform:translateX(0);}25%{transform:translateX(-4px);}75%{transform:translateX(4px);}}@keyframes ot-shift-up-2{from{opacity:0.5;transform:translateY(12px);}to{opacity:1;transform:translateY(-8px);}}[ot-animate="fade-up"],[ot-animate~="fade-up"]{animation:ot-fade-up 0.6s ease forwards;}[ot-animate="fade-down"],[ot-animate~="fade-down"]{animation:ot-fade-down 0.6s ease forwards;}[ot-animate="zoom-in"],[ot-animate~="zoom-in"]{animation:ot-zoom-in 0.6s ease forwards;}[ot-animate="slide-left"],[ot-animate~="slide-left"]{animation:ot-slide-left 0.6s ease forwards;}[ot-animate="slide-right"],[ot-animate~="slide-right"]{animation:ot-slide-right 0.6s ease forwards;}[ot-animate="pop"],[ot-animate~="pop"]{animation:ot-pop 0.6s ease forwards;}[ot-animate="bounce"],[ot-animate~="bounce"]{animation:ot-bounce 0.6s ease forwards;}[ot-animate="flip-in"],[ot-animate~="flip-in"]{animation:ot-flip-in 0.6s ease forwards;}[ot-animate="pulse"],[ot-animate~="pulse"]{animation:ot-pulse 1s ease infinite;}[ot-animate="shake"],[ot-animate~="shake"]{animation:ot-shake 0.4s ease forwards;}[ot-animate="shift-up-2"],[ot-animate~="shift-up-2"]{animation:ot-shift-up-2 0.6s ease forwards;}[ot-animate*="hover:fade-up"]:hover{transform:translateY(-4px);animation:ot-fade-up 0.6s ease forwards;}[ot-animate*="hover:fade-down"]:hover{animation:ot-fade-down 0.6s ease forwards;}[ot-animate*="hover:zoom-in"]:hover{animation:ot-zoom-in 0.6s ease forwards;}[ot-animate*="hover:slide-left"]:hover{animation:ot-slide-left 0.6s ease forwards;}[ot-animate*="hover:slide-right"]:hover{animation:ot-slide-right 0.6s ease forwards;}[ot-animate*="hover:pop"]:hover{animation:ot-pop 0.6s ease forwards;}
@@ -0,0 +1 @@
1
+ function observeOTAnimateView(){const observer=new IntersectionObserver((entries)=>{entries.forEach((entry)=>{if(entry.isIntersecting){setTimeout(()=>{const el=entry.target;el.setAttribute("ot-animate",`${el.getAttribute("ot-animate").replace("view:","")}`,);el.classList.add(`ot-animated`);observer.unobserve(el);},100);}});},{rootMargin:"-3px 0px-3px 0px",threshold:0.3},);document.querySelectorAll('[ot-animate*="view:"]').forEach((el)=>{if(el.getAttribute("ot-animate").startsWith("view:")){observer.observe(el);}});}document.addEventListener("DOMContentLoaded",observeOTAnimateView);
package/src/main.js ADDED
@@ -0,0 +1,74 @@
1
+ import router from "../node_modules/@knadh/tinyrouter/tinyrouter.js";
2
+ import { withLayout } from "./template.js";
3
+ import { homePage } from "./pages/home.js";
4
+ import { aboutPage } from "./pages/about.js";
5
+ import { usage } from "./pages/usage.js";
6
+ import { animationsPage } from "./pages/animations.js";
7
+ import { showcasePage } from "./pages/showcase.js";
8
+
9
+ const app = document.querySelector("#app");
10
+
11
+ if (!app) {
12
+ throw new Error("Missing #app mount element.");
13
+ }
14
+
15
+ function render(markup) {
16
+ app.innerHTML = markup;
17
+ // Re-init OATAnimate for hover and inView (on-load is pure CSS now)
18
+ if (window.OATAnimate) {
19
+ window.OATAnimate.init();
20
+ }
21
+ // Initialize syntax highlighting for code elements
22
+ if (window.hljs) {
23
+ document.querySelectorAll("pre code").forEach((el) => {
24
+ hljs.highlightElement(el);
25
+ });
26
+ }
27
+ // Handle hash navigation after render
28
+ if (window.location.hash) {
29
+ const id = window.location.hash.slice(1);
30
+ const element = document.getElementById(id);
31
+ if (element) {
32
+ element.scrollIntoView({ behavior: "smooth" });
33
+ }
34
+ }
35
+ }
36
+
37
+ const r = router.new({
38
+ defaultHandler: () => {
39
+ render(
40
+ withLayout(
41
+ () => "<p>Page not found.</p>",
42
+ "404"
43
+ )()
44
+ );
45
+ r.bind(document);
46
+ },
47
+ });
48
+
49
+ r.on("/", (ctx) => {
50
+ render(withLayout(homePage, "Home")(ctx));
51
+ r.bind(document);
52
+ });
53
+
54
+ r.on("/about", (ctx) => {
55
+ render(withLayout(aboutPage, "About")(ctx));
56
+ r.bind(document);
57
+ });
58
+
59
+ r.on("/usage", (ctx) => {
60
+ render(withLayout(usage, "Usage")(ctx));
61
+ r.bind(document);
62
+ });
63
+
64
+ r.on("/animations", (ctx) => {
65
+ render(withLayout(animationsPage, "Animations")(ctx));
66
+ r.bind(document);
67
+ });
68
+
69
+ r.on("/showcase", (ctx) => {
70
+ render(withLayout(showcasePage, "Showcase")(ctx));
71
+ r.bind(document);
72
+ });
73
+
74
+ r.ready();
@@ -0,0 +1,7 @@
1
+ import { html } from "../template.js";
2
+
3
+ export function aboutPage() {
4
+ return html`
5
+ <p>This is a second page to demonstrate route-based content swapping.</p>
6
+ `;
7
+ }
@@ -0,0 +1,241 @@
1
+ import { html } from "../template.js";
2
+
3
+ export function animationsPage() {
4
+ return html`
5
+ <!-- ON LOAD ANIMATIONS -->
6
+ <section id="onload" class="demo-section">
7
+ <h1>On Load Animations</h1>
8
+ <p>Animations that play when the page loads.</p>
9
+
10
+ <div class="ot-demo">
11
+ <ot-tabs>
12
+ <div role="tablist" >
13
+ <button role="tab" aria-selected="true" tabindex="0">⧉ Preview</button>
14
+ <button role="tab" aria-selected="false" tabindex="-1">{} Code</button>
15
+ </div>
16
+
17
+ <!-- ⧉ Preview Tab -->
18
+ <div role="tabpanel">
19
+ <div class="row">
20
+ <article class="card col-4" ot-animate="fade-up">
21
+ <header>
22
+ <h3>fade-up</h3>
23
+ </header>
24
+ <p>Fades in while moving upward from below.</p>
25
+ <button class="demo-btn">Sample Button</button>
26
+ </article>
27
+ <article class="card col-4" ot-animate="fade-down">
28
+ <header>
29
+ <h3>fade-down</h3>
30
+ </header>
31
+ <p>Fades in while moving downward from above.</p>
32
+ <button class="demo-btn">Sample Button</button>
33
+ </article>
34
+ <article class="card col-4" ot-animate="slide-left">
35
+ <header>
36
+ <h3>slide-left</h3>
37
+ </header>
38
+ <p>Slides in from the right side.</p>
39
+ <button class="demo-btn">Sample Button</button>
40
+ </article>
41
+ <article class="card col-4" ot-animate="slide-right">
42
+ <header>
43
+ <h3>slide-right</h3>
44
+ </header>
45
+ <p>Slides in from the left side.</p>
46
+ <button class="demo-btn">Sample Button</button>
47
+ </article>
48
+ <article class="card col-4" ot-animate="zoom-in">
49
+ <header>
50
+ <h3>zoom-in</h3>
51
+ </header>
52
+ <p>Scales up from smaller to normal size.</p>
53
+ <button class="demo-btn">Sample Button</button>
54
+ </article>
55
+ <article class="card col-4" ot-animate="pop">
56
+ <header>
57
+ <h3>pop</h3>
58
+ </header>
59
+ <p>Quick scale bounce effect on load.</p>
60
+ <button class="demo-btn">Sample Button</button>
61
+ </article>
62
+ </div>
63
+ </div>
64
+
65
+ <!-- Code Tab -->
66
+ <div role="tabpanel" hidden="">
67
+ <pre class="giallo"><code>&lt;div ot-animate=&quot;fade-up&quot;&gt;Content&lt;/div&gt;
68
+ &lt;div ot-animate=&quot;fade-down&quot;&gt;Content&lt;/div&gt;
69
+ &lt;div ot-animate=&quot;slide-left&quot;&gt;Content&lt;/div&gt;
70
+ &lt;div ot-animate=&quot;slide-right&quot;&gt;Content&lt;/div&gt;
71
+ &lt;div ot-animate=&quot;zoom-in&quot;&gt;Content&lt;/div&gt;
72
+ &lt;div ot-animate=&quot;pop&quot;&gt;Content&lt;/div&gt;</code></pre>
73
+ </div>
74
+ </ot-tabs>
75
+ </div>
76
+ </section>
77
+
78
+ <!-- ON HOVER ANIMATIONS -->
79
+ <hr/>
80
+ <section id="onhover" class="demo-section">
81
+ <h1>On Hover Animations</h1>
82
+ <p>Animations that play on mouse hover.</p>
83
+
84
+ <div class="ot-demo">
85
+ <ot-tabs>
86
+ <div role="tablist">
87
+ <button role="tab" aria-selected="true" tabindex="0">⧉ Preview</button>
88
+ <button role="tab" aria-selected="false" tabindex="-1">{} Code</button>
89
+ </div>
90
+
91
+ <!-- ⧉ Preview Tab -->
92
+ <div role="tabpanel">
93
+ <div class="row">
94
+ <article class="card col-4" ot-animate="hover:fade-up">
95
+ <header>
96
+ <h3>hover:fade-up</h3>
97
+ </header>
98
+ <p>Fades in while moving upward on hover.</p>
99
+ <button class="demo-btn">Hover Me</button>
100
+ </article>
101
+ <article class="card col-4" ot-animate="hover:fade-down">
102
+ <header>
103
+ <h3>hover:fade-down</h3>
104
+ </header>
105
+ <p>Fades in while moving downward on hover.</p>
106
+ <button class="demo-btn">Hover Me</button>
107
+ </article>
108
+ <article class="card col-4" ot-animate="hover:slide-left">
109
+ <header>
110
+ <h3>hover:slide-left</h3>
111
+ </header>
112
+ <p>Slides left on hover from right.</p>
113
+ <button class="demo-btn">Hover Me</button>
114
+ </article>
115
+ <article class="card col-4" ot-animate="hover:slide-right">
116
+ <header>
117
+ <h3>hover:slide-right</h3>
118
+ </header>
119
+ <p>Slides right on hover from left.</p>
120
+ <button class="demo-btn">Hover Me</button>
121
+ </article>
122
+ <article class="card col-4" ot-animate="hover:zoom-in">
123
+ <header>
124
+ <h3>hover:zoom-in</h3>
125
+ </header>
126
+ <p>Scales up on hover for zoom effect.</p>
127
+ <button class="demo-btn">Hover Me</button>
128
+ </article>
129
+ <article class="card col-4" ot-animate="hover:pop">
130
+ <header>
131
+ <h3>hover:pop</h3>
132
+ </header>
133
+ <p>Quick bounce scale effect on hover.</p>
134
+ <button class="demo-btn">Hover Me</button>
135
+ </article>
136
+ </div>
137
+ </div>
138
+
139
+ <!-- Code Tab -->
140
+ <div role="tabpanel" hidden="">
141
+ <pre class="giallo"><code>&lt;div ot-animate=&quot;hover:fade-up&quot;&gt;Content&lt;/div&gt;
142
+ &lt;div ot-animate=&quot;hover:fade-down&quot;&gt;Content&lt;/div&gt;
143
+ &lt;div ot-animate=&quot;hover:slide-left&quot;&gt;Content&lt;/div&gt;
144
+ &lt;div ot-animate=&quot;hover:slide-right&quot;&gt;Content&lt;/div&gt;
145
+ &lt;div ot-animate=&quot;hover:zoom-in&quot;&gt;Content&lt;/div&gt;
146
+ &lt;div ot-animate=&quot;hover:pop&quot;&gt;Content&lt;/div&gt;</code></pre>
147
+ </div>
148
+ </ot-tabs>
149
+ </div>
150
+ </section>
151
+
152
+ <!-- IN VIEW ANIMATIONS -->
153
+ <hr/>
154
+ <section id="inview" class="demo-section">
155
+ <h1>In View Animations</h1>
156
+ <p>Animations that play when element scrolls into viewport.</p>
157
+
158
+ <div class="ot-demo">
159
+ <ot-tabs>
160
+ <div role="tablist">
161
+ <button role="tab" aria-selected="true" tabindex="0">⧉ Preview</button>
162
+ <button role="tab" aria-selected="false" tabindex="-1">{} Code</button>
163
+ </div>
164
+
165
+ <!-- ⧉ Preview Tab -->
166
+ <div role="tabpanel" class="align-items-center">
167
+ <div class="row">
168
+ <article class="card col-6" ot-animate="view:fade-up">
169
+ <header>
170
+ <h3>view:fade-up</h3>
171
+ </header>
172
+ <p>Triggers when scrolled into view from below.</p>
173
+ <button class="demo-btn">Scroll to See</button>
174
+ </article>
175
+ </div>
176
+ <br/>
177
+ <div class="row">
178
+ <article class="card col-6" ot-animate="view:fade-down">
179
+ <header>
180
+ <h3>view:fade-down</h3>
181
+ </header>
182
+ <p>Triggers when scrolled into view from above.</p>
183
+ <button class="demo-btn">Scroll to See</button>
184
+ </article>
185
+ </div>
186
+ <br/>
187
+ <div class="row">
188
+ <article class="card col-6" ot-animate="view:slide-left">
189
+ <header>
190
+ <h3>view:slide-left</h3>
191
+ </header>
192
+ <p>Triggers slide in from right on scroll.</p>
193
+ <button class="demo-btn">Scroll to See</button>
194
+ </article>
195
+ </div>
196
+ <br/>
197
+ <div class="row">
198
+ <article class="card col-6" ot-animate="view:slide-right">
199
+ <header>
200
+ <h3>view:slide-right</h3>
201
+ </header>
202
+ <p>Triggers slide in from left on scroll.</p>
203
+ <button class="demo-btn">Scroll to See</button>
204
+ </article>
205
+ </div>
206
+ <br/>
207
+ <div class="row">
208
+ <article class="card col-6" ot-animate="view:zoom-in">
209
+ <header>
210
+ <h3>view:zoom-in</h3>
211
+ </header>
212
+ <p>Triggers scale up effect when in viewport.</p>
213
+ <button class="demo-btn">Scroll to See</button>
214
+ </article>
215
+ </div>
216
+ <br/>
217
+ <div class="row">
218
+ <article class="card col-6" ot-animate="view:pop">
219
+ <header>
220
+ <h3>view:pop</h3>
221
+ </header>
222
+ <p>Triggers bounce effect when in viewport.</p>
223
+ <button class="demo-btn">Scroll to See</button>
224
+ </article>
225
+ </div>
226
+ </div>
227
+
228
+ <!-- Code Tab -->
229
+ <div role="tabpanel" hidden="">
230
+ <pre class="giallo"><code>&lt;div ot-animate=&quot;view:fade-up&quot;&gt;Content&lt;/div&gt;
231
+ &lt;div ot-animate=&quot;view:fade-down&quot;&gt;Content&lt;/div&gt;
232
+ &lt;div ot-animate=&quot;view:slide-left&quot;&gt;Content&lt;/div&gt;
233
+ &lt;div ot-animate=&quot;view:slide-right&quot;&gt;Content&lt;/div&gt;
234
+ &lt;div ot-animate=&quot;view:zoom-in&quot;&gt;Content&lt;/div&gt;
235
+ &lt;div ot-animate=&quot;view:pop&quot;&gt;Content&lt;/div&gt;</code></pre>
236
+ </div>
237
+ </ot-tabs>
238
+ </div>
239
+ </section>
240
+ `;
241
+ }
@@ -0,0 +1,31 @@
1
+ import { html } from "../template.js";
2
+
3
+ export function customizingPage() {
4
+ return html`
5
+ <p>Use data attributes to customize each animation instance.</p>
6
+
7
+ <section class="card vstack">
8
+ <h2>Supported Attributes</h2>
9
+ <ul>
10
+ <li><code>data-oa</code>: animation name (<code>fade-up</code>, <code>zoom-in</code>, <code>slide-left</code>, <code>pulse</code>, <code>shake</code>, <code>bounce</code>)</li>
11
+ <li><code>data-oa-trigger</code>: <code>load</code>, <code>hover</code>, <code>inview</code></li>
12
+ <li><code>data-oa-duration</code>: duration in ms</li>
13
+ <li><code>data-oa-delay</code>: delay in ms</li>
14
+ <li><code>data-oa-easing</code>: CSS timing function</li>
15
+ </ul>
16
+ </section>
17
+
18
+ <section class="card vstack">
19
+ <h2>Example</h2>
20
+ <pre><code>&lt;div
21
+ data-oa=\"fade-up\"
22
+ data-oa-trigger=\"inview\"
23
+ data-oa-duration=\"900\"
24
+ data-oa-delay=\"120\"
25
+ data-oa-easing=\"cubic-bezier(0.2, 0.8, 0.2, 1)\"
26
+ &gt;
27
+ Animated content
28
+ &lt;/div&gt;</code></pre>
29
+ </section>
30
+ `;
31
+ }
@@ -0,0 +1,36 @@
1
+ import { html } from "../template.js";
2
+
3
+ export function homePage() {
4
+ return html`
5
+ <section class="vstack p-4">
6
+ <br />
7
+ <img
8
+ src="/public/assets/logo.svg"
9
+ alt="oat animate"
10
+ width="220 "
11
+ height="100"
12
+ />
13
+ <div class="p-4 row gap-2">
14
+ <h1 class="col title mb-2 mt-2">Oat Animate</h1>
15
+ <h3 class="col slogan text-light mb-2 mt-2">
16
+ Ultra-lightweight CSS animation extension for Oat
17
+ </h3>
18
+ <p class="col-9">
19
+ Oat Animate is an ultra-lightweight extension for Oat, designed to add micro-interactions and animation capabilities to your web projects with ease. Built for simplicity, it integrates seamlessly with Oat’s semantic UI components, requiring no extra dependencies or complex setup. Just include the extension and start animating.
20
+ </p>
21
+ <p class="col-9">
22
+ With a minimal footprint and a straightforward API, Oat Animate lets you create stunning, customizable CSS animations using simple data attributes. Choose from a wide range of effects-fade, slide, bounce, and more - to enhance user experience and bring your components to life with minimal effort.
23
+ </p>
24
+ </p>
25
+ <br />
26
+ <br />
27
+ <div class="col hstack">
28
+ <a href="/animations" class="button ">Browse animations</a>
29
+ <a href="/usage" class="button outline">Get started</a>
30
+ </div>
31
+ </div>
32
+ <br/>
33
+ <br/>
34
+ </section>
35
+ `;
36
+ }
@@ -0,0 +1,195 @@
1
+ import { html, raw } from "../template.js";
2
+
3
+ export function showcasePage() {
4
+ return html`
5
+ <!-- Finance Dashboard Showcase -->
6
+ <section id="dashboard" class="demo-section w-100">
7
+ <h1 ot-animate="fade-up">Finance Dashboard</h1>
8
+ <p ot-animate="fade-up" class="mb-4">A sample finance dashboard built with OAT animations.</p>
9
+
10
+ <!-- Stats Cards Row -->
11
+ <div class="row mb-4">
12
+ <div class="col-3">
13
+ <article class="card p-4" ot-animate="fade-up" style="animation-delay: 0.1s">
14
+ <small class="text-muted">Total Revenue</small>
15
+ <h2 class="m-0">$124,563</h2>
16
+ <small class="text-success">+12.5%</small>
17
+ </article>
18
+ </div>
19
+ <div class="col-3">
20
+ <article class="card p-4" ot-animate="fade-up" style="animation-delay: 0.2s">
21
+ <small class="text-muted">Expenses</small>
22
+ <h2 class="m-0">$45,231</h2>
23
+ <small class="text-danger">+3.2%</small>
24
+ </article>
25
+ </div>
26
+ <div class="col-3">
27
+ <article class="card p-4" ot-animate="fade-up" style="animation-delay: 0.3s">
28
+ <small class="text-muted">Net Profit</small>
29
+ <h2 class="m-0">$79,332</h2>
30
+ <small class="text-success">+18.7%</small>
31
+ </article>
32
+ </div>
33
+ <div class="col-3">
34
+ <article class="card p-4" ot-animate="fade-up" style="animation-delay: 0.4s">
35
+ <small class="text-muted">Savings Rate</small>
36
+ <h2 class="m-0">23.4%</h2>
37
+ <small class="text-success">+2.1%</small>
38
+ </article>
39
+ </div>
40
+ </div>
41
+
42
+ <!-- Charts Row -->
43
+ <div class="row mb-4">
44
+ <div class="col-8">
45
+ <article class="card p-4" ot-animate="slide-left" style="animation-delay: 0.5s">
46
+ <header class="mb-4">
47
+ <h3>Revenue Trend</h3>
48
+ </header>
49
+ <div class="chart-placeholder h-4 bg-light rounded">
50
+ <div class="row align-items-end h-100 p-2">
51
+ <div class="col" style="height: 40%"><div class="bg-primary h-100 rounded"></div></div>
52
+ <div class="col" style="height: 60%"><div class="bg-primary h-100 rounded"></div></div>
53
+ <div class="col" style="height: 45%"><div class="bg-primary h-100 rounded"></div></div>
54
+ <div class="col" style="height: 80%"><div class="bg-primary h-100 rounded"></div></div>
55
+ <div class="col" style="height: 70%"><div class="bg-primary h-100 rounded"></div></div>
56
+ <div class="col" style="height: 90%"><div class="bg-primary h-100 rounded"></div></div>
57
+ <div class="col" style="height: 75%"><div class="bg-primary h-100 rounded"></div></div>
58
+ <div class="col" style="height: 85%"><div class="bg-primary h-100 rounded"></div></div>
59
+ <div class="col" style="height: 65%"><div class="bg-primary h-100 rounded"></div></div>
60
+ <div class="col" style="height: 95%"><div class="bg-primary h-100 rounded"></div></div>
61
+ <div class="col" style="height: 88%"><div class="bg-primary h-100 rounded"></div></div>
62
+ <div class="col" style="height: 100%"><div class="bg-primary h-100 rounded"></div></div>
63
+ </div>
64
+ </div>
65
+ <div class="row mt-2">
66
+ <div class="col-6"><small class="text-muted">Jan - Jun 2024</small></div>
67
+ <div class="col-6 text-end"><small class="text-muted">$92,450 Total</small></div>
68
+ </div>
69
+ </article>
70
+ </div>
71
+ <div class="col-4">
72
+ <article class="card p-4" ot-animate="slide-right" style="animation-delay: 0.6s">
73
+ <header class="mb-4">
74
+ <h3>Expense Breakdown</h3>
75
+ </header>
76
+ <div class="text-center mb-4">
77
+ <div class="donut-chart" style="width: 120px; height: 120px; border-radius: 50%; background: conic-gradient(var(--primary) 0deg 140deg, var(--success) 140deg 220deg, var(--warning) 220deg 280deg, var(--danger) 280deg 360deg); margin: 0 auto;"></div>
78
+ <div class="mt-2"><small class="text-muted">$45,231 Total</small></div>
79
+ </div>
80
+ <div class="vstack gap-2">
81
+ <div class="hstack justify-content-between">
82
+ <span class="dot bg-primary"></span><small>Operations</small><small class="text-muted">38%</small>
83
+ </div>
84
+ <div class="hstack justify-content-between">
85
+ <span class="dot bg-success"></span><small>Marketing</small><small class="text-muted">22%</small>
86
+ </div>
87
+ <div class="hstack justify-content-between">
88
+ <span class="dot bg-warning"></span><small>R&D</small><small class="text-muted">17%</small>
89
+ </div>
90
+ <div class="hstack justify-content-between">
91
+ <span class="dot bg-danger"></span><small>Admin</small><small class="text-muted">23%</small>
92
+ </div>
93
+ </div>
94
+ </article>
95
+ </div>
96
+ </div>
97
+
98
+ <!-- Transactions Table -->
99
+ <div class="row">
100
+ <div class="col-12">
101
+ <article class="card p-4" ot-animate="fade-up" style="animation-delay: 0.7s">
102
+ <header class="mb-4">
103
+ <h3>Recent Transactions</h3>
104
+ </header>
105
+ <table class="w-100">
106
+ <thead>
107
+ <tr class="border-bottom">
108
+ <th class="p-2 text-start">Date</th>
109
+ <th class="p-2 text-start">Description</th>
110
+ <th class="p-2 text-start">Category</th>
111
+ <th class="p-2 text-end">Amount</th>
112
+ <th class="p-2 text-end">Status</th>
113
+ </tr>
114
+ </thead>
115
+ <tbody>
116
+ <tr class="border-bottom" ot-animate="slide-left" style="animation-delay: 0.8s">
117
+ <td class="p-2"><small>Dec 15, 2024</small></td>
118
+ <td class="p-2">Enterprise License - Q1</td>
119
+ <td class="p-2"><span class="badge bg-primary">Software</span></td>
120
+ <td class="p-2 text-end text-success">+$12,500</td>
121
+ <td class="p-2 text-end"><span class="badge bg-success">Completed</span></td>
122
+ </tr>
123
+ <tr class="border-bottom" ot-animate="slide-left" style="animation-delay: 0.85s">
124
+ <td class="p-2"><small>Dec 14, 2024</small></td>
125
+ <td class="p-2">Cloud Hosting - AWS</td>
126
+ <td class="p-2"><span class="badge bg-warning">Infrastructure</span></td>
127
+ <td class="p-2 text-end text-danger">-$2,340</td>
128
+ <td class="p-2 text-end"><span class="badge bg-success">Completed</span></td>
129
+ </tr>
130
+ <tr class="border-bottom" ot-animate="slide-left" style="animation-delay: 0.9s">
131
+ <td class="p-2"><small>Dec 13, 2024</small></td>
132
+ <td class="p-2">Consulting Services</td>
133
+ <td class="p-2"><span class="badge bg-info">Professional</span></td>
134
+ <td class="p-2 text-end text-success">+$8,500</td>
135
+ <td class="p-2 text-end"><span class="badge bg-success">Completed</span></td>
136
+ </tr>
137
+ <tr class="border-bottom" ot-animate="slide-left" style="animation-delay: 0.95s">
138
+ <td class="p-2"><small>Dec 12, 2024</small></td>
139
+ <td class="p-2">Office Supplies</td>
140
+ <td class="p-2"><span class="badge bg-secondary">Operations</span></td>
141
+ <td class="p-2 text-end text-danger">-$456</td>
142
+ <td class="p-2 text-end"><span class="badge bg-warning">Pending</span></td>
143
+ </tr>
144
+ <tr ot-animate="slide-left" style="animation-delay: 1s">
145
+ <td class="p-2"><small>Dec 11, 2024</small></td>
146
+ <td class="p-2">Marketing Campaign</td>
147
+ <td class="p-2"><span class="badge bg-danger">Marketing</span></td>
148
+ <td class="p-2 text-end text-danger">-$3,200</td>
149
+ <td class="p-2 text-end"><span class="badge bg-success">Completed</span></td>
150
+ </tr>
151
+ </tbody>
152
+ </table>
153
+ </article>
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Quick Actions -->
158
+ <div class="row mt-4">
159
+ <div class="col-12">
160
+ <div class="hstack gap-2" ot-animate="zoom-in" style="animation-delay: 1.1s">
161
+ <button class="demo-btn primary">Export Report</button>
162
+ <button class="demo-btn outline">Add Transaction</button>
163
+ <button class="demo-btn outline">Generate Invoice</button>
164
+ <button class="demo-btn outline">Schedule Payment</button>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ </section>
169
+
170
+ <style>
171
+ .text-muted { color: var(--muted-color, #6c757d); }
172
+ .text-success { color: var(--success-color, #28a745); }
173
+ .text-danger { color: var(--danger-color, #dc3545); }
174
+ .bg-primary { background: var(--primary-color, #0d6efd); }
175
+ .bg-success { background: var(--success-color, #28a745); }
176
+ .bg-warning { background: var(--warning-color, #ffc107); }
177
+ .bg-danger { background: var(--danger-color, #dc3545); }
178
+ .bg-info { background: var(--info-color, #17a2b8); }
179
+ .bg-light { background: var(--bg-secondary, #f8f9fa); }
180
+ .bg-secondary { background: #6c757d; }
181
+ .text-start { text-align: left; }
182
+ .text-end { text-align: right; }
183
+ .border-bottom { border-bottom: 1px solid var(--border-color, #dee2e6); }
184
+ .rounded { border-radius: 4px; }
185
+ .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 8px; }
186
+ .badge { padding: 4px 8px; border-radius: 4px; font-size: 12px; color: white; }
187
+ .donut-chart { position: relative; }
188
+ .donut-chart::after { content: ''; position: absolute; top: 20%; left: 20%; width: 60%; height: 60%; background: var(--bg-color, white); border-radius: 50%; }
189
+ .h-100 { height: 100%; }
190
+ .h-4 { height: 200px; }
191
+ .align-items-end { align-items: flex-end; }
192
+ .justify-content-between { justify-content: space-between; }
193
+ </style>
194
+ `;
195
+ }
@@ -0,0 +1,64 @@
1
+ import { html } from "../template.js";
2
+
3
+ export function usage() {
4
+ return html`
5
+ <h1>Installation and usage</h1>
6
+ <p>Add animations to any element using the <code>ot-animate</code> attribute.</p>
7
+
8
+ <section class="vstack">
9
+ <h2>Include Files</h2>
10
+ <pre><code>&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/ot-animate/dist/ot-animate.min.css&quot;&gt;
11
+ &lt;script src=&quot;https://cdn.jsdelivr.net/npm/ot-animate/dist/ot-animate.min.js&quot;&gt;&lt;/script&gt;
12
+ </code></pre>
13
+ </section>
14
+
15
+ <section class="vstack">
16
+ <h2>Animation Types</h2>
17
+ <p>Available animations:</p>
18
+ <ul>
19
+ <li><code>fade-up</code> - Fades in while moving upward</li>
20
+ <li><code>fade-down</code> - Fades in while moving downward</li>
21
+ <li><code>zoom-in</code> - Scales up from smaller size</li>
22
+ <li><code>slide-left</code> - Slides in from right</li>
23
+ <li><code>slide-right</code> - Slides in from left</li>
24
+ <li><code>pop</code> - Quick bounce scale effect</li>
25
+ <li><code>bounce</code> - Bouncing movement</li>
26
+ <li><code>flip-in</code> - 3D flip effect</li>
27
+ <li><code>pulse</code> - Pulsing scale animation (loops)</li>
28
+ <li><code>shake</code> - Horizontal shake effect</li>
29
+ </ul>
30
+ </section>
31
+
32
+ <section class="vstack">
33
+ <h2>On Load Animation</h2>
34
+ <p>Animation plays when page loads:</p>
35
+ <pre><code>
36
+ &lt;div ot-animate=&quot;fade-up&quot;&gt;Content&lt;/div&gt;
37
+ </code></pre>
38
+ </section>
39
+
40
+ <section class="vstack">
41
+ <h2>On Hover Animation</h2>
42
+ <p>Animation plays on mouse hover:</p>
43
+ <pre><code>
44
+ &lt;div ot-animate=&quot;hover:fade-up&quot;&gt;Content&lt;/div&gt;
45
+ </code></pre>
46
+ </section>
47
+
48
+ <section class="vstack">
49
+ <h2>In View Animation</h2>
50
+ <p>Animation plays when element scrolls into viewport:</p>
51
+ <pre><code>
52
+ &lt;div ot-animate=&quot;view:fade-up&quot;&gt;Content&lt;/div&gt;
53
+ </code></pre>
54
+ </section>
55
+
56
+ <section class="vstack">
57
+ <h2>Multiple Animations</h2>
58
+ <p>Combine multiple animations on a single element:</p>
59
+ <pre><code>
60
+ &lt;div ot-animate=&quot;fade-up hover:zoom-in&quot;&gt;Content&lt;/div&gt;
61
+ </code></pre>
62
+ </section>
63
+ `;
64
+ }
@@ -0,0 +1,124 @@
1
+ function escapeHtml(value) {
2
+ return String(value)
3
+ .replaceAll("&", "&amp;")
4
+ .replaceAll("<", "&lt;")
5
+ .replaceAll(">", "&gt;")
6
+ .replaceAll('"', "&quot;")
7
+ .replaceAll("'", "&#39;");
8
+ }
9
+
10
+ export function raw(value) {
11
+ return { __raw: String(value) };
12
+ }
13
+
14
+ export function html(strings, ...values) {
15
+ let out = "";
16
+ for (let i = 0; i < strings.length; i += 1) {
17
+ out += strings[i];
18
+ if (i < values.length) {
19
+ const value = values[i];
20
+ if (value && typeof value === "object" && "__raw" in value) {
21
+ out += value.__raw;
22
+ } else {
23
+ out += escapeHtml(value ?? "");
24
+ }
25
+ }
26
+ }
27
+ return out;
28
+ }
29
+
30
+ export function layoutTemplate({ title, content, activePath = "/" }) {
31
+ const navLink = (href, label) => {
32
+ const selected = activePath === href ? ' aria-current="page"' : "";
33
+ return `<a href="${href}" data-route="#${href}"${selected}>${label}</a>`;
34
+ };
35
+
36
+ return html`
37
+ <div data-sidebar-layout="always">
38
+ <nav data-topnav class="hstack">
39
+ <img src="/public/assets/logo.svg" alt="Logo" width="100" height="40" />
40
+ <div class="hstack"></div>
41
+ </nav>
42
+
43
+ <aside data-sidebar>
44
+ <nav>
45
+ <ul>
46
+ <ul>
47
+ <li>
48
+ <a href="https://github.com/dharmeshgurnani/oat-animated" target="_blank"
49
+ ><img src="/public/assets/github.svg" alt="GitHub icon" /> GitHub</a
50
+ >
51
+ </li>
52
+ <li>${raw(navLink("/", "Home"))}</li>
53
+ <li>${raw(navLink("/usage", "Usage"))}</li>
54
+ <li>${raw(navLink("/customizing", "customizing"))}</li>
55
+ <li>
56
+ <details open="">
57
+ <summary>
58
+ <svg
59
+ width="16"
60
+ height="16"
61
+ viewBox="0 0 24 24"
62
+ fill="none"
63
+ stroke="currentColor"
64
+ stroke-width="1"
65
+ >
66
+ <rect x="3" y="3" width="7" height="7"></rect>
67
+ <rect x="14" y="3" width="7" height="7"></rect>
68
+ <rect x="14" y="14" width="7" height="7"></rect>
69
+ <rect x="3" y="14" width="7" height="7"></rect>
70
+ </svg>
71
+ Animations
72
+ </summary>
73
+ <ul>
74
+ <li>${raw(navLink("/animations#onload", "On load"))}</li>
75
+ <li>${raw(navLink("/animations#onhover", "On Hover"))}</li>
76
+ <li>${raw(navLink("/animations#inview", "In View"))}</li>
77
+ </ul>
78
+ </details>
79
+ </li>
80
+ </ul>
81
+ </ul>
82
+ </nav>
83
+ <footer class=""><button class="w-100 outline small" onclick="toggleTheme()">
84
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="icon-light">
85
+ <circle cx="12" cy="12" r="5"></circle>
86
+ <line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line>
87
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
88
+ <line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line>
89
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
90
+ </svg>
91
+
92
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="icon-dark">
93
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
94
+ </svg>
95
+
96
+ Switch theme
97
+ </button></footer>
98
+ </aside>
99
+
100
+ <main class="wrap">
101
+ <div class="container m-4 p-4">
102
+ <br/>
103
+ ${raw(content)}
104
+ </div>
105
+ <footer class="hstack p-4">
106
+ <small class="p-4">👾 @dharmeshgurnani</small>
107
+ </footer>
108
+ </main>
109
+ </div>
110
+ `;
111
+ }
112
+
113
+ export function withLayout(pageView, title) {
114
+ const activePath = window.location.hash.startsWith("#/")
115
+ ? window.location.hash.slice(1)
116
+ : window.location.pathname;
117
+
118
+ return (ctx) =>
119
+ layoutTemplate({
120
+ title,
121
+ content: pageView(ctx),
122
+ activePath,
123
+ });
124
+ }