Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3ffd439f88
|
|||
|
68284bc963
|
2
.github/workflows/docker-publish.yml
vendored
2
.github/workflows/docker-publish.yml
vendored
@@ -10,6 +10,8 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
|
env:
|
||||||
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,8 +1,12 @@
|
|||||||
passport
|
passport
|
||||||
|
passport-*
|
||||||
.env
|
.env
|
||||||
passport.db*
|
passport.db*
|
||||||
public
|
public
|
||||||
zqdgr
|
zqdgr
|
||||||
|
|
||||||
# compiled via go prepare
|
# compiled via go prepare
|
||||||
|
src/assets/styles/*
|
||||||
src/assets/tailwind.css
|
src/assets/tailwind.css
|
||||||
|
|
||||||
|
node_modules
|
||||||
20
Dockerfile
20
Dockerfile
@@ -1,22 +1,9 @@
|
|||||||
FROM golang:1.25 AS builder
|
FROM golang:1.25 AS builder
|
||||||
|
|
||||||
# build dependencies
|
# build dependencies
|
||||||
RUN apt update && apt install -y upx
|
RUN apt update && apt install -y upx unzip
|
||||||
|
|
||||||
ARG TARGETARCH
|
RUN curl -fsSL https://bun.com/install | BUN_INSTALL=/usr bash
|
||||||
RUN set -eux; \
|
|
||||||
echo "Building for architecture: ${TARGETARCH}"; \
|
|
||||||
case "${TARGETARCH}" in \
|
|
||||||
"amd64") \
|
|
||||||
arch_suffix='x64' ;; \
|
|
||||||
"arm64") \
|
|
||||||
arch_suffix='arm64' ;; \
|
|
||||||
*) \
|
|
||||||
echo "Unsupported architecture: ${TARGETARCH}" && exit 1 ;; \
|
|
||||||
esac; \
|
|
||||||
curl -sLO "https://github.com/tailwindlabs/tailwindcss/releases/download/v4.1.13/tailwindcss-linux-${arch_suffix}"; \
|
|
||||||
mv "tailwindcss-linux-${arch_suffix}" /usr/local/bin/tailwindcss; \
|
|
||||||
chmod +x /usr/local/bin/tailwindcss;
|
|
||||||
|
|
||||||
|
|
||||||
RUN go install github.com/juls0730/zqdgr@latest
|
RUN go install github.com/juls0730/zqdgr@latest
|
||||||
@@ -30,8 +17,9 @@ COPY go.mod go.sum ./
|
|||||||
RUN go mod download
|
RUN go mod download
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
RUN bun install
|
||||||
|
|
||||||
RUN zqdgr build
|
RUN zqdgr build
|
||||||
RUN upx passport
|
|
||||||
|
|
||||||
# ---- Runtime Stage ----
|
# ---- Runtime Stage ----
|
||||||
FROM gcr.io/distroless/static-debian12 AS runner
|
FROM gcr.io/distroless/static-debian12 AS runner
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -19,7 +19,7 @@ Passport is a simple, fast, and lightweight web dashboard/new tab replacement.
|
|||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
Passport is available as a Docker image via this repository. This is the recommended way to run Passport.
|
Passport is available as a Docker image via this repository for both amd64 and arm64. This is the recommended way to run Passport.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d --name passport -p 3000:3000 -v passport_data:/data -e PASSPORT_ADMIN_USERNAME=admin -e PASSPORT_ADMIN_PASSWORD=password ghcr.io/juls0730/passport:latest
|
docker run -d --name passport -p 3000:3000 -v passport_data:/data -e PASSPORT_ADMIN_USERNAME=admin -e PASSPORT_ADMIN_PASSWORD=password ghcr.io/juls0730/passport:latest
|
||||||
@@ -35,9 +35,11 @@ If you want to build from source, you will need to install the dependencies firs
|
|||||||
# note entirely necessary, but strongly recommended
|
# note entirely necessary, but strongly recommended
|
||||||
go install github.com/juls0730/zqdgr@latest
|
go install github.com/juls0730/zqdgr@latest
|
||||||
|
|
||||||
curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/download/v4.1.13/tailwindcss-linux-x64
|
# install bun
|
||||||
chmod +x tailwindcss-linux-x64
|
curl -fsSL https://bun.sh/install | bash
|
||||||
mv tailwindcss-linux-x64 /usr/local/bin/tailwindcss
|
|
||||||
|
# install css build deps
|
||||||
|
bun install
|
||||||
|
|
||||||
# you may also have to install sqlite3...
|
# you may also have to install sqlite3...
|
||||||
```
|
```
|
||||||
@@ -71,9 +73,9 @@ You can then run the binary.
|
|||||||
The weather integration is optional, and will be enabled automatically if you provide an API key. The following only applies if you are using the OpenWeatherMap integration.
|
The weather integration is optional, and will be enabled automatically if you provide an API key. The following only applies if you are using the OpenWeatherMap integration.
|
||||||
|
|
||||||
| Environment Variable | Description | Required | Default |
|
| Environment Variable | Description | Required | Default |
|
||||||
| ------------------------- | ------------------------------------------------------------------------- | -------- | -------------- |
|
| -------------------------- | ------------------------------------------------------------------------- | -------- | -------------- |
|
||||||
|
| `PASSPORT_WEATHER_API_KEY` | The OpenWeather API key | true | |
|
||||||
| `WEATHER_PROVIDER` | The weather provider to use, currently only `openweathermap` is supported | false | openweathermap |
|
| `WEATHER_PROVIDER` | The weather provider to use, currently only `openweathermap` is supported | false | openweathermap |
|
||||||
| `WEATHER_API_KEY` | The OpenWeather API key | true | |
|
|
||||||
| `WEATHER_TEMP_UNITS` | The temperature units to use, either `metric` or `imperial` | false | metric |
|
| `WEATHER_TEMP_UNITS` | The temperature units to use, either `metric` or `imperial` | false | metric |
|
||||||
| `WEATHER_LAT` | The latitude of your location | true | |
|
| `WEATHER_LAT` | The latitude of your location | true | |
|
||||||
| `WEATHER_LON` | The longitude of your location | true | |
|
| `WEATHER_LON` | The longitude of your location | true | |
|
||||||
@@ -84,8 +86,8 @@ The weather integration is optional, and will be enabled automatically if you pr
|
|||||||
The uptime integration is optional, and will be enabled automatically if you provide an API key. The following only applies if you are using the UptimeRobot integration.
|
The uptime integration is optional, and will be enabled automatically if you provide an API key. The following only applies if you are using the UptimeRobot integration.
|
||||||
|
|
||||||
| Environment Variable | Description | Required | Default |
|
| Environment Variable | Description | Required | Default |
|
||||||
| ------------------------ | ------------------------------------------------- | -------- | ------- |
|
| ------------------------- | ------------------------------------------------- | -------- | ------- |
|
||||||
| `UPTIME_API_KEY` | The UptimeRobot API key | true | |
|
| `PASSPORT_UPTIME_API_KEY` | The UptimeRobot API key | true | |
|
||||||
| `UPTIME_UPDATE_INTERVAL` | The interval in seconds to update the uptime data | false | 300 |
|
| `UPTIME_UPDATE_INTERVAL` | The interval in seconds to update the uptime data | false | 300 |
|
||||||
|
|
||||||
### Adding links and categories
|
### Adding links and categories
|
||||||
|
|||||||
530
bun.lock
Normal file
530
bun.lock
Normal file
@@ -0,0 +1,530 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "passport-css-compiler",
|
||||||
|
"devDependencies": {
|
||||||
|
"@fullhuman/postcss-purgecss": "^7.0.2",
|
||||||
|
"baseline-browser-mapping": "^2.9.2",
|
||||||
|
"cssnano": "^7.1.1",
|
||||||
|
"postcss": "^8.4.35",
|
||||||
|
"postcss-cli": "^11.0.0",
|
||||||
|
"postcss-import": "^16.1.1",
|
||||||
|
"postcss-preset-env": "^10.4.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@csstools/cascade-layer-name-parser": ["@csstools/cascade-layer-name-parser@2.0.5", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A=="],
|
||||||
|
|
||||||
|
"@csstools/color-helpers": ["@csstools/color-helpers@5.1.0", "", {}, "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA=="],
|
||||||
|
|
||||||
|
"@csstools/css-calc": ["@csstools/css-calc@2.1.4", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ=="],
|
||||||
|
|
||||||
|
"@csstools/css-color-parser": ["@csstools/css-color-parser@3.1.0", "", { "dependencies": { "@csstools/color-helpers": "^5.1.0", "@csstools/css-calc": "^2.1.4" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA=="],
|
||||||
|
|
||||||
|
"@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@3.0.5", "", { "peerDependencies": { "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ=="],
|
||||||
|
|
||||||
|
"@csstools/css-tokenizer": ["@csstools/css-tokenizer@3.0.4", "", {}, "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw=="],
|
||||||
|
|
||||||
|
"@csstools/media-query-list-parser": ["@csstools/media-query-list-parser@4.0.3", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-alpha-function": ["@csstools/postcss-alpha-function@1.0.1", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-cascade-layers": ["@csstools/postcss-cascade-layers@5.0.2", "", { "dependencies": { "@csstools/selector-specificity": "^5.0.0", "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-color-function": ["@csstools/postcss-color-function@4.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-color-function-display-p3-linear": ["@csstools/postcss-color-function-display-p3-linear@1.0.1", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-color-mix-function": ["@csstools/postcss-color-mix-function@3.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-color-mix-variadic-function-arguments": ["@csstools/postcss-color-mix-variadic-function-arguments@1.0.2", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-content-alt-text": ["@csstools/postcss-content-alt-text@2.0.8", "", { "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-contrast-color-function": ["@csstools/postcss-contrast-color-function@2.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-exponential-functions": ["@csstools/postcss-exponential-functions@2.0.9", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-font-format-keywords": ["@csstools/postcss-font-format-keywords@4.0.0", "", { "dependencies": { "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-gamut-mapping": ["@csstools/postcss-gamut-mapping@2.0.11", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-gradients-interpolation-method": ["@csstools/postcss-gradients-interpolation-method@5.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-hwb-function": ["@csstools/postcss-hwb-function@4.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-ic-unit": ["@csstools/postcss-ic-unit@4.0.4", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-initial": ["@csstools/postcss-initial@2.0.1", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-is-pseudo-class": ["@csstools/postcss-is-pseudo-class@5.0.3", "", { "dependencies": { "@csstools/selector-specificity": "^5.0.0", "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-light-dark-function": ["@csstools/postcss-light-dark-function@2.0.11", "", { "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-logical-float-and-clear": ["@csstools/postcss-logical-float-and-clear@3.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-logical-overflow": ["@csstools/postcss-logical-overflow@2.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-logical-overscroll-behavior": ["@csstools/postcss-logical-overscroll-behavior@2.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-logical-resize": ["@csstools/postcss-logical-resize@3.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-logical-viewport-units": ["@csstools/postcss-logical-viewport-units@3.0.4", "", { "dependencies": { "@csstools/css-tokenizer": "^3.0.4", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-media-minmax": ["@csstools/postcss-media-minmax@2.0.9", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/media-query-list-parser": "^4.0.3" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-media-queries-aspect-ratio-number-values": ["@csstools/postcss-media-queries-aspect-ratio-number-values@3.0.5", "", { "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/media-query-list-parser": "^4.0.3" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-nested-calc": ["@csstools/postcss-nested-calc@4.0.0", "", { "dependencies": { "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-normalize-display-values": ["@csstools/postcss-normalize-display-values@4.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-oklab-function": ["@csstools/postcss-oklab-function@4.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-progressive-custom-properties": ["@csstools/postcss-progressive-custom-properties@4.2.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-random-function": ["@csstools/postcss-random-function@2.0.1", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-relative-color-syntax": ["@csstools/postcss-relative-color-syntax@3.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-scope-pseudo-class": ["@csstools/postcss-scope-pseudo-class@4.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-sign-functions": ["@csstools/postcss-sign-functions@1.1.4", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-stepped-value-functions": ["@csstools/postcss-stepped-value-functions@4.0.9", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-text-decoration-shorthand": ["@csstools/postcss-text-decoration-shorthand@4.0.3", "", { "dependencies": { "@csstools/color-helpers": "^5.1.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-trigonometric-functions": ["@csstools/postcss-trigonometric-functions@4.0.9", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-unset-value": ["@csstools/postcss-unset-value@4.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA=="],
|
||||||
|
|
||||||
|
"@csstools/selector-resolve-nested": ["@csstools/selector-resolve-nested@3.1.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.0.0" } }, "sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g=="],
|
||||||
|
|
||||||
|
"@csstools/selector-specificity": ["@csstools/selector-specificity@5.0.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.0.0" } }, "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw=="],
|
||||||
|
|
||||||
|
"@csstools/utilities": ["@csstools/utilities@2.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ=="],
|
||||||
|
|
||||||
|
"@fullhuman/postcss-purgecss": ["@fullhuman/postcss-purgecss@7.0.2", "", { "dependencies": { "purgecss": "^7.0.2" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-U4zAXNaVztbDxO9EdcLp51F3UxxYsb/7DN89rFxFJhfk2Wua2pvw2Kf3HdspbPhW/wpHjSjsxWYoIlbTgRSjbQ=="],
|
||||||
|
|
||||||
|
"@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="],
|
||||||
|
|
||||||
|
"@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
|
||||||
|
|
||||||
|
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
|
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||||
|
|
||||||
|
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
||||||
|
|
||||||
|
"autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="],
|
||||||
|
|
||||||
|
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.2", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-PxSsosKQjI38iXkmb3d0Y32efqyA0uW4s41u4IVBsLlWLhCiYNpH/AfNOVWRqCQBlD8TFJTz6OUWNd4DFJCnmw=="],
|
||||||
|
|
||||||
|
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
||||||
|
|
||||||
|
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
|
||||||
|
|
||||||
|
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||||
|
|
||||||
|
"browserslist": ["browserslist@4.26.3", "", { "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", "electron-to-chromium": "^1.5.227", "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w=="],
|
||||||
|
|
||||||
|
"caniuse-api": ["caniuse-api@3.0.0", "", { "dependencies": { "browserslist": "^4.0.0", "caniuse-lite": "^1.0.0", "lodash.memoize": "^4.1.2", "lodash.uniq": "^4.5.0" } }, "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw=="],
|
||||||
|
|
||||||
|
"caniuse-lite": ["caniuse-lite@1.0.30001746", "", {}, "sha512-eA7Ys/DGw+pnkWWSE/id29f2IcPHVoE8wxtvE5JdvD2V28VTDPy1yEeo11Guz0sJ4ZeGRcm3uaTcAqK1LXaphA=="],
|
||||||
|
|
||||||
|
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||||
|
|
||||||
|
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||||
|
|
||||||
|
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||||
|
|
||||||
|
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||||
|
|
||||||
|
"colord": ["colord@2.9.3", "", {}, "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="],
|
||||||
|
|
||||||
|
"commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
|
||||||
|
|
||||||
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
|
|
||||||
|
"css-blank-pseudo": ["css-blank-pseudo@7.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag=="],
|
||||||
|
|
||||||
|
"css-declaration-sorter": ["css-declaration-sorter@7.3.0", "", { "peerDependencies": { "postcss": "^8.0.9" } }, "sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ=="],
|
||||||
|
|
||||||
|
"css-has-pseudo": ["css-has-pseudo@7.0.3", "", { "dependencies": { "@csstools/selector-specificity": "^5.0.0", "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA=="],
|
||||||
|
|
||||||
|
"css-prefers-color-scheme": ["css-prefers-color-scheme@10.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ=="],
|
||||||
|
|
||||||
|
"css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="],
|
||||||
|
|
||||||
|
"css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="],
|
||||||
|
|
||||||
|
"css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="],
|
||||||
|
|
||||||
|
"cssdb": ["cssdb@8.4.2", "", {}, "sha512-PzjkRkRUS+IHDJohtxkIczlxPPZqRo0nXplsYXOMBRPjcVRjj1W4DfvRgshUYTVuUigU7ptVYkFJQ7abUB0nyg=="],
|
||||||
|
|
||||||
|
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
||||||
|
|
||||||
|
"cssnano": ["cssnano@7.1.1", "", { "dependencies": { "cssnano-preset-default": "^7.0.9", "lilconfig": "^3.1.3" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-fm4D8ti0dQmFPeF8DXSAA//btEmqCOgAc/9Oa3C1LW94h5usNrJEfrON7b4FkPZgnDEn6OUs5NdxiJZmAtGOpQ=="],
|
||||||
|
|
||||||
|
"cssnano-preset-default": ["cssnano-preset-default@7.0.9", "", { "dependencies": { "browserslist": "^4.25.1", "css-declaration-sorter": "^7.2.0", "cssnano-utils": "^5.0.1", "postcss-calc": "^10.1.1", "postcss-colormin": "^7.0.4", "postcss-convert-values": "^7.0.7", "postcss-discard-comments": "^7.0.4", "postcss-discard-duplicates": "^7.0.2", "postcss-discard-empty": "^7.0.1", "postcss-discard-overridden": "^7.0.1", "postcss-merge-longhand": "^7.0.5", "postcss-merge-rules": "^7.0.6", "postcss-minify-font-values": "^7.0.1", "postcss-minify-gradients": "^7.0.1", "postcss-minify-params": "^7.0.4", "postcss-minify-selectors": "^7.0.5", "postcss-normalize-charset": "^7.0.1", "postcss-normalize-display-values": "^7.0.1", "postcss-normalize-positions": "^7.0.1", "postcss-normalize-repeat-style": "^7.0.1", "postcss-normalize-string": "^7.0.1", "postcss-normalize-timing-functions": "^7.0.1", "postcss-normalize-unicode": "^7.0.4", "postcss-normalize-url": "^7.0.1", "postcss-normalize-whitespace": "^7.0.1", "postcss-ordered-values": "^7.0.2", "postcss-reduce-initial": "^7.0.4", "postcss-reduce-transforms": "^7.0.1", "postcss-svgo": "^7.1.0", "postcss-unique-selectors": "^7.0.4" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-tCD6AAFgYBOVpMBX41KjbvRh9c2uUjLXRyV7KHSIrwHiq5Z9o0TFfUCoM3TwVrRsRteN3sVXGNvjVNxYzkpTsA=="],
|
||||||
|
|
||||||
|
"cssnano-utils": ["cssnano-utils@5.0.1", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg=="],
|
||||||
|
|
||||||
|
"csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="],
|
||||||
|
|
||||||
|
"dependency-graph": ["dependency-graph@1.0.0", "", {}, "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg=="],
|
||||||
|
|
||||||
|
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
|
||||||
|
|
||||||
|
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
|
||||||
|
|
||||||
|
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
|
||||||
|
|
||||||
|
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
|
||||||
|
|
||||||
|
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||||
|
|
||||||
|
"electron-to-chromium": ["electron-to-chromium@1.5.229", "", {}, "sha512-cwhDcZKGcT/rEthLRJ9eBlMDkh1sorgsuk+6dpsehV0g9CABsIqBxU4rLRjG+d/U6pYU1s37A4lSKrVc5lSQYg=="],
|
||||||
|
|
||||||
|
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
|
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
||||||
|
|
||||||
|
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||||
|
|
||||||
|
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||||
|
|
||||||
|
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||||
|
|
||||||
|
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||||
|
|
||||||
|
"fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
|
||||||
|
|
||||||
|
"fs-extra": ["fs-extra@11.3.2", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A=="],
|
||||||
|
|
||||||
|
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||||
|
|
||||||
|
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||||
|
|
||||||
|
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||||
|
|
||||||
|
"glob": ["glob@11.0.3", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.0.3", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA=="],
|
||||||
|
|
||||||
|
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
|
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||||
|
|
||||||
|
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||||
|
|
||||||
|
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
||||||
|
|
||||||
|
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
|
||||||
|
|
||||||
|
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||||
|
|
||||||
|
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||||
|
|
||||||
|
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||||
|
|
||||||
|
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||||
|
|
||||||
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
|
"jackspeak": ["jackspeak@4.1.1", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ=="],
|
||||||
|
|
||||||
|
"jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||||
|
|
||||||
|
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
|
||||||
|
|
||||||
|
"lodash.memoize": ["lodash.memoize@4.1.2", "", {}, "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="],
|
||||||
|
|
||||||
|
"lodash.uniq": ["lodash.uniq@4.5.0", "", {}, "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="],
|
||||||
|
|
||||||
|
"lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="],
|
||||||
|
|
||||||
|
"mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="],
|
||||||
|
|
||||||
|
"minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
|
||||||
|
|
||||||
|
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||||
|
|
||||||
|
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||||
|
|
||||||
|
"node-releases": ["node-releases@2.0.21", "", {}, "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw=="],
|
||||||
|
|
||||||
|
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||||
|
|
||||||
|
"normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="],
|
||||||
|
|
||||||
|
"nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
|
||||||
|
|
||||||
|
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
|
||||||
|
|
||||||
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||||
|
|
||||||
|
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
|
||||||
|
|
||||||
|
"path-scurry": ["path-scurry@2.0.0", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg=="],
|
||||||
|
|
||||||
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
|
|
||||||
|
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||||
|
|
||||||
|
"pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="],
|
||||||
|
|
||||||
|
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||||
|
|
||||||
|
"postcss-attribute-case-insensitive": ["postcss-attribute-case-insensitive@7.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw=="],
|
||||||
|
|
||||||
|
"postcss-calc": ["postcss-calc@10.1.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.38" } }, "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw=="],
|
||||||
|
|
||||||
|
"postcss-clamp": ["postcss-clamp@4.1.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.6" } }, "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow=="],
|
||||||
|
|
||||||
|
"postcss-cli": ["postcss-cli@11.0.1", "", { "dependencies": { "chokidar": "^3.3.0", "dependency-graph": "^1.0.0", "fs-extra": "^11.0.0", "picocolors": "^1.0.0", "postcss-load-config": "^5.0.0", "postcss-reporter": "^7.0.0", "pretty-hrtime": "^1.0.3", "read-cache": "^1.0.0", "slash": "^5.0.0", "tinyglobby": "^0.2.12", "yargs": "^17.0.0" }, "peerDependencies": { "postcss": "^8.0.0" }, "bin": { "postcss": "index.js" } }, "sha512-0UnkNPSayHKRe/tc2YGW6XnSqqOA9eqpiRMgRlV1S6HdGi16vwJBx7lviARzbV1HpQHqLLRH3o8vTcB0cLc+5g=="],
|
||||||
|
|
||||||
|
"postcss-color-functional-notation": ["postcss-color-functional-notation@7.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-TLCW9fN5kvO/u38/uesdpbx3e8AkTYhMvDZYa9JpmImWuTE99bDQ7GU7hdOADIZsiI9/zuxfAJxny/khknp1Zw=="],
|
||||||
|
|
||||||
|
"postcss-color-hex-alpha": ["postcss-color-hex-alpha@10.0.0", "", { "dependencies": { "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w=="],
|
||||||
|
|
||||||
|
"postcss-color-rebeccapurple": ["postcss-color-rebeccapurple@10.0.0", "", { "dependencies": { "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ=="],
|
||||||
|
|
||||||
|
"postcss-colormin": ["postcss-colormin@7.0.4", "", { "dependencies": { "browserslist": "^4.25.1", "caniuse-api": "^3.0.0", "colord": "^2.9.3", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-ziQuVzQZBROpKpfeDwmrG+Vvlr0YWmY/ZAk99XD+mGEBuEojoFekL41NCsdhyNUtZI7DPOoIWIR7vQQK9xwluw=="],
|
||||||
|
|
||||||
|
"postcss-convert-values": ["postcss-convert-values@7.0.7", "", { "dependencies": { "browserslist": "^4.25.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-HR9DZLN04Xbe6xugRH6lS4ZQH2zm/bFh/ZyRkpedZozhvh+awAfbA0P36InO4fZfDhvYfNJeNvlTf1sjwGbw/A=="],
|
||||||
|
|
||||||
|
"postcss-custom-media": ["postcss-custom-media@11.0.6", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^2.0.5", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/media-query-list-parser": "^4.0.3" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw=="],
|
||||||
|
|
||||||
|
"postcss-custom-properties": ["postcss-custom-properties@14.0.6", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^2.0.5", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ=="],
|
||||||
|
|
||||||
|
"postcss-custom-selectors": ["postcss-custom-selectors@8.0.5", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^2.0.5", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg=="],
|
||||||
|
|
||||||
|
"postcss-dir-pseudo-class": ["postcss-dir-pseudo-class@9.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA=="],
|
||||||
|
|
||||||
|
"postcss-discard-comments": ["postcss-discard-comments@7.0.4", "", { "dependencies": { "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg=="],
|
||||||
|
|
||||||
|
"postcss-discard-duplicates": ["postcss-discard-duplicates@7.0.2", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w=="],
|
||||||
|
|
||||||
|
"postcss-discard-empty": ["postcss-discard-empty@7.0.1", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg=="],
|
||||||
|
|
||||||
|
"postcss-discard-overridden": ["postcss-discard-overridden@7.0.1", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg=="],
|
||||||
|
|
||||||
|
"postcss-double-position-gradients": ["postcss-double-position-gradients@6.0.4", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-m6IKmxo7FxSP5nF2l63QbCC3r+bWpFUWmZXZf096WxG0m7Vl1Q1+ruFOhpdDRmKrRS+S3Jtk+TVk/7z0+BVK6g=="],
|
||||||
|
|
||||||
|
"postcss-focus-visible": ["postcss-focus-visible@10.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA=="],
|
||||||
|
|
||||||
|
"postcss-focus-within": ["postcss-focus-within@9.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw=="],
|
||||||
|
|
||||||
|
"postcss-font-variant": ["postcss-font-variant@5.0.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA=="],
|
||||||
|
|
||||||
|
"postcss-gap-properties": ["postcss-gap-properties@6.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw=="],
|
||||||
|
|
||||||
|
"postcss-image-set-function": ["postcss-image-set-function@7.0.0", "", { "dependencies": { "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA=="],
|
||||||
|
|
||||||
|
"postcss-import": ["postcss-import@16.1.1", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ=="],
|
||||||
|
|
||||||
|
"postcss-lab-function": ["postcss-lab-function@7.0.12", "", { "dependencies": { "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-tUcyRk1ZTPec3OuKFsqtRzW2Go5lehW29XA21lZ65XmzQkz43VY2tyWEC202F7W3mILOjw0voOiuxRGTsN+J9w=="],
|
||||||
|
|
||||||
|
"postcss-load-config": ["postcss-load-config@5.1.0", "", { "dependencies": { "lilconfig": "^3.1.1", "yaml": "^2.4.2" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1" }, "optionalPeers": ["jiti", "postcss", "tsx"] }, "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA=="],
|
||||||
|
|
||||||
|
"postcss-logical": ["postcss-logical@8.1.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA=="],
|
||||||
|
|
||||||
|
"postcss-merge-longhand": ["postcss-merge-longhand@7.0.5", "", { "dependencies": { "postcss-value-parser": "^4.2.0", "stylehacks": "^7.0.5" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw=="],
|
||||||
|
|
||||||
|
"postcss-merge-rules": ["postcss-merge-rules@7.0.6", "", { "dependencies": { "browserslist": "^4.25.1", "caniuse-api": "^3.0.0", "cssnano-utils": "^5.0.1", "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-2jIPT4Tzs8K87tvgCpSukRQ2jjd+hH6Bb8rEEOUDmmhOeTcqDg5fEFK8uKIu+Pvc3//sm3Uu6FRqfyv7YF7+BQ=="],
|
||||||
|
|
||||||
|
"postcss-minify-font-values": ["postcss-minify-font-values@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ=="],
|
||||||
|
|
||||||
|
"postcss-minify-gradients": ["postcss-minify-gradients@7.0.1", "", { "dependencies": { "colord": "^2.9.3", "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A=="],
|
||||||
|
|
||||||
|
"postcss-minify-params": ["postcss-minify-params@7.0.4", "", { "dependencies": { "browserslist": "^4.25.1", "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-3OqqUddfH8c2e7M35W6zIwv7jssM/3miF9cbCSb1iJiWvtguQjlxZGIHK9JRmc8XAKmE2PFGtHSM7g/VcW97sw=="],
|
||||||
|
|
||||||
|
"postcss-minify-selectors": ["postcss-minify-selectors@7.0.5", "", { "dependencies": { "cssesc": "^3.0.0", "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug=="],
|
||||||
|
|
||||||
|
"postcss-nesting": ["postcss-nesting@13.0.2", "", { "dependencies": { "@csstools/selector-resolve-nested": "^3.1.0", "@csstools/selector-specificity": "^5.0.0", "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ=="],
|
||||||
|
|
||||||
|
"postcss-normalize-charset": ["postcss-normalize-charset@7.0.1", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ=="],
|
||||||
|
|
||||||
|
"postcss-normalize-display-values": ["postcss-normalize-display-values@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ=="],
|
||||||
|
|
||||||
|
"postcss-normalize-positions": ["postcss-normalize-positions@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ=="],
|
||||||
|
|
||||||
|
"postcss-normalize-repeat-style": ["postcss-normalize-repeat-style@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ=="],
|
||||||
|
|
||||||
|
"postcss-normalize-string": ["postcss-normalize-string@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ=="],
|
||||||
|
|
||||||
|
"postcss-normalize-timing-functions": ["postcss-normalize-timing-functions@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg=="],
|
||||||
|
|
||||||
|
"postcss-normalize-unicode": ["postcss-normalize-unicode@7.0.4", "", { "dependencies": { "browserslist": "^4.25.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-LvIURTi1sQoZqj8mEIE8R15yvM+OhbR1avynMtI9bUzj5gGKR/gfZFd8O7VMj0QgJaIFzxDwxGl/ASMYAkqO8g=="],
|
||||||
|
|
||||||
|
"postcss-normalize-url": ["postcss-normalize-url@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ=="],
|
||||||
|
|
||||||
|
"postcss-normalize-whitespace": ["postcss-normalize-whitespace@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA=="],
|
||||||
|
|
||||||
|
"postcss-opacity-percentage": ["postcss-opacity-percentage@3.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ=="],
|
||||||
|
|
||||||
|
"postcss-ordered-values": ["postcss-ordered-values@7.0.2", "", { "dependencies": { "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw=="],
|
||||||
|
|
||||||
|
"postcss-overflow-shorthand": ["postcss-overflow-shorthand@6.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q=="],
|
||||||
|
|
||||||
|
"postcss-page-break": ["postcss-page-break@3.0.4", "", { "peerDependencies": { "postcss": "^8" } }, "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ=="],
|
||||||
|
|
||||||
|
"postcss-place": ["postcss-place@10.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw=="],
|
||||||
|
|
||||||
|
"postcss-preset-env": ["postcss-preset-env@10.4.0", "", { "dependencies": { "@csstools/postcss-alpha-function": "^1.0.1", "@csstools/postcss-cascade-layers": "^5.0.2", "@csstools/postcss-color-function": "^4.0.12", "@csstools/postcss-color-function-display-p3-linear": "^1.0.1", "@csstools/postcss-color-mix-function": "^3.0.12", "@csstools/postcss-color-mix-variadic-function-arguments": "^1.0.2", "@csstools/postcss-content-alt-text": "^2.0.8", "@csstools/postcss-contrast-color-function": "^2.0.12", "@csstools/postcss-exponential-functions": "^2.0.9", "@csstools/postcss-font-format-keywords": "^4.0.0", "@csstools/postcss-gamut-mapping": "^2.0.11", "@csstools/postcss-gradients-interpolation-method": "^5.0.12", "@csstools/postcss-hwb-function": "^4.0.12", "@csstools/postcss-ic-unit": "^4.0.4", "@csstools/postcss-initial": "^2.0.1", "@csstools/postcss-is-pseudo-class": "^5.0.3", "@csstools/postcss-light-dark-function": "^2.0.11", "@csstools/postcss-logical-float-and-clear": "^3.0.0", "@csstools/postcss-logical-overflow": "^2.0.0", "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", "@csstools/postcss-logical-resize": "^3.0.0", "@csstools/postcss-logical-viewport-units": "^3.0.4", "@csstools/postcss-media-minmax": "^2.0.9", "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.5", "@csstools/postcss-nested-calc": "^4.0.0", "@csstools/postcss-normalize-display-values": "^4.0.0", "@csstools/postcss-oklab-function": "^4.0.12", "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/postcss-random-function": "^2.0.1", "@csstools/postcss-relative-color-syntax": "^3.0.12", "@csstools/postcss-scope-pseudo-class": "^4.0.1", "@csstools/postcss-sign-functions": "^1.1.4", "@csstools/postcss-stepped-value-functions": "^4.0.9", "@csstools/postcss-text-decoration-shorthand": "^4.0.3", "@csstools/postcss-trigonometric-functions": "^4.0.9", "@csstools/postcss-unset-value": "^4.0.0", "autoprefixer": "^10.4.21", "browserslist": "^4.26.0", "css-blank-pseudo": "^7.0.1", "css-has-pseudo": "^7.0.3", "css-prefers-color-scheme": "^10.0.0", "cssdb": "^8.4.2", "postcss-attribute-case-insensitive": "^7.0.1", "postcss-clamp": "^4.1.0", "postcss-color-functional-notation": "^7.0.12", "postcss-color-hex-alpha": "^10.0.0", "postcss-color-rebeccapurple": "^10.0.0", "postcss-custom-media": "^11.0.6", "postcss-custom-properties": "^14.0.6", "postcss-custom-selectors": "^8.0.5", "postcss-dir-pseudo-class": "^9.0.1", "postcss-double-position-gradients": "^6.0.4", "postcss-focus-visible": "^10.0.1", "postcss-focus-within": "^9.0.1", "postcss-font-variant": "^5.0.0", "postcss-gap-properties": "^6.0.0", "postcss-image-set-function": "^7.0.0", "postcss-lab-function": "^7.0.12", "postcss-logical": "^8.1.0", "postcss-nesting": "^13.0.2", "postcss-opacity-percentage": "^3.0.0", "postcss-overflow-shorthand": "^6.0.0", "postcss-page-break": "^3.0.4", "postcss-place": "^10.0.0", "postcss-pseudo-class-any-link": "^10.0.1", "postcss-replace-overflow-wrap": "^4.0.0", "postcss-selector-not": "^8.0.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-2kqpOthQ6JhxqQq1FSAAZGe9COQv75Aw8WbsOvQVNJ2nSevc9Yx/IKZGuZ7XJ+iOTtVon7LfO7ELRzg8AZ+sdw=="],
|
||||||
|
|
||||||
|
"postcss-pseudo-class-any-link": ["postcss-pseudo-class-any-link@10.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q=="],
|
||||||
|
|
||||||
|
"postcss-reduce-initial": ["postcss-reduce-initial@7.0.4", "", { "dependencies": { "browserslist": "^4.25.1", "caniuse-api": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-rdIC9IlMBn7zJo6puim58Xd++0HdbvHeHaPgXsimMfG1ijC5A9ULvNLSE0rUKVJOvNMcwewW4Ga21ngyJjY/+Q=="],
|
||||||
|
|
||||||
|
"postcss-reduce-transforms": ["postcss-reduce-transforms@7.0.1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g=="],
|
||||||
|
|
||||||
|
"postcss-replace-overflow-wrap": ["postcss-replace-overflow-wrap@4.0.0", "", { "peerDependencies": { "postcss": "^8.0.3" } }, "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw=="],
|
||||||
|
|
||||||
|
"postcss-reporter": ["postcss-reporter@7.1.0", "", { "dependencies": { "picocolors": "^1.0.0", "thenby": "^1.3.4" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA=="],
|
||||||
|
|
||||||
|
"postcss-selector-not": ["postcss-selector-not@8.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA=="],
|
||||||
|
|
||||||
|
"postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
||||||
|
|
||||||
|
"postcss-svgo": ["postcss-svgo@7.1.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0", "svgo": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w=="],
|
||||||
|
|
||||||
|
"postcss-unique-selectors": ["postcss-unique-selectors@7.0.4", "", { "dependencies": { "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ=="],
|
||||||
|
|
||||||
|
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
||||||
|
|
||||||
|
"pretty-hrtime": ["pretty-hrtime@1.0.3", "", {}, "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A=="],
|
||||||
|
|
||||||
|
"purgecss": ["purgecss@7.0.2", "", { "dependencies": { "commander": "^12.1.0", "glob": "^11.0.0", "postcss": "^8.4.47", "postcss-selector-parser": "^6.1.2" }, "bin": { "purgecss": "bin/purgecss.js" } }, "sha512-4Ku8KoxNhOWi9X1XJ73XY5fv+I+hhTRedKpGs/2gaBKU8ijUiIKF/uyyIyh7Wo713bELSICF5/NswjcuOqYouQ=="],
|
||||||
|
|
||||||
|
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
|
||||||
|
|
||||||
|
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
||||||
|
|
||||||
|
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
|
||||||
|
|
||||||
|
"resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
|
||||||
|
|
||||||
|
"sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="],
|
||||||
|
|
||||||
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
|
|
||||||
|
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||||
|
|
||||||
|
"slash": ["slash@5.1.0", "", {}, "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg=="],
|
||||||
|
|
||||||
|
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||||
|
|
||||||
|
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
|
|
||||||
|
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
|
|
||||||
|
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"stylehacks": ["stylehacks@7.0.6", "", { "dependencies": { "browserslist": "^4.25.1", "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-iitguKivmsueOmTO0wmxURXBP8uqOO+zikLGZ7Mm9e/94R4w5T999Js2taS/KBOnQ/wdC3jN3vNSrkGDrlnqQg=="],
|
||||||
|
|
||||||
|
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||||
|
|
||||||
|
"svgo": ["svgo@4.0.0", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.4.1" }, "bin": "./bin/svgo.js" }, "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw=="],
|
||||||
|
|
||||||
|
"thenby": ["thenby@1.3.4", "", {}, "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ=="],
|
||||||
|
|
||||||
|
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||||
|
|
||||||
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||||
|
|
||||||
|
"universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
|
||||||
|
|
||||||
|
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
|
||||||
|
|
||||||
|
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||||
|
|
||||||
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||||
|
|
||||||
|
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||||
|
|
||||||
|
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||||
|
|
||||||
|
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||||
|
|
||||||
|
"yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="],
|
||||||
|
|
||||||
|
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||||
|
|
||||||
|
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-cascade-layers/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-is-pseudo-class/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"@csstools/postcss-scope-pseudo-class/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"@csstools/selector-resolve-nested/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"@csstools/selector-specificity/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
||||||
|
|
||||||
|
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.10", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-uLfgBi+7IBNay8ECBO2mVMGZAc1VgZWEChxm4lv+TobGdG82LnXMjuNGo/BSSZZL4UmkWhxEHP2f5ziLNwGWMA=="],
|
||||||
|
|
||||||
|
"css-blank-pseudo/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"css-has-pseudo/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
|
||||||
|
|
||||||
|
"postcss-attribute-case-insensitive/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-calc/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-custom-selectors/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-dir-pseudo-class/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-discard-comments/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-focus-visible/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-focus-within/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-merge-rules/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-minify-selectors/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-nesting/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-pseudo-class-any-link/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-selector-not/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"postcss-unique-selectors/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"stylehacks/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
|
||||||
|
|
||||||
|
"svgo/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
|
||||||
|
|
||||||
|
"csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
19
package.json
Normal file
19
package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "passport-css-compiler",
|
||||||
|
"private": true,
|
||||||
|
"description": "A manifest to acquire CLI tools for passport. Not a Node app, only required for compiling CSS.",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "postcss src/styles/*.css !src/styles/base.css --dir src/assets/styles"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@fullhuman/postcss-purgecss": "^7.0.2",
|
||||||
|
"baseline-browser-mapping": "^2.9.2",
|
||||||
|
"cssnano": "^7.1.1",
|
||||||
|
"postcss": "^8.4.35",
|
||||||
|
"postcss-cli": "^11.0.0",
|
||||||
|
"postcss-import": "^16.1.1",
|
||||||
|
"postcss-preset-env": "^10.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
22
postcss.config.js
Normal file
22
postcss.config.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { purgeCSSPlugin } from "@fullhuman/postcss-purgecss";
|
||||||
|
import postcssPresetEnv from "postcss-preset-env";
|
||||||
|
import postcssImport from "postcss-import";
|
||||||
|
import cssnano from "cssnano";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
plugins: [
|
||||||
|
postcssImport,
|
||||||
|
purgeCSSPlugin({
|
||||||
|
content: ["./src/**/*.hbs", "./src/**/*.js"],
|
||||||
|
}),
|
||||||
|
postcssPresetEnv({
|
||||||
|
browsers: "last 4 versions",
|
||||||
|
// false *dsables* polyfills
|
||||||
|
features: {
|
||||||
|
"cascade-layers": false,
|
||||||
|
},
|
||||||
|
autoprefixer: false,
|
||||||
|
}),
|
||||||
|
cssnano,
|
||||||
|
],
|
||||||
|
};
|
||||||
Binary file not shown.
63
src/main.go
63
src/main.go
@@ -1,4 +1,4 @@
|
|||||||
//go:generate tailwindcss -i styles/main.scss -o assets/tailwind.css --minify
|
//go:generate bun run build
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ import (
|
|||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed assets/** templates/** schema.sql scripts/**.js styles/**.css
|
//go:embed assets/** templates/** schema.sql scripts/**.js
|
||||||
var embeddedAssets embed.FS
|
var embeddedAssets embed.FS
|
||||||
|
|
||||||
var devContent = `<script>
|
var devContent = `<script>
|
||||||
@@ -80,7 +80,15 @@ socket.addEventListener('message', (event) => {
|
|||||||
setTimeout(testPage, 150);
|
setTimeout(testPage, 150);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>`
|
</script>
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
outline-color: yellow;
|
||||||
|
outline-width: 5px;
|
||||||
|
outline-style: dashed;
|
||||||
|
outline-offset: -5px;
|
||||||
|
}
|
||||||
|
</style>`
|
||||||
|
|
||||||
var (
|
var (
|
||||||
insertCategoryStmt *sql.Stmt
|
insertCategoryStmt *sql.Stmt
|
||||||
@@ -285,7 +293,12 @@ func UploadFile(file *multipart.FileHeader, contentType string, c fiber.Ctx) (st
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName := fmt.Sprintf("%s.%s", fileId.String(), filepath.Ext(file.Filename))
|
var fileName string
|
||||||
|
if filepath.Ext(file.Filename) != ".svg" {
|
||||||
|
fileName = fmt.Sprintf("%s.webp", fileId.String())
|
||||||
|
} else {
|
||||||
|
fileName = fmt.Sprintf("%s.svg", fileId.String())
|
||||||
|
}
|
||||||
|
|
||||||
srcFile, err := file.Open()
|
srcFile, err := file.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -307,6 +320,10 @@ func UploadFile(file *multipart.FileHeader, contentType string, c fiber.Ctx) (st
|
|||||||
return "", errors.New("unsupported file type")
|
return "", errors.New("unsupported file type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
if contentType != "image/svg+xml" {
|
if contentType != "image/svg+xml" {
|
||||||
off, err := srcFile.Seek(0, io.SeekStart)
|
off, err := srcFile.Seek(0, io.SeekStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -715,6 +732,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileExtension := filepath.Ext(fileToEmbed)
|
fileExtension := filepath.Ext(fileToEmbed)
|
||||||
|
|
||||||
switch fileExtension {
|
switch fileExtension {
|
||||||
case ".js":
|
case ".js":
|
||||||
return fmt.Sprintf("<script>%s</script>", content)
|
return fmt.Sprintf("<script>%s</script>", content)
|
||||||
@@ -761,10 +779,13 @@ func main() {
|
|||||||
|
|
||||||
router.Use("/assets", static.New("", static.Config{
|
router.Use("/assets", static.New("", static.Config{
|
||||||
FS: assetsDir,
|
FS: assetsDir,
|
||||||
|
Browse: false,
|
||||||
MaxAge: 31536000,
|
MaxAge: 31536000,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
router.Get("/", func(c fiber.Ctx) error {
|
router.Get("/", func(c fiber.Ctx) error {
|
||||||
|
c.Response().Header.Set("Link", "</assets/fonts/InstrumentSans-VariableFont_wdth,wght.woff2>; rel=preload; as=font; type=font/woff2; crossorigin")
|
||||||
|
|
||||||
renderData := fiber.Map{
|
renderData := fiber.Map{
|
||||||
"SearchProviderURL": app.Config.SearchProvider.URL,
|
"SearchProviderURL": app.Config.SearchProvider.URL,
|
||||||
"SearchParam": app.Config.SearchProvider.Query,
|
"SearchParam": app.Config.SearchProvider.Query,
|
||||||
@@ -785,7 +806,7 @@ func main() {
|
|||||||
renderData["UptimeData"] = app.UptimeManager.GetUptime()
|
renderData["UptimeData"] = app.UptimeManager.GetUptime()
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render("views/index", renderData, "layouts/main")
|
return c.Render("views/index", renderData)
|
||||||
})
|
})
|
||||||
|
|
||||||
router.Use(middleware.AdminMiddleware(app.db))
|
router.Use(middleware.AdminMiddleware(app.db))
|
||||||
@@ -795,7 +816,7 @@ func main() {
|
|||||||
return c.Redirect().To("/admin")
|
return c.Redirect().To("/admin")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render("views/admin/login", fiber.Map{}, "layouts/main")
|
return c.Render("views/admin/login", fiber.Map{})
|
||||||
})
|
})
|
||||||
|
|
||||||
router.Post("/admin/login", func(c fiber.Ctx) error {
|
router.Post("/admin/login", func(c fiber.Ctx) error {
|
||||||
@@ -844,7 +865,8 @@ func main() {
|
|||||||
|
|
||||||
return c.Render("views/admin/index", fiber.Map{
|
return c.Render("views/admin/index", fiber.Map{
|
||||||
"Categories": app.CategoryManager.GetCategories(),
|
"Categories": app.CategoryManager.GetCategories(),
|
||||||
}, "layouts/admin")
|
"IsAdmin": true,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
api := router.Group("/api")
|
api := router.Group("/api")
|
||||||
@@ -997,8 +1019,13 @@ func main() {
|
|||||||
iconPath, err := UploadFile(file, contentType, c)
|
iconPath, err := UploadFile(file, contentType, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to upload file", "error", err)
|
slog.Error("Failed to upload file", "error", err)
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
status := fiber.StatusInternalServerError
|
||||||
"message": "Failed to upload file, please try again!",
|
if strings.Contains(err.Error(), "unsupported file type") {
|
||||||
|
status = fiber.StatusBadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(status).JSON(fiber.Map{
|
||||||
|
"message": "Failed to upload file: " + err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1089,8 +1116,13 @@ func main() {
|
|||||||
iconPath, err := UploadFile(file, contentType, c)
|
iconPath, err := UploadFile(file, contentType, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to upload file", "error", err)
|
slog.Error("Failed to upload file", "error", err)
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
status := fiber.StatusInternalServerError
|
||||||
"message": "Failed to upload file, please try again!",
|
if strings.Contains(err.Error(), "unsupported file type") {
|
||||||
|
status = fiber.StatusBadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(status).JSON(fiber.Map{
|
||||||
|
"message": "Failed to upload file: " + err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1207,8 +1239,13 @@ func main() {
|
|||||||
iconPath, err := UploadFile(file, contentType, c)
|
iconPath, err := UploadFile(file, contentType, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to upload file", "error", err)
|
slog.Error("Failed to upload file", "error", err)
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
status := fiber.StatusInternalServerError
|
||||||
"message": "Failed to upload file, please try again!",
|
if strings.Contains(err.Error(), "unsupported file type") {
|
||||||
|
status = fiber.StatusBadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(status).JSON(fiber.Map{
|
||||||
|
"message": "Failed to upload file: " + err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
// idfk what this variable capitalization is, it's a mess
|
// idfk what this variable capitalization is, it's a mess
|
||||||
let modalContainer = document.getElementById("modal-container");
|
let modalContainer = document.getElementById("modal-container");
|
||||||
let modal = modalContainer.querySelector("div");
|
let modal = modalContainer.querySelector("div");
|
||||||
@@ -9,38 +11,13 @@ let activeModal = null;
|
|||||||
let teleportStorage = document.getElementById("teleport-storage");
|
let teleportStorage = document.getElementById("teleport-storage");
|
||||||
let confirmActions = document.getElementById("confirm-actions");
|
let confirmActions = document.getElementById("confirm-actions");
|
||||||
let selectIconButton = document.getElementById("select-icon-button");
|
let selectIconButton = document.getElementById("select-icon-button");
|
||||||
|
let loadingSpinner = document.getElementById("template-loading-spinner");
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
modalContainer.classList.remove("hidden");
|
modalContainer.classList.remove("hidden");
|
||||||
modalContainer.classList.add("flex");
|
modalContainer.classList.add("flex");
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Submits a form to the given URL
|
|
||||||
* @param {Event} event - The event that triggered the function
|
|
||||||
* @param {string} url - The URL to submit the form to
|
|
||||||
* @param {"category" | "link"} target - The target to close the modal for
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function submitRequest(event, url, target) {
|
|
||||||
event.preventDefault();
|
|
||||||
let data = new FormData(event.target);
|
|
||||||
|
|
||||||
let res = await fetch(url, {
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.status === 201) {
|
|
||||||
closeModal(target);
|
|
||||||
document.getElementById(`${target}-form`).reset();
|
|
||||||
location.reload();
|
|
||||||
} else {
|
|
||||||
let json = await res.json();
|
|
||||||
document.getElementById(`${target}-message`).innerText = json.message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an event listener for the given from to error check after the first submit
|
* Adds an event listener for the given from to error check after the first submit
|
||||||
* @param {"category" | "link"} form - The form to initialize
|
* @param {"category" | "link"} form - The form to initialize
|
||||||
@@ -54,7 +31,7 @@ function addErrorListener(form) {
|
|||||||
event.target.parentElement
|
event.target.parentElement
|
||||||
.querySelectorAll("[required]")
|
.querySelectorAll("[required]")
|
||||||
.forEach((el) => {
|
.forEach((el) => {
|
||||||
el.classList.add("invalid:border-[#861024]!");
|
el.classList.add("invalid");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -74,16 +51,14 @@ function addErrorListener(form) {
|
|||||||
function cloneEditActions(primaryActions) {
|
function cloneEditActions(primaryActions) {
|
||||||
let editActions = document
|
let editActions = document
|
||||||
.getElementById("template-edit-actions")
|
.getElementById("template-edit-actions")
|
||||||
.cloneNode(true);
|
.content.firstElementChild.cloneNode(true);
|
||||||
editActions.removeAttribute("id");
|
|
||||||
editActions.classList.remove("hidden");
|
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (i = 0; i < primaryActions.length; i++) {
|
for (i = 0; i < primaryActions.length; i++) {
|
||||||
let actionButtonObj = primaryActions[i];
|
let actionButtonObj = primaryActions[i];
|
||||||
|
|
||||||
let actionButton = editActions.querySelector(
|
let actionButton = editActions.querySelector(
|
||||||
`div[data-primary-actions] button:nth-child(${i + 1})`
|
`div:first-child button:nth-child(${i + 1})`
|
||||||
);
|
);
|
||||||
actionButton.setAttribute("onclick", actionButtonObj.clickAction);
|
actionButton.setAttribute("onclick", actionButtonObj.clickAction);
|
||||||
actionButton.setAttribute("aria-label", actionButtonObj.label);
|
actionButton.setAttribute("aria-label", actionButtonObj.label);
|
||||||
@@ -92,6 +67,46 @@ function cloneEditActions(primaryActions) {
|
|||||||
return editActions;
|
return editActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function strToBase64(str) {
|
||||||
|
// TextEncoder: Always UTF8
|
||||||
|
const uint8Array = new TextEncoder().encode(str);
|
||||||
|
let binary = "";
|
||||||
|
|
||||||
|
for (let i = 0; i < uint8Array.length; ++i) {
|
||||||
|
binary += String.fromCharCode(uint8Array[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return btoa(binary);
|
||||||
|
}
|
||||||
|
function base64ToStr(base64Str) {
|
||||||
|
return atob(base64Str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the edit actions to be loading
|
||||||
|
* @param {HTMLElement} confirmButton The confirm button to set to loading
|
||||||
|
*/
|
||||||
|
function setConfirmLoading(confirmButton) {
|
||||||
|
const originalContents = strToBase64(confirmButton.innerHTML);
|
||||||
|
const loadingContents = `${loadingSpinner.innerHTML}`;
|
||||||
|
confirmButton.disabled = true;
|
||||||
|
// disable the cancel button too
|
||||||
|
confirmButton.nextElementSibling.disabled = true;
|
||||||
|
confirmButton.dataset.originContents = originalContents;
|
||||||
|
confirmButton.innerHTML = loadingContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the loading state of the confirm button
|
||||||
|
* @param {HTMLElement} confirmButton The confirm button to clear the loading state of
|
||||||
|
*/
|
||||||
|
function clearConfirmLoading(confirmButton) {
|
||||||
|
confirmButton.disabled = false;
|
||||||
|
confirmButton.nextElementSibling.disabled = false;
|
||||||
|
confirmButton.innerHTML = base64ToStr(confirmButton.dataset.originContents);
|
||||||
|
confirmButton.dataset.originContents = "";
|
||||||
|
}
|
||||||
|
|
||||||
addErrorListener("link");
|
addErrorListener("link");
|
||||||
document
|
document
|
||||||
.getElementById("link-form")
|
.getElementById("link-form")
|
||||||
@@ -99,14 +114,23 @@ document
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let data = new FormData(event.target);
|
let data = new FormData(event.target);
|
||||||
|
|
||||||
let res = await fetch(`/api/category/${targetCategoryID}/link`, {
|
const submitButton = event.target.querySelector("button");
|
||||||
|
let originalContents = submitButton.innerHTML;
|
||||||
|
|
||||||
|
submitButton.disabled = true;
|
||||||
|
submitButton.innerHTML = `${loadingSpinner.innerHTML}<span>Adding link...</span>`;
|
||||||
|
|
||||||
|
await fetch(`/api/category/${targetCategoryID}/link`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: data,
|
body: data,
|
||||||
});
|
})
|
||||||
|
.then(async (res) => {
|
||||||
if (res.status === 201) {
|
|
||||||
let json = await res.json();
|
let json = await res.json();
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(json.message);
|
||||||
|
}
|
||||||
|
|
||||||
let category = document.getElementById(
|
let category = document.getElementById(
|
||||||
`${targetCategoryID}_category`
|
`${targetCategoryID}_category`
|
||||||
);
|
);
|
||||||
@@ -114,13 +138,10 @@ document
|
|||||||
|
|
||||||
let newLinkCard = document
|
let newLinkCard = document
|
||||||
.getElementById("template-link-card")
|
.getElementById("template-link-card")
|
||||||
.cloneNode(true);
|
.content.firstElementChild.cloneNode(true);
|
||||||
|
|
||||||
newLinkCard.classList.remove("hidden");
|
|
||||||
newLinkCard.classList.add("link-card", "admin", "relative");
|
|
||||||
|
|
||||||
let newLinkImgElement = newLinkCard.querySelector(
|
let newLinkImgElement = newLinkCard.querySelector(
|
||||||
"div[data-img-container] img"
|
"div:first-child img"
|
||||||
);
|
);
|
||||||
|
|
||||||
newLinkImgElement.src = await processFile(data.get("icon"));
|
newLinkImgElement.src = await processFile(data.get("icon"));
|
||||||
@@ -154,11 +175,16 @@ document
|
|||||||
// after the close animation plays
|
// after the close animation plays
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.getElementById(`link-form`).reset();
|
document.getElementById(`link-form`).reset();
|
||||||
|
document.getElementById(`link-message`).innerText = "";
|
||||||
}, 300);
|
}, 300);
|
||||||
} else {
|
})
|
||||||
let json = await res.json();
|
.catch((err) => {
|
||||||
document.getElementById(`link-message`).innerText = json.message;
|
document.getElementById(`link-message`).innerText = err.message;
|
||||||
}
|
})
|
||||||
|
.finally(() => {
|
||||||
|
submitButton.disabled = false;
|
||||||
|
submitButton.innerHTML = originalContents;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addErrorListener("category");
|
addErrorListener("category");
|
||||||
@@ -168,22 +194,36 @@ document
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let data = new FormData(event.target);
|
let data = new FormData(event.target);
|
||||||
|
|
||||||
let res = await fetch(`/api/category`, {
|
const submitButton = event.target.querySelector("button");
|
||||||
|
const originalContents = submitButton.innerHTML;
|
||||||
|
|
||||||
|
submitButton.disabled = true;
|
||||||
|
submitButton.innerHTML = `${loadingSpinner.innerHTML}<span>Adding category...</span>`;
|
||||||
|
|
||||||
|
await fetch(`/api/category`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: data,
|
body: data,
|
||||||
});
|
})
|
||||||
|
.then(async (res) => {
|
||||||
if (res.status === 201) {
|
|
||||||
let json = await res.json();
|
let json = await res.json();
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(json.message);
|
||||||
|
}
|
||||||
|
|
||||||
let newCategory = document
|
let newCategory = document
|
||||||
.getElementById("template-category")
|
.getElementById("template-category")
|
||||||
.cloneNode(true);
|
.content.firstElementChild.cloneNode(true);
|
||||||
|
|
||||||
let linkGrid = newCategory.querySelector("div:nth-child(2)");
|
let linkGrid = newCategory.querySelector("div:nth-child(2)");
|
||||||
let categoryHeader = newCategory.querySelector(".category-header");
|
let categoryHeader =
|
||||||
categoryHeader.setAttribute("id", `${json.category.id}_category`);
|
newCategory.querySelector(".category-header");
|
||||||
categoryHeader.querySelector("h2").textContent = json.category.name;
|
categoryHeader.setAttribute(
|
||||||
|
"id",
|
||||||
|
`${json.category.id}_category`
|
||||||
|
);
|
||||||
|
categoryHeader.querySelector("h2").textContent =
|
||||||
|
json.category.name;
|
||||||
|
|
||||||
let editActions = cloneEditActions([
|
let editActions = cloneEditActions([
|
||||||
{
|
{
|
||||||
@@ -196,11 +236,12 @@ document
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
editActions.classList.add("pl-2");
|
editActions.classList.add("pl-2", "flex-shrink-0");
|
||||||
|
|
||||||
categoryHeader.appendChild(editActions);
|
categoryHeader.appendChild(editActions);
|
||||||
|
|
||||||
let categoryImg = categoryHeader.querySelector(".category-img");
|
let categoryImg =
|
||||||
|
categoryHeader.querySelector("div:first-child");
|
||||||
|
|
||||||
categoryImg.querySelector("img").src = await processFile(
|
categoryImg.querySelector("img").src = await processFile(
|
||||||
data.get("icon")
|
data.get("icon")
|
||||||
@@ -230,12 +271,17 @@ document
|
|||||||
// after the close animation plays
|
// after the close animation plays
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.getElementById(`category-form`).reset();
|
document.getElementById(`category-form`).reset();
|
||||||
|
document.getElementById(`category-message`).innerText = "";
|
||||||
}, 300);
|
}, 300);
|
||||||
} else {
|
})
|
||||||
let json = await res.json();
|
.catch((err) => {
|
||||||
document.getElementById(`category-message`).innerText =
|
document.getElementById(`category-message`).innerText =
|
||||||
json.message;
|
err.message;
|
||||||
}
|
})
|
||||||
|
.finally(() => {
|
||||||
|
submitButton.disabled = false;
|
||||||
|
submitButton.innerHTML = originalContents;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// when the background is clicked, close the modal
|
// when the background is clicked, close the modal
|
||||||
@@ -328,6 +374,9 @@ function closeModal() {
|
|||||||
document
|
document
|
||||||
.getElementById(activeModal + "-contents")
|
.getElementById(activeModal + "-contents")
|
||||||
.classList.add("hidden");
|
.classList.add("hidden");
|
||||||
|
if (document.getElementById(`${activeModal}-message`) !== null) {
|
||||||
|
document.getElementById(`${activeModal}-message`).innerText = "";
|
||||||
|
}
|
||||||
activeModal = null;
|
activeModal = null;
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
@@ -336,11 +385,11 @@ function closeModal() {
|
|||||||
.getElementById(activeModal + "-form")
|
.getElementById(activeModal + "-form")
|
||||||
.querySelectorAll("[required]")
|
.querySelectorAll("[required]")
|
||||||
.forEach((el) => {
|
.forEach((el) => {
|
||||||
el.classList.remove("invalid:border-[#861024]!");
|
el.classList.remove("invalid");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
targetCategoryID = null;
|
currentlyEditing = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,23 +421,38 @@ function unteleportElement(element) {
|
|||||||
teleportElement(element, teleportStorage);
|
teleportElement(element, teleportStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmEdit() {
|
/**
|
||||||
|
* Confirms the edit
|
||||||
|
* @param {Event} ev The event that triggered the function
|
||||||
|
*/
|
||||||
|
async function confirmEdit(ev) {
|
||||||
if (currentlyEditing.cleanup !== undefined) {
|
if (currentlyEditing.cleanup !== undefined) {
|
||||||
// this function could be called via deleting something, which doesn't have a cleanup function
|
// this function could be called via deleting something, which doesn't have a cleanup function
|
||||||
currentlyEditing.cleanup();
|
currentlyEditing.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let confirmButton = ev.target.closest("button");
|
||||||
|
|
||||||
|
try {
|
||||||
|
setConfirmLoading(confirmButton);
|
||||||
|
|
||||||
switch (currentlyEditing.type) {
|
switch (currentlyEditing.type) {
|
||||||
case "link":
|
case "link":
|
||||||
confirmLinkEdit();
|
await confirmLinkEdit();
|
||||||
break;
|
break;
|
||||||
case "category":
|
case "category":
|
||||||
confirmCategoryEdit();
|
await confirmCategoryEdit();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error("Unknown currentlyEditing type");
|
console.error("Unknown currentlyEditing type");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// TODO: tell the user that something went wrong?
|
||||||
|
console.error(err);
|
||||||
|
} finally {
|
||||||
|
clearConfirmLoading(confirmButton);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelEdit() {
|
function cancelEdit() {
|
||||||
@@ -417,22 +481,23 @@ function cancelEdit() {
|
|||||||
* @param {HTMLElement} target The target element that was clicked
|
* @param {HTMLElement} target The target element that was clicked
|
||||||
*/
|
*/
|
||||||
function editLink(target) {
|
function editLink(target) {
|
||||||
let startTime = performance.now();
|
|
||||||
|
|
||||||
// we do it in this dynamic way so that if we add a new link without refreshing the page, it still works
|
// we do it in this dynamic way so that if we add a new link without refreshing the page, it still works
|
||||||
let linkEl = target.closest(".link-card");
|
let linkEl = target.closest("[data-card]");
|
||||||
let linkID = parseInt(linkEl.id);
|
let linkID = parseInt(linkEl.id);
|
||||||
let categoryID = parseInt(linkEl.parentElement.previousElementSibling.id);
|
let categoryID = parseInt(linkEl.parentElement.previousElementSibling.id);
|
||||||
|
|
||||||
if (currentlyEditing.linkID !== undefined) {
|
if (
|
||||||
|
currentlyEditing.linkID !== undefined ||
|
||||||
|
currentlyEditing.categoryID !== undefined
|
||||||
|
) {
|
||||||
// cancel the edit if it's already in progress
|
// cancel the edit if it's already in progress
|
||||||
cancelEdit();
|
cancelEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
let linkImg = linkEl.querySelector("div[data-img-container] img");
|
let linkImg = linkEl.querySelector("div:first-child img");
|
||||||
let linkName = linkEl.querySelector("div[data-text-container] h3");
|
let linkName = linkEl.querySelector("div:nth-child(2) h3");
|
||||||
let linkDesc = linkEl.querySelector("div[data-text-container] p");
|
let linkDesc = linkEl.querySelector("div:nth-child(2) p");
|
||||||
let editActions = linkEl.querySelector("[data-edit-actions]");
|
let editActions = linkEl.querySelector("div:nth-child(3)");
|
||||||
|
|
||||||
currentlyEditing = {
|
currentlyEditing = {
|
||||||
type: "link",
|
type: "link",
|
||||||
@@ -447,14 +512,13 @@ function editLink(target) {
|
|||||||
throw new Error("failed to find link ID or category ID");
|
throw new Error("failed to find link ID or category ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
iconUploadInput.accept = "image/*";
|
iconUploadInput.accept = "image/jpeg,image/png,image/webp,image/svg+xml";
|
||||||
targetedImageElement = linkImg;
|
targetedImageElement = linkImg;
|
||||||
|
|
||||||
teleportElement(selectIconButton, linkImg.parentElement);
|
teleportElement(selectIconButton, linkImg.parentElement);
|
||||||
teleportElement(confirmActions, editActions);
|
teleportElement(confirmActions, editActions);
|
||||||
|
|
||||||
editActions.querySelector("div[data-primary-actions]").style.display =
|
editActions.querySelector("div:first-child").style.display = "none";
|
||||||
"none";
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
currentlyEditing.cleanup = replaceWithResizableTextarea([
|
currentlyEditing.cleanup = replaceWithResizableTextarea([
|
||||||
@@ -468,6 +532,10 @@ function editLink(target) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirms the edit of the link
|
||||||
|
* @param {Event} ev The event that triggered the function
|
||||||
|
*/
|
||||||
async function confirmLinkEdit() {
|
async function confirmLinkEdit() {
|
||||||
let linkEl = document.getElementById(`${currentlyEditing.linkID}_link`);
|
let linkEl = document.getElementById(`${currentlyEditing.linkID}_link`);
|
||||||
let linkNameInput = linkEl.querySelector("textarea");
|
let linkNameInput = linkEl.querySelector("textarea");
|
||||||
@@ -498,26 +566,23 @@ async function confirmLinkEdit() {
|
|||||||
formData.get("description") === null &&
|
formData.get("description") === null &&
|
||||||
formData.get("icon") === null
|
formData.get("icon") === null
|
||||||
) {
|
) {
|
||||||
|
cancelEdit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = await fetch(
|
await fetch(
|
||||||
`/api/category/${currentlyEditing.categoryID}/link/${currentlyEditing.linkID}`,
|
`/api/category/${currentlyEditing.categoryID}/link/${currentlyEditing.linkID}`,
|
||||||
{
|
{
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
body: formData,
|
body: formData,
|
||||||
}
|
}
|
||||||
);
|
).then(() => {
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
iconUploadInput.value = "";
|
iconUploadInput.value = "";
|
||||||
|
|
||||||
currentlyEditing.icon = undefined;
|
currentlyEditing.icon = undefined;
|
||||||
cancelLinkEdit(linkNameInput.value, linkDescInput.value);
|
cancelLinkEdit(linkNameInput.value, linkDescInput.value);
|
||||||
currentlyEditing = {};
|
currentlyEditing = {};
|
||||||
} else {
|
});
|
||||||
console.error("Failed to edit category");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelLinkEdit(
|
function cancelLinkEdit(
|
||||||
@@ -527,14 +592,14 @@ function cancelLinkEdit(
|
|||||||
let linkEl = document.getElementById(`${currentlyEditing.linkID}_link`);
|
let linkEl = document.getElementById(`${currentlyEditing.linkID}_link`);
|
||||||
let linkInput = linkEl.querySelector("textarea");
|
let linkInput = linkEl.querySelector("textarea");
|
||||||
let linkTextarea = linkInput.nextElementSibling;
|
let linkTextarea = linkInput.nextElementSibling;
|
||||||
let linkImg = linkEl.querySelector("div[data-img-container] img");
|
let linkImg = linkEl.querySelector("div:first-child img");
|
||||||
let editActions = linkEl.querySelector("[data-edit-actions]");
|
let editActions = linkEl.querySelector("div:nth-child(3)");
|
||||||
|
|
||||||
if (currentlyEditing.icon !== undefined) {
|
if (currentlyEditing.icon !== undefined) {
|
||||||
linkImg.src = currentlyEditing.icon;
|
linkImg.src = currentlyEditing.icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
editActions.querySelector("div[data-primary-actions]").style.display = "";
|
editActions.querySelector("div:first-child").style.display = "";
|
||||||
|
|
||||||
// teleport the teleported elements back to the body for literally safe keeping
|
// teleport the teleported elements back to the body for literally safe keeping
|
||||||
unteleportElement(selectIconButton);
|
unteleportElement(selectIconButton);
|
||||||
@@ -553,11 +618,14 @@ function cancelLinkEdit(
|
|||||||
*/
|
*/
|
||||||
function deleteLink(target) {
|
function deleteLink(target) {
|
||||||
// we do it in this dynamic way so that if we add a new link without refreshing the page, it still works
|
// we do it in this dynamic way so that if we add a new link without refreshing the page, it still works
|
||||||
let linkEl = target.closest(".link-card");
|
let linkEl = target.closest("[data-card]");
|
||||||
let linkID = parseInt(linkEl.id);
|
let linkID = parseInt(linkEl.id);
|
||||||
let categoryID = parseInt(linkEl.parentElement.previousElementSibling.id);
|
let categoryID = parseInt(linkEl.parentElement.previousElementSibling.id);
|
||||||
|
|
||||||
if (currentlyEditing.linkID !== undefined) {
|
if (
|
||||||
|
currentlyEditing.linkID !== undefined ||
|
||||||
|
currentlyEditing.categoryID !== undefined
|
||||||
|
) {
|
||||||
// cancel the edit if it's already in progress
|
// cancel the edit if it's already in progress
|
||||||
cancelEdit();
|
cancelEdit();
|
||||||
}
|
}
|
||||||
@@ -571,21 +639,47 @@ function deleteLink(target) {
|
|||||||
openModal("link-delete");
|
openModal("link-delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmDeleteLink() {
|
/**
|
||||||
let res = await fetch(
|
* Confirms the deletion of the link
|
||||||
|
* @param {Event} ev The event that triggered the function
|
||||||
|
*/
|
||||||
|
async function confirmDeleteLink(ev) {
|
||||||
|
const originalContents = ev.target.innerHTML;
|
||||||
|
const deleteButton = ev.target;
|
||||||
|
const cancelButton = deleteButton.nextElementSibling;
|
||||||
|
deleteButton.disabled = true;
|
||||||
|
cancelButton.disabled = true;
|
||||||
|
deleteButton.innerHTML = `${loadingSpinner.innerHTML}<span>Deleting link...</span>`;
|
||||||
|
|
||||||
|
await fetch(
|
||||||
`/api/category/${currentlyEditing.categoryID}/link/${currentlyEditing.linkID}`,
|
`/api/category/${currentlyEditing.categoryID}/link/${currentlyEditing.linkID}`,
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
let json = await res.json();
|
||||||
|
throw new Error(json.message);
|
||||||
|
}
|
||||||
|
|
||||||
if (res.status === 200) {
|
let linkEl = document.getElementById(
|
||||||
let linkEl = document.getElementById(`${currentlyEditing.linkID}_link`);
|
`${currentlyEditing.linkID}_link`
|
||||||
|
);
|
||||||
linkEl.remove();
|
linkEl.remove();
|
||||||
|
|
||||||
closeModal();
|
closeModal();
|
||||||
currentlyEditing = {};
|
currentlyEditing = {};
|
||||||
}
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
document.getElementById(`delete-link-message`).innerText =
|
||||||
|
err.message;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
deleteButton.disabled = false;
|
||||||
|
cancelButton.disabled = false;
|
||||||
|
deleteButton.innerHTML = originalContents;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -596,14 +690,17 @@ function editCategory(target) {
|
|||||||
let categoryEl = target.closest(".category-header");
|
let categoryEl = target.closest(".category-header");
|
||||||
let categoryID = parseInt(categoryEl.id);
|
let categoryID = parseInt(categoryEl.id);
|
||||||
|
|
||||||
if (currentlyEditing.linkID !== undefined) {
|
if (
|
||||||
|
currentlyEditing.linkID !== undefined ||
|
||||||
|
currentlyEditing.categoryID !== undefined
|
||||||
|
) {
|
||||||
// cancel the edit if it's already in progress
|
// cancel the edit if it's already in progress
|
||||||
cancelEdit();
|
cancelEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
let categoryName = categoryEl.querySelector("h2");
|
let categoryName = categoryEl.querySelector("h2");
|
||||||
let categoryIcon = categoryEl.querySelector("div[data-img-container] img");
|
let categoryIcon = categoryEl.querySelector("div:first-child img");
|
||||||
let editActions = categoryEl.querySelector("[data-edit-actions]");
|
let editActions = categoryEl.querySelector("div:nth-child(3)");
|
||||||
|
|
||||||
currentlyEditing = {
|
currentlyEditing = {
|
||||||
type: "category",
|
type: "category",
|
||||||
@@ -622,8 +719,7 @@ function editCategory(target) {
|
|||||||
teleportElement(selectIconButton, categoryIcon.parentElement);
|
teleportElement(selectIconButton, categoryIcon.parentElement);
|
||||||
teleportElement(confirmActions, editActions);
|
teleportElement(confirmActions, editActions);
|
||||||
|
|
||||||
editActions.querySelector("div[data-primary-actions]").style.display =
|
editActions.querySelector("div:first-child").style.display = "none";
|
||||||
"none";
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
currentlyEditing.cleanup = replaceWithResizableTextarea([
|
currentlyEditing.cleanup = replaceWithResizableTextarea([
|
||||||
@@ -659,15 +755,14 @@ async function confirmCategoryEdit() {
|
|||||||
|
|
||||||
// nothing to update
|
// nothing to update
|
||||||
if (formData.get("name") === null && formData.get("icon") === null) {
|
if (formData.get("name") === null && formData.get("icon") === null) {
|
||||||
|
cancelEdit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = await fetch(`/api/category/${currentlyEditing.categoryID}`, {
|
await fetch(`/api/category/${currentlyEditing.categoryID}`, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
}).then(() => {
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
iconUploadInput.value = "";
|
iconUploadInput.value = "";
|
||||||
|
|
||||||
currentlyEditing.icon = undefined;
|
currentlyEditing.icon = undefined;
|
||||||
@@ -675,9 +770,7 @@ async function confirmCategoryEdit() {
|
|||||||
cancelCategoryEdit(categoryInput.value);
|
cancelCategoryEdit(categoryInput.value);
|
||||||
|
|
||||||
currentlyEditing = {};
|
currentlyEditing = {};
|
||||||
} else {
|
});
|
||||||
console.error("Failed to edit category");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelCategoryEdit(text = currentlyEditing.originalText) {
|
function cancelCategoryEdit(text = currentlyEditing.originalText) {
|
||||||
@@ -686,8 +779,8 @@ function cancelCategoryEdit(text = currentlyEditing.originalText) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let categoryInput = categoryEl.querySelector("textarea");
|
let categoryInput = categoryEl.querySelector("textarea");
|
||||||
let categoryIcon = categoryEl.querySelector(".category-img img");
|
let categoryIcon = categoryEl.querySelector("div:first-child img");
|
||||||
let editActions = categoryEl.querySelector("[data-edit-actions]");
|
let editActions = categoryEl.querySelector("div:nth-child(3)");
|
||||||
|
|
||||||
if (currentlyEditing.icon !== undefined) {
|
if (currentlyEditing.icon !== undefined) {
|
||||||
categoryIcon.src = currentlyEditing.icon;
|
categoryIcon.src = currentlyEditing.icon;
|
||||||
@@ -696,7 +789,7 @@ function cancelCategoryEdit(text = currentlyEditing.originalText) {
|
|||||||
unteleportElement(selectIconButton);
|
unteleportElement(selectIconButton);
|
||||||
unteleportElement(confirmActions);
|
unteleportElement(confirmActions);
|
||||||
|
|
||||||
editActions.querySelector("div[data-primary-actions]").style.display = "";
|
editActions.querySelector("div:first-child").style.display = "";
|
||||||
|
|
||||||
restoreElementFromInput(categoryInput, text);
|
restoreElementFromInput(categoryInput, text);
|
||||||
|
|
||||||
@@ -711,7 +804,10 @@ function cancelCategoryEdit(text = currentlyEditing.originalText) {
|
|||||||
function deleteCategory(target) {
|
function deleteCategory(target) {
|
||||||
let categoryEl = target.closest(".category-header");
|
let categoryEl = target.closest(".category-header");
|
||||||
|
|
||||||
if (currentlyEditing.categoryID !== undefined) {
|
if (
|
||||||
|
currentlyEditing.categoryID !== undefined ||
|
||||||
|
currentlyEditing.linkID !== undefined
|
||||||
|
) {
|
||||||
// cancel the edit if it's already in progress
|
// cancel the edit if it's already in progress
|
||||||
cancelEdit();
|
cancelEdit();
|
||||||
}
|
}
|
||||||
@@ -727,11 +823,22 @@ function deleteCategory(target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function confirmDeleteCategory() {
|
async function confirmDeleteCategory() {
|
||||||
let res = await fetch(`/api/category/${currentlyEditing.categoryID}`, {
|
const originalContents = ev.target.innerHTML;
|
||||||
method: "DELETE",
|
const deleteButton = ev.target;
|
||||||
});
|
const cancelButton = deleteButton.nextElementSibling;
|
||||||
|
deleteButton.disabled = true;
|
||||||
|
cancelButton.disabled = true;
|
||||||
|
deleteButton.innerHTML = `${loadingSpinner.innerHTML}<span>Deleting category...</span>`;
|
||||||
|
|
||||||
|
await fetch(`/api/category/${currentlyEditing.categoryID}`, {
|
||||||
|
method: "DELETE",
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
let json = await res.json();
|
||||||
|
throw new Error(json.message);
|
||||||
|
}
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
let categoryEl = document.getElementById(
|
let categoryEl = document.getElementById(
|
||||||
`${currentlyEditing.categoryID}_category`
|
`${currentlyEditing.categoryID}_category`
|
||||||
);
|
);
|
||||||
@@ -742,7 +849,16 @@ async function confirmDeleteCategory() {
|
|||||||
|
|
||||||
closeModal();
|
closeModal();
|
||||||
currentlyEditing = {};
|
currentlyEditing = {};
|
||||||
}
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
document.getElementById(`delete-category-message`).innerText =
|
||||||
|
err.message;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
deleteButton.disabled = false;
|
||||||
|
cancelButton.disabled = false;
|
||||||
|
deleteButton.innerHTML = originalContents;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function roundToNearestHundredth(num) {
|
function roundToNearestHundredth(num) {
|
||||||
@@ -759,6 +875,7 @@ const stylesToCopy = [
|
|||||||
"letter-spacing",
|
"letter-spacing",
|
||||||
"text-transform",
|
"text-transform",
|
||||||
"text-align",
|
"text-align",
|
||||||
|
"text-wrap-style",
|
||||||
];
|
];
|
||||||
|
|
||||||
let _textMeasuringSpan,
|
let _textMeasuringSpan,
|
||||||
@@ -776,8 +893,6 @@ let _textMeasuringSpan,
|
|||||||
* @returns (() => void) A cleanup function to remove event listeners
|
* @returns (() => void) A cleanup function to remove event listeners
|
||||||
*/
|
*/
|
||||||
function replaceWithResizableTextarea(targetEls) {
|
function replaceWithResizableTextarea(targetEls) {
|
||||||
let startTime = performance.now();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} TargetInfo
|
* @typedef {Object} TargetInfo
|
||||||
* @property {HTMLElement} targetEl The element to replace.
|
* @property {HTMLElement} targetEl The element to replace.
|
||||||
@@ -812,11 +927,17 @@ function replaceWithResizableTextarea(targetEls) {
|
|||||||
parseFloat(computedStyle.borderTopWidth) +
|
parseFloat(computedStyle.borderTopWidth) +
|
||||||
parseFloat(computedStyle.borderBottomWidth);
|
parseFloat(computedStyle.borderBottomWidth);
|
||||||
|
|
||||||
let maxWidth = parentBoundingRect.width - borderWidth;
|
let maxWidth = parentBoundingRect.width;
|
||||||
// take care of category headers specifically because the parent bounding box contains two other elements
|
// take care of category headers specifically because the parent bounding box contains two other elements
|
||||||
if (targetEl.tagName === "H2") {
|
if (targetEl.tagName === "H2") {
|
||||||
|
let imageComputedStyle = window.getComputedStyle(
|
||||||
|
targetEl.previousElementSibling
|
||||||
|
);
|
||||||
|
|
||||||
let imageWidth =
|
let imageWidth =
|
||||||
targetEl.previousElementSibling.getBoundingClientRect().width;
|
targetEl.previousElementSibling.getBoundingClientRect().width +
|
||||||
|
parseFloat(imageComputedStyle.marginLeft) +
|
||||||
|
parseFloat(imageComputedStyle.marginRight);
|
||||||
let actionButtonWidth =
|
let actionButtonWidth =
|
||||||
targetEl.nextElementSibling.getBoundingClientRect().width;
|
targetEl.nextElementSibling.getBoundingClientRect().width;
|
||||||
|
|
||||||
@@ -898,11 +1019,12 @@ function replaceWithResizableTextarea(targetEls) {
|
|||||||
// step 3: batch writes
|
// step 3: batch writes
|
||||||
let inputElements = [];
|
let inputElements = [];
|
||||||
|
|
||||||
elsInitialStyles.forEach((elInfo) => {
|
elsInitialStyles.forEach((elInfo, i) => {
|
||||||
const inputElement = document.createElement("textarea");
|
const inputElement = document.createElement("textarea");
|
||||||
inputElement.value = elInfo.originalText;
|
inputElement.value = elInfo.originalText;
|
||||||
inputElement.className = "resizable-input";
|
inputElement.className = "resizable-input";
|
||||||
inputElement.placeholder = elInfo.targetEl.dataset.placeholder;
|
inputElement.placeholder =
|
||||||
|
i == 0 ? "Enter title..." : "Enter description...";
|
||||||
inputElement.dataset.originalElementType = elInfo.targetEl.tagName;
|
inputElement.dataset.originalElementType = elInfo.targetEl.tagName;
|
||||||
inputElement.dataset.originalClassName = elInfo.targetEl.className;
|
inputElement.dataset.originalClassName = elInfo.targetEl.className;
|
||||||
|
|
||||||
@@ -938,9 +1060,6 @@ function replaceWithResizableTextarea(targetEls) {
|
|||||||
|
|
||||||
function resize(inputElement, fill = false) {
|
function resize(inputElement, fill = false) {
|
||||||
const currentInputComputedStyle = window.getComputedStyle(inputElement);
|
const currentInputComputedStyle = window.getComputedStyle(inputElement);
|
||||||
const currentInputBorderWidth =
|
|
||||||
parseFloat(currentInputComputedStyle.borderLeftWidth) +
|
|
||||||
parseFloat(currentInputComputedStyle.borderRightWidth);
|
|
||||||
|
|
||||||
const currentParentElBoundingRectWidth =
|
const currentParentElBoundingRectWidth =
|
||||||
inputElement.parentElement.getBoundingClientRect().width;
|
inputElement.parentElement.getBoundingClientRect().width;
|
||||||
@@ -951,15 +1070,20 @@ function replaceWithResizableTextarea(targetEls) {
|
|||||||
|
|
||||||
// is it maybe a bit of some math that doesnt entirely make sense to me? you bet. But does it work? Hell yeah it does
|
// is it maybe a bit of some math that doesnt entirely make sense to me? you bet. But does it work? Hell yeah it does
|
||||||
if (inputElement.dataset.originalElementType === "H2") {
|
if (inputElement.dataset.originalElementType === "H2") {
|
||||||
|
let imageComputedStyle = window.getComputedStyle(
|
||||||
|
inputElement.previousElementSibling
|
||||||
|
);
|
||||||
|
|
||||||
let imageWidth =
|
let imageWidth =
|
||||||
inputElement.previousElementSibling.getBoundingClientRect()
|
inputElement.previousElementSibling.getBoundingClientRect()
|
||||||
.width;
|
.width +
|
||||||
|
parseFloat(imageComputedStyle.marginLeft) +
|
||||||
|
parseFloat(imageComputedStyle.marginRight);
|
||||||
let actionButtonWidth =
|
let actionButtonWidth =
|
||||||
inputElement.nextElementSibling.getBoundingClientRect().width;
|
inputElement.nextElementSibling.getBoundingClientRect().width;
|
||||||
|
|
||||||
// the brain cells rub together and this vaguely makes sense to me I think but I cant explain it
|
// the brain cells rub together and this vaguely makes sense to me I think but I cant explain it
|
||||||
maxWidth -= imageWidth + actionButtonWidth + caretBuffer;
|
maxWidth -= imageWidth + actionButtonWidth;
|
||||||
maxWidth += currentInputBorderWidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentContentWidth;
|
let currentContentWidth;
|
||||||
@@ -992,9 +1116,7 @@ function replaceWithResizableTextarea(targetEls) {
|
|||||||
_textMeasuringSpan.getBoundingClientRect().width;
|
_textMeasuringSpan.getBoundingClientRect().width;
|
||||||
|
|
||||||
currentContentWidth = Math.min(
|
currentContentWidth = Math.min(
|
||||||
roundToNearestHundredth(
|
roundToNearestHundredth(measuredTextWidth) + caretBuffer,
|
||||||
measuredTextWidth + currentInputBorderWidth
|
|
||||||
) + caretBuffer,
|
|
||||||
maxWidth
|
maxWidth
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type UptimeRobotSite struct {
|
|||||||
FriendlyName string `json:"friendly_name"`
|
FriendlyName string `json:"friendly_name"`
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
|
Up bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UptimeManager struct {
|
type UptimeManager struct {
|
||||||
@@ -104,6 +105,10 @@ func (u *UptimeManager) update() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i, monitor := range monitors.Monitors {
|
||||||
|
monitors.Monitors[i].Up = monitor.Status == 2
|
||||||
|
}
|
||||||
|
|
||||||
u.mutex.Lock()
|
u.mutex.Lock()
|
||||||
u.sites = monitors.Monitors
|
u.sites = monitors.Monitors
|
||||||
u.lastUpdate = time.Now()
|
u.lastUpdate = time.Now()
|
||||||
|
|||||||
@@ -1,22 +1,41 @@
|
|||||||
.modal-bg {
|
@import "./base.css";
|
||||||
|
@import "./card.css";
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.modal-bg {
|
||||||
|
position: fixed;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
inset: 0;
|
||||||
|
background-color: color-mix(in srgb, #000 45%, #0000);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.modal-bg.is-visible {
|
.modal-bg.is-visible {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
background-color: var(--color-overlay);
|
||||||
|
border-radius: calc(var(--spacing) * 3);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: calc(var(--spacing) * 4);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 24rem;
|
||||||
|
}
|
||||||
|
|
||||||
.modal.is-visible {
|
.modal.is-visible {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
#blur-target {
|
||||||
|
transition: filter 300ms cubic-bezier(0.45, 0, 0.55, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
.modal-bg {
|
.modal-bg {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -45,9 +64,130 @@
|
|||||||
transform: translateY(0) scale(1);
|
transform: translateY(0) scale(1);
|
||||||
transition-delay: 0s;
|
transition-delay: 0s;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.action-button {
|
#blur-target {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: calc(var(--spacing) * 2);
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
& > button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
column-gap: calc(var(--spacing) * 2);
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
color: #fff;
|
||||||
|
border-radius: calc(var(--spacing) * 1.5);
|
||||||
|
padding-inline: calc(var(--spacing) * 4);
|
||||||
|
padding-block: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-modal {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
& > p {
|
||||||
|
margin-bottom: calc(var(--spacing) * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: calc(var(--spacing) * 2);
|
||||||
|
|
||||||
|
& > button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
column-gap: calc(var(--spacing) * 2);
|
||||||
|
padding-inline: calc(var(--spacing) * 4);
|
||||||
|
padding-block: calc(var(--spacing) * 2);
|
||||||
|
border-radius: calc(var(--spacing) * 1.5);
|
||||||
|
width: 100%;
|
||||||
|
color: #fff;
|
||||||
|
transition: filter 300ms cubic-bezier(0.45, 0, 0.55, 1);
|
||||||
|
|
||||||
|
&:nth-child(1) {
|
||||||
|
background-color: var(--color-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
border: 1px solid var(--color-highlight);
|
||||||
|
background-color: #0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not([disabled]) {
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(125%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
filter: brightness(95%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input:invalid.invalid {
|
||||||
|
border: 1px solid var(--color-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-link-card {
|
||||||
|
border: calc(var(--spacing) * 0.5) dashed var(--color-subtle);
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-grid > div > div:nth-child(3) {
|
||||||
|
position: absolute;
|
||||||
|
right: var(--spacing);
|
||||||
|
top: var(--spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-header > div:nth-child(2) {
|
||||||
|
padding-left: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-category-button {
|
||||||
|
width: fit-content;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--color-subtle);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-category-button > h2 {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-style: dashed;
|
||||||
|
text-decoration-thickness: calc(var(--spacing) * 0.5);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
@@ -60,6 +200,7 @@
|
|||||||
transition: filter 0.15s cubic-bezier(0.45, 0, 0.55, 1);
|
transition: filter 0.15s cubic-bezier(0.45, 0, 0.55, 1);
|
||||||
contain: layout style paint;
|
contain: layout style paint;
|
||||||
|
|
||||||
|
&:not([disabled]) {
|
||||||
&:hover {
|
&:hover {
|
||||||
filter: brightness(125%);
|
filter: brightness(125%);
|
||||||
}
|
}
|
||||||
@@ -67,4 +208,46 @@
|
|||||||
&:active {
|
&:active {
|
||||||
filter: brightness(95%);
|
filter: brightness(95%);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-icon-button {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: color-mix(in srgb, var(--color-highlight) 70%, #0000);
|
||||||
|
color: var(--color-base);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[disabled] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
filter: brightness(75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding: calc(var(--spacing) * 3);
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
text-decoration: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: calc(var(--spacing) * 2);
|
||||||
|
color: var(--color-text);
|
||||||
|
border-bottom: 1px solid var(--color-text);
|
||||||
|
justify-content: center;
|
||||||
|
line-height: var(--leading-condensed);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
199
src/styles/base.css
Normal file
199
src/styles/base.css
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
@layer reset, base, components, utilities;
|
||||||
|
@font-face {
|
||||||
|
font-family: "Instrument Sans";
|
||||||
|
src: url("/assets/fonts/InstrumentSans-VariableFont_wdth,wght.woff2")
|
||||||
|
format("woff2");
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer reset {
|
||||||
|
/*
|
||||||
|
Josh's Custom CSS Reset slightly Modified
|
||||||
|
https://www.joshwcomeau.com/css/custom-css-reset/
|
||||||
|
*/
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
border: 0 solid;
|
||||||
|
line-height: calc(1em + 0.5rem);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
picture,
|
||||||
|
video,
|
||||||
|
canvas,
|
||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-wrap: pretty;
|
||||||
|
hyphens: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--family-sans: "Instrument Sans", ui-sans-serif, system-ui, sans-serif,
|
||||||
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||||
|
"Noto Color Emoji";
|
||||||
|
--color-accent: oklch(57.93% 0.258 294.12);
|
||||||
|
--color-success: oklch(70.19% 0.158 160.44);
|
||||||
|
--color-error: oklch(53% 0.251 28.48);
|
||||||
|
|
||||||
|
--color-base: oklch(11% 0.007 285);
|
||||||
|
--color-surface: oklch(19% 0.007 285.66);
|
||||||
|
--color-overlay: oklch(26% 0.008 285.66);
|
||||||
|
|
||||||
|
--color-muted: oklch(63% 0.015 286);
|
||||||
|
--color-subtle: oklch(72% 0.015 286);
|
||||||
|
--color-text: oklch(87% 0.015 286);
|
||||||
|
|
||||||
|
--color-highlight-sm: oklch(30.67% 0.007 286);
|
||||||
|
--color-highlight: oklch(39.26% 0.01 286);
|
||||||
|
--color-highlight-lg: oklch(47.72% 0.011 286);
|
||||||
|
|
||||||
|
--spacing: 0.25rem;
|
||||||
|
|
||||||
|
--leading-condensed: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
font-family: var(--family-sans);
|
||||||
|
color-scheme: dark;
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: clamp(42px, 10vw, 64px);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: clamp(30px, 6vw, 36px);
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:not(.search) {
|
||||||
|
color: var(--color-text);
|
||||||
|
padding-inline: calc(var(--spacing) * 4);
|
||||||
|
padding-block: calc(var(--spacing) * 2);
|
||||||
|
|
||||||
|
border-radius: calc(var(--spacing) * 1.5);
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-highlight) 70%, #0000);
|
||||||
|
|
||||||
|
transition-property: color, border, background-color;
|
||||||
|
transition-duration: 300ms;
|
||||||
|
transition-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--color-highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[type="file"] {
|
||||||
|
padding: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&::file-selector-button {
|
||||||
|
border: 0px;
|
||||||
|
padding: calc(var(--spacing) * 2);
|
||||||
|
margin-right: var(--spacing);
|
||||||
|
background-color: var(--color-highlight);
|
||||||
|
color: var(--color-subtle);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leading-condensed {
|
||||||
|
line-height: var(--leading-condensed);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-error {
|
||||||
|
color: var(--color-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-success {
|
||||||
|
color: var(--color-success);
|
||||||
|
}
|
||||||
|
}
|
||||||
157
src/styles/card.css
Normal file
157
src/styles/card.css
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/* All css related to the card and category stuff */
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.link-grid > :is(a, div) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
border-radius: calc(var(--spacing) * 4);
|
||||||
|
padding: calc(var(--spacing) * 2.5);
|
||||||
|
align-items: center;
|
||||||
|
transition-property: box-shadow, transform, translate;
|
||||||
|
transition-duration: 150ms;
|
||||||
|
transition-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
|
||||||
|
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1),
|
||||||
|
0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||||
|
contain: layout style paint;
|
||||||
|
|
||||||
|
&:not(:is(div)) {
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1),
|
||||||
|
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
box-shadow: 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||||
|
transform: translateY(2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.new-link-card) {
|
||||||
|
text-decoration: none;
|
||||||
|
background: var(--color-overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.link-grid > :is(a, div) {
|
||||||
|
transition: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Div that holds the image */
|
||||||
|
.link-grid > :is(a, div) > div:first-child {
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: calc(var(--spacing) * 2);
|
||||||
|
border-radius: calc(var(--spacing) * 2.5);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-grid > :is(a, div) > div:first-child img {
|
||||||
|
user-select: none;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Div that holds the text */
|
||||||
|
.link-grid > :is(a, div) > div:nth-child(2) {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-grid > :is(a, div) > div:nth-child(2) h3 {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-grid > :is(a, div) > div:nth-child(2) p {
|
||||||
|
color: var(--color-subtle);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
border: 1px solid #0000;
|
||||||
|
min-height: calc(1em + 0.5rem);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
min-height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-header > div:first-child {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
position: relative;
|
||||||
|
margin-right: calc(var(--spacing) * 2);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: calc(var(--spacing) * 8);
|
||||||
|
height: calc(var(--spacing) * 8);
|
||||||
|
border-radius: calc(var(--spacing) * 1.5);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categoy-header > div:first-child img {
|
||||||
|
user-select: none;
|
||||||
|
object-fit: cover;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-header h2 {
|
||||||
|
text-transform: capitalize;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: #0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr));
|
||||||
|
gap: calc(var(--spacing) * 2);
|
||||||
|
padding: calc(var(--spacing) * 2.5);
|
||||||
|
contain: layout style paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Empty state */
|
||||||
|
.link-grid > p {
|
||||||
|
color: var(--color-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-section > div {
|
||||||
|
width: 100%;
|
||||||
|
padding: calc(var(--spacing) * 2.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.card-section > div {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.flex-shrink-0 {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl-2 {
|
||||||
|
padding-left: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/styles/login.css
Normal file
58
src/styles/login.css
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
@import "./base.css";
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
background-color: var(--color-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.login-container {
|
||||||
|
width: fit-content;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
border-radius: calc(var(--spacing) * 3);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container > img {
|
||||||
|
height: calc(var(--spacing) * 96);
|
||||||
|
width: calc(var(--spacing) * 64);
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: calc(var(--spacing) * 4);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: calc(var(--spacing) * 3);
|
||||||
|
margin-top: calc(var(--spacing) * 2);
|
||||||
|
margin-bottom: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form button {
|
||||||
|
padding-left: calc(var(--spacing) * 4);
|
||||||
|
padding-right: calc(var(--spacing) * 4);
|
||||||
|
padding-top: calc(var(--spacing) * 2);
|
||||||
|
padding-bottom: calc(var(--spacing) * 2);
|
||||||
|
|
||||||
|
border-radius: calc(var(--spacing) * 2.5);
|
||||||
|
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
133
src/styles/main.css
Normal file
133
src/styles/main.css
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
@import "./base.css";
|
||||||
|
@import "./card.css";
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.hero {
|
||||||
|
/* grid grid-rows-3 grid-cols-[1fr] justify-center items-center h-screen bg-base */
|
||||||
|
display: grid;
|
||||||
|
grid-template: repeat(3, minmax(0, 1fr)) / 1fr;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: var(--color-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glance-container {
|
||||||
|
display: flex;
|
||||||
|
color: var(--color-subtle);
|
||||||
|
height: 100%;
|
||||||
|
padding: calc(var(--spacing) * 2.5);
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-hero-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
grid-row-start: 2;
|
||||||
|
padding-left: calc(var(--spacing) * 3);
|
||||||
|
padding-right: calc(var(--spacing) * 3);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-hero-container > div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: calc(var(--spacing) * 2.5);
|
||||||
|
|
||||||
|
& > svg {
|
||||||
|
margin-right: calc(var(--spacing) * 3);
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
width: clamp(42px, 10vw, 60px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-hero-container > form {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 48rem;
|
||||||
|
|
||||||
|
& > input {
|
||||||
|
color: #fff;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
border: 1px solid
|
||||||
|
color-mix(in srgb, var(--color-highlight-sm) 70%, #0000);
|
||||||
|
padding-left: calc(var(--spacing) * 3);
|
||||||
|
padding-right: calc(var(--spacing) * 3);
|
||||||
|
padding-top: var(--spacing);
|
||||||
|
padding-bottom: var(--spacing);
|
||||||
|
height: calc(var(--spacing) * 7);
|
||||||
|
border-radius: 9999px;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--color-highlight);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.weather-data {
|
||||||
|
display: flex;
|
||||||
|
height: fit-content;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weather-data span {
|
||||||
|
margin-right: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uptime-data {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: end;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
margin-right: calc(var(--spacing) * 2);
|
||||||
|
line-height: var(--leading-condensed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.uptime-status {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
width: calc(var(--spacing) * 2);
|
||||||
|
height: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uptime-status > svg {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uptime-status > svg:nth-child(1) {
|
||||||
|
position: absolute;
|
||||||
|
animation: ping 1s linear infinite;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.animate-ping {
|
||||||
|
animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ping {
|
||||||
|
75%,
|
||||||
|
100% {
|
||||||
|
transform: scale(2);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
@import "tailwindcss";
|
|
||||||
|
|
||||||
@theme {
|
|
||||||
--color-accent: oklch(57.93% 0.258 294.12);
|
|
||||||
--color-success: oklch(70.19% 0.158 160.44);
|
|
||||||
--color-error: oklch(53% 0.251 28.48);
|
|
||||||
|
|
||||||
--color-base: oklch(11% 0.007 285);
|
|
||||||
--color-surface: oklch(19% 0.007 285.66);
|
|
||||||
--color-overlay: oklch(26% 0.008 285.66);
|
|
||||||
|
|
||||||
--color-muted: oklch(63% 0.015 286);
|
|
||||||
--color-subtle: oklch(72% 0.015 286);
|
|
||||||
--color-text: oklch(87% 0.015 286);
|
|
||||||
|
|
||||||
--color-highlight-sm: oklch(30.67% 0.007 286);
|
|
||||||
--color-highlight: oklch(39.26% 0.01 286);
|
|
||||||
--color-highlight-lg: oklch(47.72% 0.011 286);
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Instrument Sans";
|
|
||||||
src: url("/assets/fonts/InstrumentSans-VariableFont_wdth,wght.woff2")
|
|
||||||
format("woff2");
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--default-font-family: "Instrument Sans", ui-sans-serif, system-ui,
|
|
||||||
sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
|
||||||
"Noto Color Emoji";
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
line-height: normal;
|
|
||||||
color-scheme: dark;
|
|
||||||
color: var(--color-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer base {
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: clamp(42px, 10vw, 64px);
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: clamp(30px, 6vw, 36px);
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:not(.search) {
|
|
||||||
@apply px-4 py-2 rounded-md w-full bg-surface border border-highlight/70 placeholder:text-highlight text-text focus-visible:outline-none transition-colors duration-300 ease-out overflow-hidden;
|
|
||||||
|
|
||||||
&[type="file"] {
|
|
||||||
@apply p-0 cursor-pointer;
|
|
||||||
|
|
||||||
&::file-selector-button {
|
|
||||||
@apply px-2 py-2 mr-1 bg-highlight text-subtle cursor-pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card {
|
|
||||||
background: var(--color-overlay);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
text-decoration: none;
|
|
||||||
border-radius: 1rem;
|
|
||||||
padding: 0.625rem;
|
|
||||||
align-items: center;
|
|
||||||
transition-property: box-shadow, transform, translate;
|
|
||||||
transition-duration: 150ms;
|
|
||||||
transition-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
|
|
||||||
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
||||||
contain: layout style paint;
|
|
||||||
|
|
||||||
&:not(.admin) {
|
|
||||||
&:hover {
|
|
||||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1),
|
|
||||||
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
||||||
transform: translateY(-4px);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
box-shadow: 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
||||||
transform: translateY(2px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.link-card {
|
|
||||||
transition: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Div that holds the image */
|
|
||||||
.link-card div[data-img-container] {
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding-right: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card div[data-img-container] img {
|
|
||||||
user-select: none;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
aspect-ratio: 1/1;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Div that holds the text */
|
|
||||||
.link-card div[data-text-container] {
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
row-gap: 1px;
|
|
||||||
overflow: hidden;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card div[data-text-container] p {
|
|
||||||
color: var(--color-subtle);
|
|
||||||
white-space: pre-wrap;
|
|
||||||
border: 1px solid #0000;
|
|
||||||
min-height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-link-card {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0.625rem;
|
|
||||||
border: 0.125rem dashed var(--color-subtle);
|
|
||||||
border-radius: 1rem;
|
|
||||||
transition: box-shadow, transofrm 150ms cubic-bezier(0.45, 0, 0.55, 1);
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.categoy-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-header div[data-img-container] {
|
|
||||||
@apply shrink-0 relative mr-2 h-full flex items-center justify-center size-8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categoy-header div[data-img-container] img {
|
|
||||||
user-select: none;
|
|
||||||
object-fit: cover;
|
|
||||||
aspect-ratio: 1/1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-header h2 {
|
|
||||||
text-transform: capitalize;
|
|
||||||
word-break: break-all;
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: #0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr));
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0.625rem;
|
|
||||||
contain: layout style paint;
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>Passport</title>
|
|
||||||
<link rel="favicon" href="/favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous"
|
|
||||||
href="/assets/fonts/InstrumentSans-VariableFont_wdth,wght.woff2" />
|
|
||||||
{{{embedFile "assets/tailwind.css"}}}
|
|
||||||
{{{embedFile "styles/adminUi.css"}}}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-surface text-text">
|
|
||||||
{{embed}}
|
|
||||||
</body>
|
|
||||||
|
|
||||||
{{{devContent}}}
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>Passport</title>
|
|
||||||
<link rel="favicon" href="/favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous"
|
|
||||||
href="/assets/fonts/InstrumentSans-VariableFont_wdth,wght.woff2" />
|
|
||||||
{{{embedFile "assets/tailwind.css"}}}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-surface text-text">
|
|
||||||
{{embed}}
|
|
||||||
</body>
|
|
||||||
|
|
||||||
{{{devContent}}}
|
|
||||||
|
|
||||||
</html>
|
|
||||||
111
src/templates/partials/category-grid.hbs
Normal file
111
src/templates/partials/category-grid.hbs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<section class="card-section">
|
||||||
|
<div>
|
||||||
|
{{#each Categories}}
|
||||||
|
<div class="category-header" id="{{this.ID}}_category">
|
||||||
|
<div>
|
||||||
|
<img width="32" height="32" draggable="false" alt="{{this.Name}}" src="{{this.Icon}}" />
|
||||||
|
</div>
|
||||||
|
<h2>{{this.Name}}</h2>
|
||||||
|
{{#if IsAdmin}}
|
||||||
|
<div class="flex-shrink-0 pl-2">
|
||||||
|
<div class="action-container">
|
||||||
|
<button aria-label="Edit category" onclick="editCategory(this)" class="action-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<use href="#edit-icon" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button aria-label="Delete category" onclick="deleteCategory(this)"
|
||||||
|
class="text-error action-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<use href="#trash-icon" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="link-grid">
|
||||||
|
{{#each this.Links}}
|
||||||
|
|
||||||
|
{{#if IsAdmin}}<div data-card id="{{this.ID}}_link" {{else}} <a href="{{this.URL}}" draggable="false"
|
||||||
|
target="_blank" rel="noreferrer" {{/if}}>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<img width="64" height="64" draggable="false" src="{{this.Icon}}" alt="{{this.Name}}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>{{this.Name}}</h3>
|
||||||
|
<p>{{this.Description}}</p>
|
||||||
|
</div>
|
||||||
|
{{#if IsAdmin}}
|
||||||
|
<div>
|
||||||
|
<div class="action-container">
|
||||||
|
<button aria-label="Edit link" onclick="editLink(this)" class="action-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<use href="#edit-icon" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button aria-label="Delete link" onclick="deleteLink(this)" class="text-error action-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<use href="#trash-icon" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if IsAdmin}}
|
||||||
|
</div {{else}} </a {{/if}}>
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
{{#unless IsAdmin}}
|
||||||
|
<p class="text-subtle">No links here, add one!</p>
|
||||||
|
{{/unless}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#if IsAdmin}}
|
||||||
|
<div onclick="openModal('link', {{this.ID}})" class="new-link-card link-card admin">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24">
|
||||||
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
stroke-width="2" d="M12 5v14m-7-7h14" />
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<h3>Add a link</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if }}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#if IsAdmin}}
|
||||||
|
<div class="add-category-button" id="add-category-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
|
||||||
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M12 5v14m-7-7h14" />
|
||||||
|
</svg>
|
||||||
|
<h2 onclick="openModal('category')">
|
||||||
|
Add a new category
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- store the svg icons here so that they can be reused -->
|
||||||
|
{{#if IsAdmin}}
|
||||||
|
<div class="hidden">
|
||||||
|
<svg id="edit-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||||
|
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
||||||
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||||
|
<path d="M7 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-1" />
|
||||||
|
<path d="M20.385 6.585a2.1 2.1 0 0 0-2.97-2.97L9 12v3h3zM16 5l3 3" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg id="trash-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||||
|
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
||||||
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M4 7h16m-10 4v6m4-6v6M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<div id="category-contents" class="hidden">
|
<div id="category-contents" class="hidden">
|
||||||
<h3>Create A category</h3>
|
<h3>Create A category</h3>
|
||||||
<form id="category-form" action="/api/categories" method="post"
|
<form id="category-form" action="/api/categories" method="post" class="modal-form">
|
||||||
class="flex flex-col gap-y-3 my-2 [&>div]:flex [&>div]:flex-col [&>div]:gap-1">
|
|
||||||
<div>
|
<div>
|
||||||
<label for="categoryName">Name</label>
|
<label for="categoryName">Name</label>
|
||||||
<input required type="text" name="name" id="categoryName" maxlength="50" />
|
<input required type="text" name="name" id="categoryName" maxlength="50" />
|
||||||
@@ -10,7 +9,7 @@
|
|||||||
<label for="linkIcon">Icon</label>
|
<label for="linkIcon">Icon</label>
|
||||||
<input type="file" name="icon" id="linkIcon" accept=".svg" required />
|
<input type="file" name="icon" id="linkIcon" accept=".svg" required />
|
||||||
</div>
|
</div>
|
||||||
<button class="px-4 py-2 rounded-md w-full bg-accent text-white border-0" type="submit">Create
|
<button type="submit">Create
|
||||||
category</button>
|
category</button>
|
||||||
</form>
|
</form>
|
||||||
<span id="category-message"></span>
|
<span id="category-message"></span>
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<div id="category-delete-contents" class="hidden text-center">
|
<div id="category-delete-contents" class="hidden delete-modal">
|
||||||
<h3>Are you sure you want to delete this category?</h3>
|
<h3>Are you sure you want to delete this category?</h3>
|
||||||
<p class="mb-3">You are about to delete the category <strong id="category-name"></strong>. This action cannot be
|
<p>You are about to delete the category <strong id="category-name"></strong>. This action cannot be
|
||||||
undone.
|
undone.
|
||||||
All links associated with this category will also be deleted. Are you sure you want to continue?</p>
|
All links associated with this category will also be deleted. Are you sure you want to continue?</p>
|
||||||
<div class="flex justify-end flex-col gap-y-2">
|
<div>
|
||||||
<button class="px-4 py-2 rounded-md w-full bg-error text-white border-0"
|
<button onclick="confirmDeleteCategory(event)">Delete
|
||||||
onclick="confirmDeleteCategory()">Delete
|
|
||||||
category</button>
|
category</button>
|
||||||
<button class="px-4 py-2 rounded-md w-full bg-overlay border border-highlight text-white"
|
<button onclick="closeModal()">Cancel</button>
|
||||||
onclick="closeModal()">Cancel</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span id="delete-category-message"></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<div id="link-delete-contents" class="hidden text-center">
|
<div id="link-delete-contents" class="hidden delete-modal">
|
||||||
<h3>Are you sure you want to delete this link?</h3>
|
<h3>Are you sure you want to delete this link?</h3>
|
||||||
<p class="mb-3">You are about to delete the link <strong id="link-name"></strong>. This action cannot be undone. Are
|
<p>You are about to delete the link <strong id="link-name"></strong>. This action cannot be undone. Are
|
||||||
you sure you
|
you sure you
|
||||||
want to continue?</p>
|
want to continue?</p>
|
||||||
<div class="flex justify-end flex-col gap-y-2">
|
<div>
|
||||||
<button class="px-4 py-2 rounded-md w-full bg-error text-white border-0" onclick="confirmDeleteLink()">Delete
|
<button onclick="confirmDeleteLink(event)">Delete
|
||||||
link</button>
|
link</button>
|
||||||
<button class="px-4 py-2 rounded-md w-full bg-overlay border border-highlight text-white"
|
<button onclick="closeModal()">Cancel</button>
|
||||||
onclick="closeModal()">Cancel</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span id="delete-link-message"></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<div id="link-contents" class="hidden">
|
<div id="link-contents" class="hidden">
|
||||||
<h3>Add A link</h3>
|
<h3>Add A link</h3>
|
||||||
<form id="link-form" action="/api/links" method="post"
|
<form id="link-form" action="/api/links" method="post" class="modal-form">
|
||||||
class="flex flex-col gap-y-3 my-2 [&>div]:flex [&>div]:flex-col [&>div]:gap-1">
|
|
||||||
<div>
|
<div>
|
||||||
<label for="linkName">Name</label>
|
<label for="linkName">Name</label>
|
||||||
<input required type="text" name="name" id="linkName" maxlength="50" />
|
<input required type="text" name="name" id="linkName" maxlength="50" />
|
||||||
@@ -16,9 +15,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="linkIcon">Icon</label>
|
<label for="linkIcon">Icon</label>
|
||||||
<input required type="file" name="icon" id="linkIcon" accept="image/*" />
|
<input required type="file" name="icon" id="linkIcon"
|
||||||
|
accept="image/jpeg,image/png,image/webp,image/svg+xml" />
|
||||||
</div>
|
</div>
|
||||||
<button class="px-4 py-2 rounded-md w-full bg-accent text-white border-0" type="submit">Add
|
<button type="submit">Add
|
||||||
link</button>
|
link</button>
|
||||||
</form>
|
</form>
|
||||||
<span id="link-message"></span>
|
<span id="link-message"></span>
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
<div id="blur-target"
|
<!DOCTYPE html>
|
||||||
class="transition-[filter] motion-reduce:transition-none ease-[cubic-bezier(0.45,0,0.55,1)] duration-300">
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Passport</title>
|
||||||
|
<link rel="favicon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous"
|
||||||
|
href="/assets/fonts/InstrumentSans-VariableFont_wdth,wght.woff2" />
|
||||||
|
{{{embedFile "assets/styles/adminUi.css"}}}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="blur-target">
|
||||||
<header class="flex w-full p-3">
|
<header class="flex w-full p-3">
|
||||||
<a href="/"
|
<a href="/"
|
||||||
class="flex items-center flex-row gap-2 text-white border-b hover:border-transparent justify-center">
|
class="flex items-center flex-row gap-2 text-white border-b hover:border-transparent justify-center">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
||||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
stroke-width="2">
|
||||||
<path d="m9 14l-4-4l4-4" />
|
<path d="m9 14l-4-4l4-4" />
|
||||||
<path d="M5 10h11a4 4 0 1 1 0 8h-1" />
|
<path d="M5 10h11a4 4 0 1 1 0 8h-1" />
|
||||||
</g>
|
</g>
|
||||||
@@ -14,17 +27,73 @@
|
|||||||
</a>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section class="flex justify-center w-full">
|
{{> 'partials/category-grid' }}
|
||||||
<div class="w-full sm:w-4/5 p-2.5">
|
|
||||||
{{#each Categories}}
|
|
||||||
<div class="flex items-center category-header" id="{{this.ID}}_category">
|
|
||||||
<div class="category-img" data-img-container>
|
|
||||||
<img width="32" height="32" draggable="false" alt="{{this.Name}}" src="{{this.Icon}}" />
|
|
||||||
</div>
|
</div>
|
||||||
<h2 data-placeholder="Enter title...">{{~ this.Name ~}}</h2>
|
|
||||||
<div class="pl-2" data-edit-actions>
|
<input type="file" id="icon-upload" accept="image/*" style="display: none;" />
|
||||||
<div class="flex flex-row gap-2" data-primary-actions>
|
<div id="modal-container" role="dialog" aria-modal="true" class="modal-bg">
|
||||||
<button aria-label="Edit category" onclick="editCategory(this)" class="action-button">
|
<div class="modal">
|
||||||
|
{{> 'partials/modals/category-form' }}
|
||||||
|
{{> 'partials/modals/link-form' }}
|
||||||
|
{{> 'partials/modals/delete-link' }}
|
||||||
|
{{> 'partials/modals/delete-category' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template id="template-loading-spinner">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<!-- Icon from SVG Spinners by Utkarsh Verma - https://github.com/n3r4zzurr0/svg-spinners/blob/main/LICENSE
|
||||||
|
-->
|
||||||
|
<path fill="#EAEAEA" d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
|
||||||
|
opacity=".25" />
|
||||||
|
<path fill="#EAEAEA"
|
||||||
|
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z">
|
||||||
|
<animateTransform attributeName="transform" dur="0.75s" repeatCount="indefinite" type="rotate" values="0
|
||||||
|
12 12;360 12 12" />
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- store a blank link card so that if we add a new link we can clone it to make the editing experience easier -->
|
||||||
|
<template id="template-link-card">
|
||||||
|
<div data-card>
|
||||||
|
<div>
|
||||||
|
<img width="64" height="64" draggable="false" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3></h3>
|
||||||
|
<!-- add 2 to the height to account for the border -->
|
||||||
|
<p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="template-category">
|
||||||
|
<div>
|
||||||
|
<div class="category-header">
|
||||||
|
<div>
|
||||||
|
<img width="32" height="32" draggable="false" />
|
||||||
|
</div>
|
||||||
|
<h2></h2>
|
||||||
|
</div>
|
||||||
|
<div class="link-grid">
|
||||||
|
<div class="new-link-card link-card admin">
|
||||||
|
<svg class="mr-2" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24">
|
||||||
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
stroke-width="2" d="M12 5v14m-7-7h14" />
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<h3>Add a link</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="template-edit-actions">
|
||||||
|
<div>
|
||||||
|
<div class="action-container">
|
||||||
|
<button class="action-button">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
||||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
@@ -34,8 +103,7 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button aria-label="Delete category" onclick="deleteCategory(this)"
|
<button class="text-error action-button">
|
||||||
class="text-error action-button">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
@@ -45,164 +113,40 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
<div class="link-grid">
|
|
||||||
{{#each this.Links}}
|
|
||||||
<div id="{{this.ID}}_link" class="link-card relative admin">
|
|
||||||
<div class="relative" data-img-container>
|
|
||||||
<img width="64" height="64" draggable="false" src="{{this.Icon}}" alt="{{this.Name}}" />
|
|
||||||
</div>
|
|
||||||
<div data-text-container>
|
|
||||||
<h3 class="border border-transparent" data-placeholder="Enter title...">
|
|
||||||
{{~ this.Name ~}}
|
|
||||||
</h3>
|
|
||||||
<!-- add 2 to the height to account for the border -->
|
|
||||||
<p data-placeholder="Enter description...">
|
|
||||||
{{~ this.Description ~}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="absolute right-1 top-1" data-edit-actions>
|
|
||||||
<div class="flex flex-row gap-2" data-primary-actions>
|
|
||||||
<button aria-label="Edit link" onclick="editLink(this)" class="action-button">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
|
||||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
stroke-width="2">
|
|
||||||
<path d="M7 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-1" />
|
|
||||||
<path d="M20.385 6.585a2.1 2.1 0 0 0-2.97-2.97L9 12v3h3zM16 5l3 3" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<button aria-label="Delete link" onclick="deleteLink(this)"
|
|
||||||
class="text-error action-button">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round"
|
|
||||||
stroke-linejoin="round" stroke-width="2"
|
|
||||||
d="M4 7h16m-10 4v6m4-6v6M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
<div onclick="openModal('link', {{this.ID}})" class="new-link-card">
|
|
||||||
<svg class="mr-2" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24">
|
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
stroke-width="2" d="M12 5v14m-7-7h14" />
|
|
||||||
</svg>
|
|
||||||
<div>
|
|
||||||
<h3>Add a link</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
<div class="flex items-center" id="add-category-button">
|
|
||||||
<svg class="mr-2" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
|
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
stroke-width="2" d="M12 5v14m-7-7h14" />
|
|
||||||
</svg>
|
|
||||||
<h2 onclick="openModal('category')" class="text-subtle underline decoration-dashed cursor-pointer">
|
|
||||||
Add a new category
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input type="file" id="icon-upload" accept="image/*" style="display: none;" />
|
<div id="teleport-storage" class="absolute -top-full -left-full hidden">
|
||||||
<div id="modal-container" role="dialog" aria-modal="true"
|
|
||||||
class="modal-bg fixed top-0 left-0 bottom-0 right-0 bg-black/45 justify-center items-center hidden">
|
|
||||||
<div class="bg-overlay rounded-xl overflow-hidden w-full p-4 modal max-w-sm">
|
|
||||||
{{> 'partials/modals/category-form' }}
|
|
||||||
{{> 'partials/modals/link-form' }}
|
|
||||||
{{> 'partials/modals/delete-link' }}
|
|
||||||
{{> 'partials/modals/delete-category' }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- store a blank link card so that if we add a new link we can clone it to make the editing experience easier -->
|
|
||||||
<div id="template-link-card" class="hidden">
|
|
||||||
<div class="relative" data-img-container>
|
|
||||||
<img width="64" height="64" draggable="false" />
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow flex flex-col gap-y-px overflow-hidden" data-text-container>
|
|
||||||
<h3 class="border border-transparent"></h3>
|
|
||||||
<!-- add 2 to the height to account for the border -->
|
|
||||||
<p class="min-h-[22px] border border-transparent"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="template-category" class="hidden">
|
|
||||||
<div class="flex items-center category-header">
|
|
||||||
<div class="category-img" data-img-container>
|
|
||||||
<img width="32" height="32" draggable="false" />
|
|
||||||
</div>
|
|
||||||
<h2></h2>
|
|
||||||
</div>
|
|
||||||
<div class="link-grid">
|
|
||||||
<div class="new-link-card">
|
|
||||||
<svg class="mr-2" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24">
|
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
||||||
d="M12 5v14m-7-7h14" />
|
|
||||||
</svg>
|
|
||||||
<div>
|
|
||||||
<h3>Add a link</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="template-edit-actions" class="hidden" data-edit-actions>
|
|
||||||
<div class="flex flex-row gap-2" data-primary-actions>
|
|
||||||
<button class="action-button">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
|
||||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
|
||||||
<path d="M7 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-1" />
|
|
||||||
<path d="M20.385 6.585a2.1 2.1 0 0 0-2.97-2.97L9 12v3h3zM16 5l3 3" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<button class="text-error action-button">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
||||||
d="M4 7h16m-10 4v6m4-6v6M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="teleport-storage" class="absolute -top-full -left-full hidden">
|
|
||||||
<!-- These are the elements that appear when the user enters edit mode, they allow for the cancelation/confirmation of the edit -->
|
<!-- These are the elements that appear when the user enters edit mode, they allow for the cancelation/confirmation of the edit -->
|
||||||
<div class="flex flex-row gap-2" data-confirm-actions id="confirm-actions">
|
<div class="action-container" id="confirm-actions">
|
||||||
<button class="action-button text-success" onclick="confirmEdit()">
|
<button class="action-button text-success" onclick="confirmEdit(event)">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
d="m5 12l5 5L20 7" />
|
stroke-width="2" d="m5 12l5 5L20 7" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="action-button text-error" onclick="cancelEdit()">
|
<button class="action-button text-error" onclick="cancelEdit()">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0-18 0m15.364-6.364L5.636 18.364" />
|
stroke-width="2" d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0-18 0m15.364-6.364L5.636 18.364" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- This is the element that appears on top of the icon when the user is editing it that allows for changing the icon -->
|
<!-- This is the element that appears on top of the icon when the user is editing it that allows for changing the icon -->
|
||||||
<button id="select-icon-button" onclick="selectIcon()"
|
<button id="select-icon-button" onclick="selectIcon()" class="select-icon-button" draggable="false">
|
||||||
class="flex absolute inset-0 bg-highlight/80 rounded-md text-base items-center justify-center"
|
|
||||||
draggable="false">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28"
|
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28"
|
||||||
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2M7 9l5-5l5 5m-5-5v12" />
|
d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2M7 9l5-5l5 5m-5-5v12" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{{embedFile "scripts/admin.js"}}}
|
{{{embedFile "scripts/admin.js"}}}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
{{{devContent}}}
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,20 +1,31 @@
|
|||||||
<main class="flex justify-center items-center h-screen relative bg-base">
|
<!DOCTYPE html>
|
||||||
<div class="flex bg-surface rounded-xl overflow-hidden">
|
<html lang="en">
|
||||||
<img src="/assets/leaves.webp" class="h-96 w-64 object-cover" />
|
|
||||||
<div class="flex flex-col p-4 text-center">
|
<head>
|
||||||
<h2 class="text-2xl">
|
<title>Passport</title>
|
||||||
|
<link rel="favicon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous"
|
||||||
|
href="/assets/fonts/InstrumentSans-VariableFont_wdth,wght.woff2" />
|
||||||
|
{{{embedFile "assets/styles/login.css"}}}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<main class="login-container">
|
||||||
|
<img src="/assets/leaves.webp" />
|
||||||
|
<div>
|
||||||
|
<h2>
|
||||||
Login
|
Login
|
||||||
</h2>
|
</h2>
|
||||||
<form action="/admin/login" method="post" class="flex flex-col gap-y-3 my-2">
|
<form action="/admin/login" method="post" class="login-form">
|
||||||
<input type="text" name="username" placeholder="Username" />
|
<input type="text" name="username" placeholder="Username" />
|
||||||
<input type="password" name="password" placeholder="Password" />
|
<input type="password" name="password" placeholder="Password" />
|
||||||
<button class="px-4 py-2 rounded-md w-full bg-accent text-white border-0" type="submit">Login</button>
|
<button class="px-4 py-2 rounded-md w-full bg-accent text-white border-0" type="submit">Login</button>
|
||||||
</form>
|
</form>
|
||||||
<span id="message"></span>
|
<span id="message"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
</main>
|
</body>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let message = document.getElementById("message");
|
let message = document.getElementById("message");
|
||||||
let form = document.querySelector("form");
|
let form = document.querySelector("form");
|
||||||
@@ -43,3 +54,6 @@
|
|||||||
message.innerText = (await res.json()).message;
|
message.innerText = (await res.json()).message;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
{{{devContent}}}
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,100 +1,86 @@
|
|||||||
<main class="grid grid-rows-3 grid-cols-[1fr] justify-center items-center h-screen bg-base">
|
<!DOCTYPE html>
|
||||||
<div class="flex h-full p-2.5 justify-between">
|
<html lang="en">
|
||||||
<div>
|
|
||||||
|
<head>
|
||||||
|
<title>Passport</title>
|
||||||
|
<link rel="favicon" href="/favicon.ico" />
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous"
|
||||||
|
href="/assets/fonts/InstrumentSans-VariableFont_wdth,wght.woff2" />
|
||||||
|
{{{embedFile "assets/styles/main.css"}}}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<main class="hero">
|
||||||
|
<div class="glance-container">
|
||||||
{{#if WeatherData}}
|
{{#if WeatherData}}
|
||||||
<div class="text-subtle flex items-center">
|
<div class="weather-data">
|
||||||
<span class="mr-2 flex items-center">
|
<span>
|
||||||
{{{WeatherData.Icon}}}
|
{{{WeatherData.Icon}}}
|
||||||
</span>
|
</span>
|
||||||
<div class="font-semibold">
|
<div class="font-semibold">
|
||||||
<p>{{WeatherData.Temp}}°C</p>
|
<p class="leading-condensed">{{WeatherData.Temp}}°C</p>
|
||||||
<p>{{WeatherData.Desc}}</p>
|
<p class="leading-condensed">{{WeatherData.Desc}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{#if UptimeData}}
|
{{#if UptimeData}}
|
||||||
<div class="text-subtle flex items-end flex-col">
|
<div class="uptime-data">
|
||||||
|
<svg width="0" height="0" style="display:none">
|
||||||
|
<defs>
|
||||||
|
<circle id="status-dot" cx="5" cy="5" r="5" />
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
{{#each UptimeData}}
|
{{#each UptimeData}}
|
||||||
<div class="flex items-center">
|
<div>
|
||||||
<span class="mr-2 flex items-center">
|
<span>
|
||||||
{{{this.FriendlyName}}}
|
{{this.FriendlyName}}
|
||||||
</span>
|
</span>
|
||||||
<div class="relative my-auto size-2">
|
<div class="uptime-status">
|
||||||
<div class="relative my-auto size-2 flex-shrink-0 flex-grow-0">
|
<svg viewBox="0 0 10 10">
|
||||||
<svg class="absolute w-full h-full animate-ping" viewBox="0 0 10 10">
|
<use href="#status-dot" class="{{#if this.Up}}text-success{{else}}text-error{{/if}}">
|
||||||
<circle cx="5" cy="5" r="5"
|
</use>
|
||||||
class="fill-current {{#if (eq this.Status 2)}} text-success {{else}} text-error {{/if}}">
|
|
||||||
</circle>
|
|
||||||
</svg>
|
</svg>
|
||||||
<svg class="relative w-full h-full" viewBox="0 0 10 10">
|
<svg viewBox="0 0 10 10">
|
||||||
<circle cx="5" cy="5" r="5"
|
<use href="#status-dot" class="{{#if this.Up}}text-success{{else}}text-error{{/if}}">
|
||||||
class="fill-current {{#if (eq this.Status 2)}} text-success {{else}} text-error {{/if}}">
|
</use>
|
||||||
</circle>
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="primary-hero-container">
|
||||||
<div class="row-start-2 flex flex-col items-center w-full px-6">
|
<div>
|
||||||
<div class="flex items-center pb-2.5">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 100 100">
|
||||||
<svg class="mr-3 aspect-square w-[clamp(42px,10vw,60px)]" viewBox="0 0 100 100" fill="none"
|
<rect width="70" height="47" x="12.1" y="24.8" fill="url(#a)" rx="12"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
transform="rotate(14.6 12.1 24.8)" />
|
||||||
<rect x="12.1483" y="24.7693" width="70" height="47" rx="12" transform="rotate(14.63 12.1483 24.7693)"
|
<path fill="url(#b)" fill-rule="evenodd"
|
||||||
fill="url(#paint0_linear_20_10)" />
|
d="M52.7 13.5a12 12 0 0 0-16.2 5l-3.7 7 35.6 9.3a17 17 0 0 1 12.2 20.7l-5.8 22.3a12 12 0 0 0 12.7-6.2l10.8-20.3a12 12 0 0 0-5-16.2z"
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
clip-rule="evenodd" />
|
||||||
d="M52.7386 13.4812C46.8869 10.3698 39.6209 12.5913 36.5096 18.4429L32.7819 25.4537L68.4322 34.7599C77.5166 37.1313 82.9586 46.418 80.5872 55.5025L74.7779 77.7567C74.7752 77.7674 74.7724 77.778 74.7696 77.7886C79.7728 78.7022 85.0029 76.3441 87.518 71.6138L98.3159 51.306C101.427 45.4543 99.2058 38.1883 93.3542 35.0769L52.7386 13.4812Z"
|
|
||||||
fill="url(#paint1_linear_20_10)" />
|
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="paint0_linear_20_10" x1="12.359" y1="44.8681" x2="82.491" y2="48.2607"
|
<linearGradient id="a" x1="12.4" x2="82.5" y1="44.9" y2="48.3" gradientUnits="userSpaceOnUse">
|
||||||
gradientUnits="userSpaceOnUse">
|
<stop stop-color="#f0389b" />
|
||||||
<stop stop-color="#F0389B" />
|
<stop offset="1" stop-color="#eee740" />
|
||||||
<stop offset="1" stop-color="#EEE740" />
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<linearGradient id="paint1_linear_20_10" x1="33.8935" y1="25.6926" x2="94.2236" y2="61.6131"
|
<linearGradient id="b" x1="33.9" x2="94.2" y1="25.7" y2="61.6" gradientUnits="userSpaceOnUse">
|
||||||
gradientUnits="userSpaceOnUse">
|
<stop stop-color="#aa38f0" />
|
||||||
<stop stop-color="#AA38F0" />
|
<stop offset="1" stop-color="#ee406a" />
|
||||||
<stop offset="1" stop-color="#EE406A" />
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
<h1>Passport</h1>
|
<h1>Passport</h1>
|
||||||
</div>
|
</div>
|
||||||
<form class="w-full max-w-3xl" action="{{ SearchProviderURL }}" method="GET">
|
<form action="{{ SearchProviderURL }}" method="GET">
|
||||||
<input name="{{ SearchParam }}" aria-label="Search bar"
|
<input name="{{ SearchParam }}" aria-label="Search bar" placeholder="Search..." />
|
||||||
class="w-full bg-surface border border-highlight-sm/70 rounded-full px-3 py-1 text-white h-7 focus-visible:outline-none placeholder:italic placeholder:text-highlight search"
|
|
||||||
placeholder="Search..." />
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<section class="flex justify-center w-full bg-surface">
|
{{> 'partials/category-grid' }}
|
||||||
<div class="w-full sm:w-4/5 p-2.5">
|
</body>
|
||||||
{{#each Categories}}
|
|
||||||
<div class="flex items-center mt-2 first:mt-0">
|
{{{devContent}}}
|
||||||
<img class="object-contain mr-2 select-none size-8" width="32" height="32" draggable="false"
|
|
||||||
alt="{{this.Name}}" src="{{this.Icon}}" />
|
</html>
|
||||||
<h2 class="capitalize break-all">{{this.Name}}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="link-grid">
|
|
||||||
{{#each this.Links}}
|
|
||||||
<a href="{{this.URL}}" class="link-card" draggable="false" target="_blank" rel="noopener noreferrer">
|
|
||||||
<div data-img-container>
|
|
||||||
<img width="64" height="64" draggable="false" src="{{this.Icon}}" alt="{{this.Name}}" />
|
|
||||||
</div>
|
|
||||||
<div data-text-container>
|
|
||||||
<h3>{{this.Name}}</h3>
|
|
||||||
<p class="min-h-5">{{this.Description}}</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{{else}}
|
|
||||||
<p class="text-subtle">No links here, add one!</p>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "passport",
|
"name": "passport",
|
||||||
"version": "0.3.2",
|
"version": "0.3.4",
|
||||||
"description": "Passport is a simple, lightweight, and fast dashboard/new tab page for your browser.",
|
"description": "Passport is a simple, lightweight, and fast dashboard/new tab page for your browser.",
|
||||||
"author": "juls0730",
|
"author": "juls0730",
|
||||||
"license": "BSL-1.0",
|
"license": "BSL-1.0",
|
||||||
@@ -10,9 +10,16 @@
|
|||||||
"url": "https://github.com/juls0730/passport.git"
|
"url": "https://github.com/juls0730/passport.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "go generate ./src/; PASSPORT_DEV_MODE=true go run src/main.go",
|
"generate": "go generate ./src/",
|
||||||
"build": "go generate ./src/ && go build -tags netgo,prod -ldflags=\"-w -s\" -o passport src/main.go"
|
"dev": "zqdgr generate; PASSPORT_DEV_MODE=true go run src/main.go",
|
||||||
|
"build": "zqdgr generate && go build -tags netgo,prod -ldflags=\"-w -s\" -o passport src/main.go && upx passport",
|
||||||
|
"build:all": "zqdgr build && zqdgr build:arm64 && zqdgr build:amd64",
|
||||||
|
"build:amd64": "zqdgr generate && GOOS=linux GOARCH=amd64 go build -tags netgo,prod -ldflags=\"-w -s\" -o passport-linux-amd64 src/main.go && upx passport-linux-amd64",
|
||||||
|
"build:arm64": "zqdgr generate && GOOS=linux GOARCH=arm64 go build -tags netgo,prod -ldflags=\"-w -s\" -o passport-linux-arm64 src/main.go && upx passport-linux-arm64"
|
||||||
},
|
},
|
||||||
"pattern": "src/**/*.{go,hbs,js,css,scss,svg,png,jpg,jpeg,webp,woff2,ico,webp}",
|
"pattern": "src/**/*.{go,hbs,css,js,svg,png,jpg,jpeg,webp,woff2,ico,webp}",
|
||||||
|
"excluded_files": [
|
||||||
|
"src/assets/styles"
|
||||||
|
],
|
||||||
"shutdown_signal": "SIGINT"
|
"shutdown_signal": "SIGINT"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user