A fast, local-first "redirection engine" for !bang users with a few extra features ^-^

chore: prevent style flashes and add dark theme

+211 -156
+2 -1
index.html
··· 24 24 media="print" 25 25 onload="this.media='all'" 26 26 /> 27 + <link rel="stylesheet" href="/global.css" /> 27 28 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 28 29 <title>Unduck</title> 29 30 <meta ··· 31 32 content="A better default search engine (with bangs!)" 32 33 /> 33 34 </head> 34 - <body style="background-color: transparent"> 35 + <body> 35 36 <div id="app"></div> 36 37 <script type="module" src="/src/main.ts"></script> 37 38 </body>
+17 -1
public/clipboard-check.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clipboard-check"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="m9 14 2 2 4-4"/></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clipboard-check"> 2 + <style> 3 + @media (prefers-color-scheme: light) { 4 + .lucide-clipboard-check { 5 + stroke: #1a1a1a; 6 + } 7 + } 8 + @media (prefers-color-scheme: dark) { 9 + .lucide-clipboard-check { 10 + stroke: #e0e0e0; 11 + } 12 + } 13 + </style> 14 + <rect width="8" height="4" x="8" y="2" rx="1" ry="1"/> 15 + <path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/> 16 + <path d="m9 14 2 2 4-4"/> 17 + </svg>
+16 -1
public/clipboard.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clipboard"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clipboard"> 2 + <style> 3 + @media (prefers-color-scheme: light) { 4 + .lucide-clipboard { 5 + stroke: #1a1a1a; 6 + } 7 + } 8 + @media (prefers-color-scheme: dark) { 9 + .lucide-clipboard { 10 + stroke: #e0e0e0; 11 + } 12 + } 13 + </style> 14 + <rect width="8" height="4" x="8" y="2" rx="1" ry="1"/> 15 + <path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/> 16 + </svg>
+176
public/global.css
··· 1 + /* @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"); */ 2 + 3 + /* Font fallback that closely matches Inter metrics */ 4 + @font-face { 5 + font-family: "Inter Fallback"; 6 + size-adjust: 107%; 7 + ascent-override: 90%; 8 + src: local("Arial"); 9 + } 10 + 11 + :root { 12 + font-family: 13 + Inter, 14 + "Inter Fallback", 15 + system-ui, 16 + -apple-system, 17 + BlinkMacSystemFont, 18 + "Segoe UI", 19 + Roboto, 20 + Oxygen, 21 + Ubuntu, 22 + Cantarell, 23 + "Open Sans", 24 + "Helvetica Neue", 25 + sans-serif; 26 + font-synthesis: none; 27 + text-rendering: optimizeLegibility; 28 + -webkit-font-smoothing: antialiased; 29 + -moz-osx-font-smoothing: grayscale; 30 + 31 + /* Light mode colors */ 32 + --text-color: #1a1a1a; 33 + --text-color-secondary: #666; 34 + --text-color-hover: #333; 35 + --bg-color: #fff; 36 + --bg-color-secondary: #f5f5f5; 37 + --bg-color-hover: #f0f0f0; 38 + --bg-color-active: #e5e5e5; 39 + --border-color: #ddd; 40 + } 41 + 42 + @media (prefers-color-scheme: dark) { 43 + :root { 44 + --text-color: #e0e0e0; 45 + --text-color-secondary: #999; 46 + --text-color-hover: #fff; 47 + --bg-color: #121212; 48 + --bg-color-secondary: #1e1e1e; 49 + --bg-color-hover: #2a2a2a; 50 + --bg-color-active: #333; 51 + --border-color: #444; 52 + } 53 + } 54 + 55 + * { 56 + margin: 0; 57 + padding: 0; 58 + box-sizing: border-box; 59 + } 60 + 61 + html, 62 + body { 63 + height: 100%; 64 + width: 100%; 65 + } 66 + 67 + body { 68 + line-height: 1.5; 69 + font-weight: 400; 70 + font-size: 16px; 71 + color: var(--text-color); 72 + background-color: var(--bg-color); 73 + } 74 + 75 + h1, 76 + h2, 77 + h3, 78 + h4, 79 + h5, 80 + h6 { 81 + font-weight: 600; 82 + line-height: 1.2; 83 + padding: 0.75rem; 84 + } 85 + 86 + a { 87 + color: var(--text-color-secondary); 88 + } 89 + a:hover { 90 + color: var(--text-color-hover); 91 + } 92 + 93 + button { 94 + font: inherit; 95 + border: none; 96 + background: none; 97 + cursor: pointer; 98 + } 99 + 100 + input, 101 + textarea { 102 + font: inherit; 103 + } 104 + 105 + /* Add these new styles */ 106 + .url-container { 107 + display: flex; 108 + align-items: center; 109 + gap: 8px; 110 + margin-top: 16px; 111 + } 112 + 113 + /* Add this new style */ 114 + .content-container { 115 + max-width: 37rem; 116 + text-align: center; 117 + padding: 0 8px; 118 + } 119 + 120 + /* Update url-input width to be 100% since container will control max width */ 121 + .url-input { 122 + padding: 8px 12px; 123 + border: 1px solid var(--border-color); 124 + border-radius: 4px; 125 + width: 100%; 126 + background: var(--bg-color-secondary); 127 + color: var(--text-color); 128 + } 129 + 130 + .copy-button { 131 + padding: 8px; 132 + color: var(--text-color-secondary); 133 + border-radius: 4px; 134 + transition: all 0.2s; 135 + display: flex; 136 + align-items: center; 137 + justify-content: center; 138 + } 139 + 140 + .copy-button:hover { 141 + background: var(--bg-color-hover); 142 + } 143 + 144 + .copy-button:active { 145 + background: var(--bg-color-active); 146 + } 147 + 148 + .copy-button img { 149 + width: 20px; 150 + height: 20px; 151 + } 152 + 153 + .copy-button.copied { 154 + background: #28a745; 155 + } 156 + 157 + /* Add footer styles */ 158 + .footer { 159 + position: fixed; 160 + bottom: 16px; 161 + left: 0; 162 + right: 0; 163 + text-align: center; 164 + font-size: 14px; 165 + color: var(--text-color-secondary); 166 + } 167 + 168 + .footer a { 169 + color: var(--text-color-secondary); 170 + text-decoration: none; 171 + font-weight: 500; 172 + } 173 + 174 + .footer a:hover { 175 + color: var(--text-color-hover); 176 + }
-1
public/search.svg
··· 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 2 <svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg"> 3 - <rect width="1200" height="1200" fill="black"/> 4 3 <path fill="white" d="m980.48 905.76-198.84-199.08c89.203-125.34 77.953-300.14-34.406-412.64-125.26-125.44-328.03-125.44-453.32 0-125.26 125.44-125.26 328.45 0 453.84 112.36 112.5 286.97 123.74 412.18 34.406l198.84 199.08c53.25 53.297 132.05-19.078 75.562-75.609zm-610.87-233.58c-83.391-83.531-83.391-218.86 0-302.39s218.58-83.531 302.02 0c83.391 83.531 83.391 218.86 0 302.39-83.438 83.484-218.63 83.484-302.02 0z"/> 5 4 </svg>
-151
src/global.css
··· 1 - /* @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"); */ 2 - 3 - /* Font fallback that closely matches Inter metrics */ 4 - @font-face { 5 - font-family: "Inter Fallback"; 6 - size-adjust: 107%; 7 - ascent-override: 90%; 8 - src: local("Arial"); 9 - } 10 - 11 - :root { 12 - font-family: 13 - Inter, 14 - "Inter Fallback", 15 - system-ui, 16 - -apple-system, 17 - BlinkMacSystemFont, 18 - "Segoe UI", 19 - Roboto, 20 - Oxygen, 21 - Ubuntu, 22 - Cantarell, 23 - "Open Sans", 24 - "Helvetica Neue", 25 - sans-serif; 26 - font-synthesis: none; 27 - text-rendering: optimizeLegibility; 28 - -webkit-font-smoothing: antialiased; 29 - -moz-osx-font-smoothing: grayscale; 30 - } 31 - 32 - * { 33 - margin: 0; 34 - padding: 0; 35 - box-sizing: border-box; 36 - } 37 - 38 - html, 39 - body { 40 - height: 100%; 41 - width: 100%; 42 - } 43 - 44 - body { 45 - line-height: 1.5; 46 - font-weight: 400; 47 - font-size: 16px; 48 - color: #1a1a1a; 49 - } 50 - 51 - h1, 52 - h2, 53 - h3, 54 - h4, 55 - h5, 56 - h6 { 57 - font-weight: 600; 58 - line-height: 1.2; 59 - padding: 0.75rem; 60 - } 61 - 62 - a { 63 - color: #444444; 64 - } 65 - a:hover { 66 - color: #888888; 67 - } 68 - 69 - button { 70 - font: inherit; 71 - border: none; 72 - background: none; 73 - cursor: pointer; 74 - } 75 - 76 - input, 77 - textarea { 78 - font: inherit; 79 - } 80 - 81 - /* Add these new styles */ 82 - .url-container { 83 - display: flex; 84 - align-items: center; 85 - gap: 8px; 86 - margin-top: 16px; 87 - } 88 - 89 - /* Add this new style */ 90 - .content-container { 91 - max-width: 37rem; 92 - text-align: center; 93 - padding: 0 8px; 94 - } 95 - 96 - /* Update url-input width to be 100% since container will control max width */ 97 - .url-input { 98 - padding: 8px 12px; 99 - border: 1px solid #ddd; 100 - border-radius: 4px; 101 - width: 100%; 102 - background: #f5f5f5; 103 - } 104 - 105 - .copy-button { 106 - padding: 8px; 107 - color: #666; 108 - border-radius: 4px; 109 - transition: all 0.2s; 110 - display: flex; 111 - align-items: center; 112 - justify-content: center; 113 - } 114 - 115 - .copy-button:hover { 116 - background: #f0f0f0; 117 - } 118 - 119 - .copy-button:active { 120 - background: #e5e5e5; 121 - } 122 - 123 - .copy-button img { 124 - width: 20px; 125 - height: 20px; 126 - } 127 - 128 - .copy-button.copied { 129 - background: #28a745; 130 - } 131 - 132 - /* Add footer styles */ 133 - .footer { 134 - position: fixed; 135 - bottom: 16px; 136 - left: 0; 137 - right: 0; 138 - text-align: center; 139 - font-size: 14px; 140 - color: #666; 141 - } 142 - 143 - .footer a { 144 - color: #666; 145 - text-decoration: none; 146 - font-weight: 500; 147 - } 148 - 149 - .footer a:hover { 150 - color: #333; 151 - }
-1
src/main.ts
··· 1 1 import { bangs } from "./bang"; 2 - import "./global.css"; 3 2 4 3 function noSearchDefaultPageRender() { 5 4 const app = document.querySelector<HTMLDivElement>("#app");