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

chore: combat cache issues

Changed files
+371 -2
src
+61 -2
index.html
···
media="print"
onload="this.media='all'"
/>
-
<link rel="preload" href="/global.css" as="style" />
-
<link rel="stylesheet" href="/global.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Unduck</title>
<meta
···
media="print"
onload="this.media='all'"
/>
+
<style>
+
:root {
+
/* Light mode colors */
+
--text-color: #1a1a1a;
+
--text-color-secondary: #666;
+
--text-color-hover: #333;
+
--bg-color: #fff;
+
--bg-color-secondary: #f5f5f5;
+
--bg-color-hover: #f0f0f0;
+
--bg-color-active: #e5e5e5;
+
--border-color: #ddd;
+
}
+
+
@media (prefers-color-scheme: dark) {
+
:root {
+
--text-color: #e0e0e0;
+
--text-color-secondary: #999;
+
--text-color-hover: #fff;
+
--bg-color: #121212;
+
--bg-color-secondary: #1e1e1e;
+
--bg-color-hover: #2a2a2a;
+
--bg-color-active: #333;
+
--border-color: #444;
+
}
+
}
+
+
* {
+
margin: 0;
+
padding: 0;
+
box-sizing: border-box;
+
}
+
+
body {
+
font-family: system-ui, sans-serif;
+
line-height: 1.5;
+
color: var(--text-color);
+
background-color: var(--bg-color);
+
}
+
+
input {
+
padding: 8px 12px;
+
border: 1px solid var(--border-color);
+
border-radius: 4px;
+
width: 100%;
+
background: var(--bg-color-secondary);
+
color: var(--text-color);
+
font: inherit;
+
}
+
+
button {
+
font: inherit;
+
border: none;
+
background: none;
+
cursor: pointer;
+
color: var(--text-color-secondary);
+
}
+
+
button:hover {
+
background: var(--bg-color-hover);
+
}
+
</style>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Unduck</title>
<meta
+309
src/global.css
···
···
+
/* @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"); */
+
+
/* Font fallback that closely matches Inter metrics */
+
@font-face {
+
font-family: "Inter Fallback";
+
size-adjust: 107%;
+
ascent-override: 90%;
+
src: local("Arial");
+
}
+
+
:root {
+
font-family:
+
Inter,
+
"Inter Fallback",
+
system-ui,
+
-apple-system,
+
BlinkMacSystemFont,
+
"Segoe UI",
+
Roboto,
+
Oxygen,
+
Ubuntu,
+
Cantarell,
+
"Open Sans",
+
"Helvetica Neue",
+
sans-serif;
+
font-synthesis: none;
+
text-rendering: optimizeLegibility;
+
-webkit-font-smoothing: antialiased;
+
-moz-osx-font-smoothing: grayscale;
+
+
/* Light mode colors */
+
--text-color: #1a1a1a;
+
--text-color-secondary: #666;
+
--text-color-hover: #333;
+
--bg-color: #fff;
+
--bg-color-secondary: #f5f5f5;
+
--bg-color-hover: #f0f0f0;
+
--bg-color-active: #e5e5e5;
+
--border-color: #ddd;
+
}
+
+
@media (prefers-color-scheme: dark) {
+
:root {
+
--text-color: #e0e0e0;
+
--text-color-secondary: #999;
+
--text-color-hover: #fff;
+
--bg-color: #121212;
+
--bg-color-secondary: #1e1e1e;
+
--bg-color-hover: #2a2a2a;
+
--bg-color-active: #333;
+
--border-color: #444;
+
}
+
}
+
+
* {
+
margin: 0;
+
padding: 0;
+
box-sizing: border-box;
+
outline: none;
+
}
+
+
*:focus {
+
border: 2px solid var(--text-color-secondary);
+
}
+
+
html,
+
body {
+
height: 100%;
+
width: 100%;
+
}
+
+
body {
+
line-height: 1.5;
+
font-weight: 400;
+
font-size: 16px;
+
color: var(--text-color);
+
background-color: var(--bg-color);
+
}
+
+
h1,
+
h2,
+
h3,
+
h4,
+
h5,
+
h6 {
+
font-weight: 600;
+
line-height: 1.2;
+
padding-bottom: 0.75rem;
+
}
+
+
a {
+
color: var(--text-color-secondary);
+
}
+
a:hover {
+
color: var(--text-color-hover);
+
}
+
+
button {
+
font: inherit;
+
border: none;
+
background: none;
+
cursor: pointer;
+
}
+
+
input,
+
textarea {
+
font: inherit;
+
}
+
+
/* Add these new styles */
+
.url-container {
+
display: flex;
+
align-items: center;
+
gap: 8px;
+
margin-top: 16px;
+
}
+
+
/* Add this new style */
+
.content-container {
+
max-width: 37rem;
+
text-align: center;
+
padding: 0 8px;
+
}
+
+
/* Update url-input width to be 100% since container will control max width */
+
input {
+
padding: 8px 12px;
+
border: 1px solid var(--border-color);
+
border-radius: 4px;
+
width: 100%;
+
background: var(--bg-color-secondary);
+
color: var(--text-color);
+
}
+
+
.copy-button {
+
padding: 8px;
+
color: var(--text-color-secondary);
+
border-radius: 4px;
+
transition: all 0.2s;
+
display: flex;
+
align-items: center;
+
justify-content: center;
+
}
+
+
.copy-button:hover {
+
background: var(--bg-color-hover);
+
}
+
+
.copy-button:active {
+
background: var(--bg-color-active);
+
}
+
+
.copy-button img {
+
width: 20px;
+
height: 20px;
+
}
+
+
.copy-button.copied {
+
background: #28a745;
+
}
+
+
/* Add footer styles */
+
.footer {
+
position: fixed;
+
bottom: 16px;
+
left: 0;
+
right: 0;
+
text-align: center;
+
font-size: 14px;
+
color: var(--text-color-secondary);
+
}
+
+
.footer a {
+
color: var(--text-color-secondary);
+
text-decoration: none;
+
font-weight: 500;
+
}
+
+
.footer a:hover {
+
color: var(--text-color-hover);
+
}
+
+
/* Add styles for the settings button */
+
.settings-button {
+
padding: 8px;
+
color: var(--text-color-secondary);
+
border-radius: 4px;
+
transition: all 0.2s;
+
display: flex;
+
align-items: center;
+
justify-content: center;
+
}
+
+
.settings-button:hover {
+
background: var(--bg-color-hover);
+
}
+
+
.settings-button:hover {
+
background: var(--bg-color-active);
+
}
+
+
.settings-button:hover img {
+
transform: rotate(180deg);
+
transition: transform 0.6s ease;
+
}
+
+
.settings-button:active {
+
transform: scale(0.95);
+
}
+
+
.settings {
+
transition: transform 0.6s ease;
+
}
+
+
.settings-button:not(:hover) .settings {
+
transform: rotate(0deg);
+
}
+
+
.modal {
+
display: none;
+
position: fixed;
+
top: 0;
+
left: 0;
+
width: 100%;
+
height: 100%;
+
background-color: rgba(0, 0, 0, 0.5);
+
z-index: 1000;
+
}
+
+
.modal-content {
+
position: relative;
+
background-color: var(--bg-color);
+
border: 1px solid var(--border-color);
+
margin: 15% auto;
+
padding: 20px;
+
border-radius: 8px;
+
width: 80%;
+
max-width: 500px;
+
}
+
+
.close-modal {
+
position: absolute;
+
right: 10px;
+
top: 10px;
+
cursor: pointer;
+
font-size: 24px;
+
color: var(--text-color-secondary);
+
padding-left: 8px;
+
padding-right: 8px;
+
}
+
+
.bang-select {
+
width: 100%;
+
padding: 8px;
+
margin-top: 10px;
+
border-radius: 4px;
+
}
+
+
.bang-select-container {
+
position: relative;
+
display: inline-block;
+
width: 100%;
+
}
+
+
.bang-select-container::after {
+
content: "↵";
+
position: absolute;
+
right: 10px;
+
top: 33%;
+
color: var(--text-color-secondary);
+
pointer-events: none;
+
font-size: 1.2em;
+
}
+
+
/* Update the bang-select class to account for the icon */
+
.bang-select {
+
padding-right: 30px; /* Make room for the icon */
+
}
+
+
@keyframes shake {
+
0%,
+
100% {
+
transform: translateX(0);
+
}
+
25% {
+
transform: translateX(-5px);
+
}
+
75% {
+
transform: translateX(5px);
+
}
+
}
+
+
@keyframes flash-red {
+
0%,
+
100% {
+
background-color: transparent;
+
}
+
50% {
+
background-color: rgba(255, 0, 0, 0.2);
+
}
+
}
+
+
.shake {
+
animation: shake 0.2s ease-in-out;
+
}
+
+
.flash-red {
+
animation: flash-red 0.3s ease-in-out;
+
}
+1
src/main.ts
···
import { bangs } from "./bang";
function getFocusableElements(
root: HTMLElement = document.body,
···
import { bangs } from "./bang";
+
import "./global.css";
function getFocusableElements(
root: HTMLElement = document.body,