Compare commits
26 Commits
991fd13184
...
main
Author | SHA1 | Date | |
---|---|---|---|
5032672341 | |||
eec2d36526 | |||
3f3c0d72f8 | |||
f6b6639905 | |||
3781ae935d | |||
ede223d9d5 | |||
dc1fa6d08a | |||
7df4b38d09 | |||
7644c2c810 | |||
b5e740a5c2 | |||
48a526f404 | |||
94a7880db3 | |||
6f336b18d3 | |||
1451ab0ef1 | |||
b35f479def | |||
740ef0f748 | |||
5d6e12c308 | |||
c75f426065 | |||
69239287b2 | |||
8f77173b8b | |||
cdcd418239 | |||
537bf9d613 | |||
eba6c8273c | |||
97fe722790 | |||
8ea7faf483 | |||
c010ea4ea7 |
26
.env.example
Normal file
26
.env.example
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# All environment variables must be prefixed with VITE_ to be seen by client.
|
||||||
|
|
||||||
|
# Self-hosted Services URLs. Do not include the trailing slash.
|
||||||
|
VITE_BANG_URL="https://bang."
|
||||||
|
VITE_GITEA_URL="https://git."
|
||||||
|
VITE_SEARXNG_URL="https://search."
|
||||||
|
VITE_OPENWEBUI_URL="https://chat."
|
||||||
|
VITE_NEXTCLOUD_URL="https://apps.cloud."
|
||||||
|
VITE_PLEX_URL="https://plex."
|
||||||
|
VITE_OVERSEERR_URL="https://overseerr."
|
||||||
|
VITE_SONARR_URL="https://sonarr."
|
||||||
|
VITE_RADARR_URL="https://radarr."
|
||||||
|
VITE_LIDARR_URL="https://lidarr."
|
||||||
|
|
||||||
|
# Set default bang here. For example "g" would be Google.
|
||||||
|
# Google is the default if you don't set this.
|
||||||
|
# 's' is for your searxng instance, replacing startpage
|
||||||
|
VITE_DEFAULT_BANG="s"
|
||||||
|
|
||||||
|
# SPECIFIC MODELS FOR OPENWEBUI
|
||||||
|
# Local
|
||||||
|
VITE_LLAMA_MODEL="llama3.1" # !llama
|
||||||
|
VITE_DEEPSEEK_MODEL="deepseek-r1:8b" # !r1
|
||||||
|
# Remote
|
||||||
|
VITE_OPENAI_MODEL="gpt-4o-mini" # !openai
|
||||||
|
VITE_CLAUDE_MODEL="anthropic/claude-3.5-sonnet" # !claude
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -6,6 +6,7 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
public/opensearch.xml
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
@ -22,3 +23,10 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# ENV
|
||||||
|
docker/.env
|
||||||
|
!docker/.env.example
|
||||||
|
.env
|
||||||
|
.env*
|
||||||
|
!.env.example
|
||||||
|
41
README.md
41
README.md
@ -1,14 +1,43 @@
|
|||||||
# Bang
|
# 💣Bang
|
||||||
|
|
||||||
*This is a fork of [unduck](https://unduck.link) by [Theo](https://github.com/t3dotgg/unduck).*
|
*This is a fork of [unduck](https://unduck.link) by [Theo](https://github.com/t3dotgg/unduck).*
|
||||||
|
|
||||||
|
## Why fork?
|
||||||
|
|
||||||
|
This fork allows anyone to easily self host this service & add bangs for their own self-hosted websites. Bang comes pre-configured to work with
|
||||||
|
|
||||||
|
- Searxng *!s*
|
||||||
|
- Gitea *!tea*
|
||||||
|
- OpenWebUI *!ai*
|
||||||
|
- Plex *!plex*
|
||||||
|
- Sonarr *!tv*
|
||||||
|
- Radarr *!mv*
|
||||||
|
- Lidarr *!mp3*
|
||||||
|
- ~Overseerr *!ov*~ *Overseerr doesn't seem to work correctly*
|
||||||
|
|
||||||
|
*Note: We have replaced some of the default bangs from duckduckgo with our own bangs in order to have more simple bangs for the self-hosted websites.*
|
||||||
|
|
||||||
|
All you have to do is fill out the environment variables in the .env.example files located in the root directory & the docker directory & rename them to .env.
|
||||||
|
|
||||||
|
You can also easily add your own bangs by adding a new entry in the bangs.ts file.
|
||||||
|
|
||||||
|
## How to self host
|
||||||
|
|
||||||
|
1. Clone the repo & fill out the .env.example files in the root directory & the docker directory & rename them to .env.
|
||||||
|
- *Note: Our docker compose assumes you plan to select an external network.*
|
||||||
|
2. Run the bash script `host-bang` in the docker directory with the root directory of the project as an argument.
|
||||||
|
- *Note: You can also simply run it from the root or docker directory without an argument.*
|
||||||
|
|
||||||
|
### How to update the website
|
||||||
|
|
||||||
|
1. Run the bash script `update-bang` in the docker directory with the root directory of the project as an argument.
|
||||||
|
- *Note: You can also simply run it from the root or docker directory without an argument.*
|
||||||
|
|
||||||
|
## Theo's words
|
||||||
|
|
||||||
DuckDuckGo's bang redirects are too slow. Add the following URL as a custom search engine to your browser. Enables all of DuckDuckGo's bangs to work, but much faster.
|
DuckDuckGo's bang redirects are too slow. Add the following URL as a custom search engine to your browser. Enables all of DuckDuckGo's bangs to work, but much faster.
|
||||||
|
|
||||||
```
|
### How is it that much faster?
|
||||||
https://bang.gbrown.org?q=%s
|
|
||||||
```
|
|
||||||
|
|
||||||
## How is it that much faster?
|
|
||||||
|
|
||||||
DuckDuckGo does their redirects server side. Their DNS is...not always great. Result is that it often takes ages.
|
DuckDuckGo does their redirects server side. Their DNS is...not always great. Result is that it often takes ages.
|
||||||
|
|
||||||
|
3
docker/.env.example
Normal file
3
docker/.env.example
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
PORT=5000
|
||||||
|
DOMAIN=bang.mydomain.com
|
||||||
|
NETWORK=bridge
|
33
docker/Dockerfile
Normal file
33
docker/Dockerfile
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Stage 1: Build the project
|
||||||
|
FROM node:18 AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package.json and pnpm-lock.yaml to the working directory
|
||||||
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
RUN pnpm install
|
||||||
|
|
||||||
|
# Copy project files into the docker image
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the project
|
||||||
|
RUN pnpm run prebuild
|
||||||
|
RUN pnpm run build
|
||||||
|
|
||||||
|
# Stage 2: Serve the app using the same version of Node
|
||||||
|
FROM node:18-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install a simple http server
|
||||||
|
RUN npm install -g serve
|
||||||
|
|
||||||
|
# Copy built assets from the builder stage
|
||||||
|
COPY --from=builder /app/dist ./
|
||||||
|
|
||||||
|
# Expose port 5000 for the server
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
# Start the server using the `serve` package
|
||||||
|
CMD ["serve", "-s", ".", "-l", "5000"]
|
21
docker/docker-compose.yml
Normal file
21
docker/docker-compose.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
services:
|
||||||
|
bang-web-server:
|
||||||
|
build:
|
||||||
|
context: ../
|
||||||
|
dockerfile: docker/Dockerfile
|
||||||
|
container_name: bang
|
||||||
|
hostname: bang.gib
|
||||||
|
domainname: bang.gbrown.org
|
||||||
|
networks:
|
||||||
|
- nginx-bridge
|
||||||
|
#ports:
|
||||||
|
#- 5000:5000
|
||||||
|
tty: true
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ../:/app
|
||||||
|
command: serve -s /app/dist -l 5000
|
||||||
|
|
||||||
|
networks:
|
||||||
|
nginx-bridge:
|
||||||
|
external: true
|
51
docker/host-bang
Executable file
51
docker/host-bang
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Function to check if we're in the correct directory
|
||||||
|
check_directory() {
|
||||||
|
if [ -d "docker" ] && [ -f "package.json" ]; then
|
||||||
|
return 0 # We're in the root directory
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize root_dir
|
||||||
|
root_dir=""
|
||||||
|
|
||||||
|
# Check if argument is provided
|
||||||
|
if [ $# -eq 1 ]; then
|
||||||
|
# Use provided path
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
root_dir="$1"
|
||||||
|
cd "$root_dir" || exit 1
|
||||||
|
else
|
||||||
|
echo "Error: Provided directory does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# No argument provided, try to determine location
|
||||||
|
current_dir=$(basename "$(pwd)")
|
||||||
|
|
||||||
|
if [ "$current_dir" = "docker" ]; then
|
||||||
|
cd .. || exit 1
|
||||||
|
elif [ "$current_dir" != "Bang" ]; then
|
||||||
|
echo "Error: Not in the correct directory and no valid path provided"
|
||||||
|
echo "Please either:"
|
||||||
|
echo "1. Run this script from the Bang root directory"
|
||||||
|
echo "2. Run this script from the docker directory"
|
||||||
|
echo "3. Provide the path to the Bang root directory as an argument"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify we're in the correct directory
|
||||||
|
if ! check_directory; then
|
||||||
|
echo "Error: Not in the correct directory structure"
|
||||||
|
echo "Make sure you're in a directory with 'docker' folder and package.json"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
pnpm install
|
||||||
|
pnpm build
|
||||||
|
cd docker || exit 1
|
||||||
|
sudo docker compose up -d
|
||||||
|
cd ..
|
52
docker/update-bang
Executable file
52
docker/update-bang
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Function to check if we're in the correct directory
|
||||||
|
check_directory() {
|
||||||
|
if [ -d "docker" ] && [ -f "package.json" ]; then
|
||||||
|
return 0 # We're in the root directory
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize root_dir
|
||||||
|
root_dir=""
|
||||||
|
|
||||||
|
# Check if argument is provided
|
||||||
|
if [ $# -eq 1 ]; then
|
||||||
|
# Use provided path
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
root_dir="$1"
|
||||||
|
cd "$root_dir" || exit 1
|
||||||
|
else
|
||||||
|
echo "Error: Provided directory does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# No argument provided, try to determine location
|
||||||
|
current_dir=$(basename "$(pwd)")
|
||||||
|
|
||||||
|
if [ "$current_dir" = "docker" ]; then
|
||||||
|
cd .. || exit 1
|
||||||
|
elif [ "$current_dir" != "Bang" ]; then
|
||||||
|
echo "Error: Not in the correct directory and no valid path provided"
|
||||||
|
echo "Please either:"
|
||||||
|
echo "1. Run this script from the Bang root directory"
|
||||||
|
echo "2. Run this script from the docker directory"
|
||||||
|
echo "3. Provide the path to the Bang root directory as an argument"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify we're in the correct directory
|
||||||
|
if ! check_directory; then
|
||||||
|
echo "Error: Not in the correct directory structure"
|
||||||
|
echo "Make sure you're in a directory with 'docker' folder and package.json"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git pull
|
||||||
|
pnpm build
|
||||||
|
cd docker || exit 1
|
||||||
|
sudo docker compose down
|
||||||
|
sudo docker compose up -d
|
||||||
|
cd ..
|
15
index.html
15
index.html
@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/search.svg" />
|
<link rel="icon" type="image/svg+xml" href="/bang.svg" />
|
||||||
<link
|
<link
|
||||||
rel="preconnect"
|
rel="preconnect"
|
||||||
href="https://fonts.googleapis.com"
|
href="https://fonts.googleapis.com"
|
||||||
@ -24,13 +24,14 @@
|
|||||||
media="print"
|
media="print"
|
||||||
onload="this.media='all'"
|
onload="this.media='all'"
|
||||||
/>
|
/>
|
||||||
<script
|
<link
|
||||||
defer
|
rel="search"
|
||||||
data-domain="unduck.link"
|
type="application/opensearchdescription+xml"
|
||||||
src="https://plausible.io/js/script.js"
|
title="Bang!"
|
||||||
></script>
|
href="/opensearch.xml"
|
||||||
|
/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Unduck</title>
|
<title>Bang!</title>
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="A better default search engine (with bangs!)"
|
content="A better default search engine (with bangs!)"
|
||||||
|
14
package.json
14
package.json
@ -1,21 +1,25 @@
|
|||||||
{
|
{
|
||||||
"name": "unduck",
|
"name": "bang",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
"generate-opensearch": "ts-node scripts/generateOpenSearch.ts",
|
||||||
|
"prebuild": "pnpm generate-opensearch",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "~5.7.2",
|
"@types/node": "^22.15.17",
|
||||||
"vite": "^6.1.0"
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "~5.7.3",
|
||||||
|
"vite": "^6.3.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vite-plugin-pwa": "^0.21.1"
|
"vite-plugin-pwa": "^0.21.2"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b",
|
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
"esbuild"
|
"esbuild"
|
||||||
|
1904
pnpm-lock.yaml
generated
1904
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
53
public/bang.svg
Normal file
53
public/bang.svg
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 128 128" style="enable-background:new 0 0 128 128;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<polygon style="fill:#FFE36C;" points="81.13,29.99 62.79,30.17 78.47,21.62 74.76,8.38 85.17,16.28 95.64,8.27 92.89,19.05
|
||||||
|
110.15,21.03 92.19,28.03 85.03,40.53 "/>
|
||||||
|
<path style="fill:#FF8F00;" d="M92.27,13.37l-0.76,2.96l-1.13,4.45l4.56,0.52l6.94,0.79l-9.76,3.81l-1.32,0.51l-0.7,1.23
|
||||||
|
l-4.68,8.17l-1.92-5.2l-0.98-2.65L79.7,28l-8.91,0.09l7.24-3.95l2.8-1.53l-0.86-3.07l-1.67-5.96l4.44,3.37l2.43,1.84l2.42-1.85
|
||||||
|
L92.27,13.37 M85.16,13.76L72.49,4.15c-0.41-0.31-0.98,0.08-0.84,0.57l4.46,15.91l-19.44,10.6c-0.49,0.27-0.3,1.01,0.26,1
|
||||||
|
l22.81-0.23l4.5,12.17c0.16,0.43,0.74,0.47,0.97,0.08l8.37-14.62l22.82-8.9c0.52-0.2,0.42-0.97-0.13-1.03L95.4,17.32l3.22-12.65
|
||||||
|
c0.13-0.49-0.44-0.87-0.84-0.56L85.16,13.76z"/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#4D4D4D;" d="M94.59,44.29c-1.27-0.18-7.6,6.13-12.17,2.17c0,0-0.01,0.01-0.01,0.01
|
||||||
|
c-2.63-2.13-5.53-3.99-8.72-5.51c-21.75-10.37-47.8-1.15-58.18,20.61c-10.37,21.75-1.15,47.8,20.61,58.18
|
||||||
|
c21.75,10.37,47.8,1.15,58.18-20.61c3.37-7.06,4.67-14.57,4.14-21.85c-0.04-0.51-0.13-1.64,0.12-2.48c1.71-5.74,7.93-8.6,7.8-8.87
|
||||||
|
C106.23,65.66,95.87,44.47,94.59,44.29z"/>
|
||||||
|
|
||||||
|
<ellipse transform="matrix(0.8667 -0.4988 0.4988 0.8667 -14.1049 57.4504)" style="fill:#757575;" cx="100.46" cy="55.12" rx="5.83" ry="12.33"/>
|
||||||
|
|
||||||
|
<ellipse transform="matrix(0.866 -0.5 0.5 0.866 -13.8369 58.5564)" style="fill:#212121;" cx="102.35" cy="55.1" rx="2.29" ry="3.52"/>
|
||||||
|
<path style="opacity:0.9;fill:#757575;" d="M53.9,52.57c2.74,7.78-1.27,12.42-6.46,15.39c-2.48,1.42-5.36,2.04-7.87,3.41
|
||||||
|
c-4.88,2.66-7.84,7.79-12.09,11.36c-1.06,0.89-2.27,1.71-3.65,1.86c-1.84,0.2-3.64-0.88-4.74-2.37C18,80.72,13.53,66.5,29.85,51.95
|
||||||
|
C37.14,45.45,50.9,44.04,53.9,52.57z"/>
|
||||||
|
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="42.079" y1="34.5524" x2="83.8122" y2="48.0625">
|
||||||
|
<stop offset="0" style="stop-color:#FFF9C4;stop-opacity:0.1"/>
|
||||||
|
<stop offset="1.516624e-03" style="stop-color:#FFF9C4;stop-opacity:0.1007"/>
|
||||||
|
<stop offset="0.3781" style="stop-color:#FFFCA6;stop-opacity:0.2626"/>
|
||||||
|
<stop offset="0.7007" style="stop-color:#FFFE94;stop-opacity:0.4014"/>
|
||||||
|
<stop offset="0.93" style="stop-color:#FFFF8D;stop-opacity:0.5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<path style="fill:url(#SVGID_1_);" d="M41.86,38.72c3.69,0.12,11.23,0.17,20.77,3.92c3.21,1.26,5.92,3.02,8.83,4.82
|
||||||
|
c2.35,1.45,5.02,2.66,7.77,2.4c0.97-0.09,2.04-0.47,2.42-1.37c0.23-0.56,0.21-1.13,0.01-1.69c-0.24-0.66-1.06-1.58-2.32-2.61
|
||||||
|
c-1.77-1.19-3.65-2.28-5.64-3.23C63.34,36.02,52.01,35.53,41.86,38.72z"/>
|
||||||
|
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="102.0288" y1="57.3021" x2="91.1394" y2="42.9353">
|
||||||
|
<stop offset="0.1096" style="stop-color:#FFF9C4;stop-opacity:0"/>
|
||||||
|
<stop offset="1" style="stop-color:#FFFF8D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<path style="fill:url(#SVGID_2_);" d="M102.13,47.64c-0.05-0.05-0.1-0.11-0.15-0.16c-0.01-0.01-0.01-0.02-0.02-0.02
|
||||||
|
c-0.23-0.23-0.46-0.45-0.69-0.67c-0.03-0.03-0.07-0.06-0.1-0.1c-2.53-2.29-5.12-3.26-6.86-2.27c-2.79,1.6-2.3,7.69,1.1,13.59
|
||||||
|
c0.73,1.26,1.53,2.41,2.37,3.43c-0.1-0.29-3.84-11.52-1.51-14.53C98.26,44.37,101.78,47.34,102.13,47.64z"/>
|
||||||
|
<path style="fill:#212121;" d="M88.16,74.53c-2.42-1.59-4.79-3.75-6.26-9.18c-0.19-0.69-0.83-4.12,1.02-4.67
|
||||||
|
c1.6-0.48,2.79,2.15,4.17,4.46c1.5,2.53,3.93,4.72,6.54,6.15c0.76,0.41,4.29,2,1.97,4.22C94.07,76.96,89.58,75.47,88.16,74.53z"/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#C69461;" d="M100.85,53.44c0.1-0.04,10.25-4.65,9.37-11.34c-0.58-4.42-2.3-6.62-11.4-8.78
|
||||||
|
c-8.9-2.11-13.25-6.24-13.43-6.42c-0.89-0.86-0.92-2.29-0.05-3.19c0.86-0.89,2.28-0.92,3.18-0.06c0.07,0.06,3.77,3.48,11.35,5.28
|
||||||
|
c8.82,2.09,13.79,4.72,14.83,12.57c1.16,8.78-8.52,14.25-11.29,15.7C101.69,58.11,99.71,53.94,100.85,53.44z"/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#F6BC41;" d="M88.5,23.66c-0.89-0.86-2.32-0.83-3.18,0.06c-0.86,0.9-0.84,2.32,0.05,3.19
|
||||||
|
c0.13,0.13,2.5,2.37,7.25,4.39l0.95-1.66l3.66-1.43C91.42,26.35,88.56,23.71,88.5,23.66z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
1
public/chrome.svg
Normal file
1
public/chrome.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" height="48" width="48"><defs><linearGradient id="a" x1="3.2173" y1="15" x2="44.7812" y2="15" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#d93025"/><stop offset="1" stop-color="#ea4335"/></linearGradient><linearGradient id="b" x1="20.7219" y1="47.6791" x2="41.5039" y2="11.6837" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fcc934"/><stop offset="1" stop-color="#fbbc04"/></linearGradient><linearGradient id="c" x1="26.5981" y1="46.5015" x2="5.8161" y2="10.506" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1e8e3e"/><stop offset="1" stop-color="#34a853"/></linearGradient></defs><circle cx="24" cy="23.9947" r="12" style="fill:#fff"/><path d="M3.2154,36A24,24,0,1,0,12,3.2154,24,24,0,0,0,3.2154,36ZM34.3923,18A12,12,0,1,1,18,13.6077,12,12,0,0,1,34.3923,18Z" style="fill:none"/><path d="M24,12H44.7812a23.9939,23.9939,0,0,0-41.5639.0029L13.6079,30l.0093-.0024A11.9852,11.9852,0,0,1,24,12Z" style="fill:url(#a)"/><circle cx="24" cy="24" r="9.5" style="fill:#1a73e8"/><path d="M34.3913,30.0029,24.0007,48A23.994,23.994,0,0,0,44.78,12.0031H23.9989l-.0025.0093A11.985,11.985,0,0,1,34.3913,30.0029Z" style="fill:url(#b)"/><path d="M13.6086,30.0031,3.218,12.006A23.994,23.994,0,0,0,24.0025,48L34.3931,30.0029l-.0067-.0068a11.9852,11.9852,0,0,1-20.7778.007Z" style="fill:url(#c)"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clipboard"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clipboard"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/></svg>
|
||||||
|
Before Width: | Height: | Size: 357 B After Width: | Height: | Size: 350 B |
120
public/firefox.svg
Normal file
120
public/firefox.svg
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<svg width="77.42" height="79.97" version="1.1" viewBox="0 0 77.42 79.97" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||||
|
<title>Firefox Browser logo</title>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="a" x1="70.79" x2="6.447" y1="12.39" y2="74.47" gradientTransform="translate(-1.3 -.004086)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#fff44f" offset=".048"/>
|
||||||
|
<stop stop-color="#ffe847" offset=".111"/>
|
||||||
|
<stop stop-color="#ffc830" offset=".225"/>
|
||||||
|
<stop stop-color="#ff980e" offset=".368"/>
|
||||||
|
<stop stop-color="#ff8b16" offset=".401"/>
|
||||||
|
<stop stop-color="#ff672a" offset=".462"/>
|
||||||
|
<stop stop-color="#ff3647" offset=".534"/>
|
||||||
|
<stop stop-color="#e31587" offset=".705"/>
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient id="b" cx="-7907" cy="-8515" r="80.8" gradientTransform="translate(7974,8524)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#ffbd4f" offset=".129"/>
|
||||||
|
<stop stop-color="#ffac31" offset=".186"/>
|
||||||
|
<stop stop-color="#ff9d17" offset=".247"/>
|
||||||
|
<stop stop-color="#ff980e" offset=".283"/>
|
||||||
|
<stop stop-color="#ff563b" offset=".403"/>
|
||||||
|
<stop stop-color="#ff3750" offset=".467"/>
|
||||||
|
<stop stop-color="#f5156c" offset=".71"/>
|
||||||
|
<stop stop-color="#eb0878" offset=".782"/>
|
||||||
|
<stop stop-color="#e50080" offset=".86"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="c" cx="-7937" cy="-8482" r="80.8" gradientTransform="translate(7974,8524)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#960e18" offset=".3"/>
|
||||||
|
<stop stop-color="#b11927" stop-opacity=".74" offset=".351"/>
|
||||||
|
<stop stop-color="#db293d" stop-opacity=".343" offset=".435"/>
|
||||||
|
<stop stop-color="#f5334b" stop-opacity=".094" offset=".497"/>
|
||||||
|
<stop stop-color="#ff3750" stop-opacity="0" offset=".53"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="d" cx="-7927" cy="-8533" r="58.53" gradientTransform="translate(7974,8524)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#fff44f" offset=".132"/>
|
||||||
|
<stop stop-color="#ffdc3e" offset=".252"/>
|
||||||
|
<stop stop-color="#ff9d12" offset=".506"/>
|
||||||
|
<stop stop-color="#ff980e" offset=".526"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="e" cx="-7946" cy="-8461" r="38.47" gradientTransform="translate(7974,8524)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#3a8ee6" offset=".353"/>
|
||||||
|
<stop stop-color="#5c79f0" offset=".472"/>
|
||||||
|
<stop stop-color="#9059ff" offset=".669"/>
|
||||||
|
<stop stop-color="#c139e6" offset="1"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="f" cx="-7936" cy="-8492" r="20.4" gradientTransform="matrix(.972 -.235 .275 1.138 10090 7834)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#9059ff" stop-opacity="0" offset=".206"/>
|
||||||
|
<stop stop-color="#8c4ff3" stop-opacity=".064" offset=".278"/>
|
||||||
|
<stop stop-color="#7716a8" stop-opacity=".45" offset=".747"/>
|
||||||
|
<stop stop-color="#6e008b" stop-opacity=".6" offset=".975"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="g" cx="-7938" cy="-8518" r="27.68" gradientTransform="translate(7974,8524)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#ffe226" offset="0"/>
|
||||||
|
<stop stop-color="#ffdb27" offset=".121"/>
|
||||||
|
<stop stop-color="#ffc82a" offset=".295"/>
|
||||||
|
<stop stop-color="#ffa930" offset=".502"/>
|
||||||
|
<stop stop-color="#ff7e37" offset=".732"/>
|
||||||
|
<stop stop-color="#ff7139" offset=".792"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="h" cx="-7916" cy="-8536" r="118.1" gradientTransform="translate(7974,8524)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#fff44f" offset=".113"/>
|
||||||
|
<stop stop-color="#ff980e" offset=".456"/>
|
||||||
|
<stop stop-color="#ff5634" offset=".622"/>
|
||||||
|
<stop stop-color="#ff3647" offset=".716"/>
|
||||||
|
<stop stop-color="#e31587" offset=".904"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="i" cx="-7927" cy="-8523" r="86.5" gradientTransform="matrix(.105 .995 -.653 .069 -4685 8470)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#fff44f" offset="0"/>
|
||||||
|
<stop stop-color="#ffe847" offset=".06"/>
|
||||||
|
<stop stop-color="#ffc830" offset=".168"/>
|
||||||
|
<stop stop-color="#ff980e" offset=".304"/>
|
||||||
|
<stop stop-color="#ff8b16" offset=".356"/>
|
||||||
|
<stop stop-color="#ff672a" offset=".455"/>
|
||||||
|
<stop stop-color="#ff3647" offset=".57"/>
|
||||||
|
<stop stop-color="#e31587" offset=".737"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="j" cx="-7938" cy="-8508" r="73.72" gradientTransform="translate(7974,8524)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#fff44f" offset=".137"/>
|
||||||
|
<stop stop-color="#ff980e" offset=".48"/>
|
||||||
|
<stop stop-color="#ff5634" offset=".592"/>
|
||||||
|
<stop stop-color="#ff3647" offset=".655"/>
|
||||||
|
<stop stop-color="#e31587" offset=".904"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="k" cx="-7919" cy="-8504" r="80.69" gradientTransform="translate(7974,8524)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#fff44f" offset=".094"/>
|
||||||
|
<stop stop-color="#ffe141" offset=".231"/>
|
||||||
|
<stop stop-color="#ffaf1e" offset=".509"/>
|
||||||
|
<stop stop-color="#ff980e" offset=".626"/>
|
||||||
|
</radialGradient>
|
||||||
|
<linearGradient id="l" x1="70.01" x2="15.27" y1="12.06" y2="66.81" gradientTransform="translate(-1.3 -.004086)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#fff44f" stop-opacity=".8" offset=".167"/>
|
||||||
|
<stop stop-color="#fff44f" stop-opacity=".634" offset=".266"/>
|
||||||
|
<stop stop-color="#fff44f" stop-opacity=".217" offset=".489"/>
|
||||||
|
<stop stop-color="#fff44f" stop-opacity="0" offset=".6"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<g transform="matrix(.9819843 0 0 .9819843 .6974849 .7199239)">
|
||||||
|
<path d="m74.62 26.83c-1.684-4.052-5.1-8.427-7.775-9.81a40.27 40.27 0 0 1 3.925 11.76l7e-3 0.065c-4.382-10.92-11.81-15.33-17.88-24.92-0.307-0.485-0.614-0.971-0.913-1.484-0.171-0.293-0.308-0.557-0.427-0.8a7.053 7.053 0 0 1-0.578-1.535 0.1 0.1 0 0 0-0.088-0.1 0.138 0.138 0 0 0-0.073 0c-5e-3 0-0.013 9e-3 -0.019 0.011s-0.019 0.011-0.028 0.015l0.015-0.026c-9.735 5.7-13.04 16.25-13.34 21.53a19.39 19.39 0 0 0-10.67 4.111 11.59 11.59 0 0 0-1-0.758 17.97 17.97 0 0 1-0.109-9.473 28.7 28.7 0 0 0-9.329 7.21h-0.018c-1.536-1.947-1.428-8.367-1.34-9.708a6.928 6.928 0 0 0-1.294 0.687 28.22 28.22 0 0 0-3.788 3.245 33.84 33.84 0 0 0-3.623 4.347v6e-3 -7e-3a32.73 32.73 0 0 0-5.2 11.74l-0.052 0.256c-0.073 0.341-0.336 2.049-0.381 2.42 0 0.029-6e-3 0.056-9e-3 0.085a36.94 36.94 0 0 0-0.629 5.343v0.2a38.76 38.76 0 0 0 76.95 6.554c0.065-0.5 0.118-0.995 0.176-1.5a39.86 39.86 0 0 0-2.514-19.47zm-44.67 30.34c0.181 0.087 0.351 0.181 0.537 0.264l0.027 0.017q-0.282-0.135-0.564-0.281zm8.878-23.38m31.95-4.934v-0.037l7e-3 0.041z" fill="url(#a)"/>
|
||||||
|
<path d="m74.62 26.83c-1.684-4.052-5.1-8.427-7.775-9.81a40.27 40.27 0 0 1 3.925 11.76v0.037l7e-3 0.041a35.1 35.1 0 0 1-1.206 26.16c-4.442 9.531-15.19 19.3-32.02 18.82-18.18-0.515-34.2-14.01-37.19-31.68-0.545-2.787 0-4.2 0.274-6.465a28.88 28.88 0 0 0-0.623 5.348v0.2a38.76 38.76 0 0 0 76.95 6.554c0.065-0.5 0.118-0.995 0.176-1.5a39.86 39.86 0 0 0-2.514-19.47z" fill="url(#b)"/>
|
||||||
|
<path d="m74.62 26.83c-1.684-4.052-5.1-8.427-7.775-9.81a40.27 40.27 0 0 1 3.925 11.76v0.037l7e-3 0.041a35.1 35.1 0 0 1-1.206 26.16c-4.442 9.531-15.19 19.3-32.02 18.82-18.18-0.515-34.2-14.01-37.19-31.68-0.545-2.787 0-4.2 0.274-6.465a28.88 28.88 0 0 0-0.623 5.348v0.2a38.76 38.76 0 0 0 76.95 6.554c0.065-0.5 0.118-0.995 0.176-1.5a39.86 39.86 0 0 0-2.514-19.47z" fill="url(#c)"/>
|
||||||
|
<path d="m55.78 31.38c0.084 0.059 0.162 0.118 0.241 0.177a21.1 21.1 0 0 0-3.6-4.695c-12.05-12.05-3.157-26.12-1.658-26.84l0.015-0.022c-9.735 5.7-13.04 16.25-13.34 21.53 0.452-0.031 0.9-0.069 1.362-0.069a19.56 19.56 0 0 1 16.98 9.917z" fill="url(#d)"/>
|
||||||
|
<path d="m38.82 33.79c-0.064 0.964-3.47 4.289-4.661 4.289-11.02 0-12.81 6.667-12.81 6.667 0.488 5.614 4.4 10.24 9.129 12.68 0.216 0.112 0.435 0.213 0.654 0.312q0.569 0.252 1.138 0.466a17.24 17.24 0 0 0 5.043 0.973c19.32 0.906 23.06-23.1 9.119-30.07a13.38 13.38 0 0 1 9.345 2.269 19.56 19.56 0 0 0-16.98-9.917c-0.46 0-0.91 0.038-1.362 0.069a19.39 19.39 0 0 0-10.67 4.111c0.591 0.5 1.258 1.168 2.663 2.553 2.63 2.591 9.375 5.275 9.39 5.59z" fill="url(#e)"/>
|
||||||
|
<path d="m38.82 33.79c-0.064 0.964-3.47 4.289-4.661 4.289-11.02 0-12.81 6.667-12.81 6.667 0.488 5.614 4.4 10.24 9.129 12.68 0.216 0.112 0.435 0.213 0.654 0.312q0.569 0.252 1.138 0.466a17.24 17.24 0 0 0 5.043 0.973c19.32 0.906 23.06-23.1 9.119-30.07a13.38 13.38 0 0 1 9.345 2.269 19.56 19.56 0 0 0-16.98-9.917c-0.46 0-0.91 0.038-1.362 0.069a19.39 19.39 0 0 0-10.67 4.111c0.591 0.5 1.258 1.168 2.663 2.553 2.63 2.591 9.375 5.275 9.39 5.59z" fill="url(#f)"/>
|
||||||
|
<path d="m24.96 24.36c0.314 0.2 0.573 0.374 0.8 0.531a17.97 17.97 0 0 1-0.109-9.473 28.7 28.7 0 0 0-9.329 7.21c0.189-5e-3 5.811-0.106 8.638 1.732z" fill="url(#g)"/>
|
||||||
|
<path d="m0.354 42.16c2.991 17.67 19.01 31.17 37.19 31.68 16.83 0.476 27.58-9.294 32.02-18.82a35.1 35.1 0 0 0 1.206-26.16v-0.037c0-0.029-6e-3 -0.046 0-0.037l7e-3 0.065c1.375 8.977-3.191 17.67-10.33 23.56l-0.022 0.05c-13.91 11.33-27.22 6.834-29.91 5q-0.282-0.135-0.564-0.281c-8.109-3.876-11.46-11.26-10.74-17.6a9.953 9.953 0 0 1-9.181-5.775 14.62 14.62 0 0 1 14.25-0.572 19.3 19.3 0 0 0 14.55 0.572c-0.015-0.315-6.76-3-9.39-5.59-1.405-1.385-2.072-2.052-2.663-2.553a11.59 11.59 0 0 0-1-0.758c-0.23-0.157-0.489-0.327-0.8-0.531-2.827-1.838-8.449-1.737-8.635-1.732h-0.018c-1.536-1.947-1.428-8.367-1.34-9.708a6.928 6.928 0 0 0-1.294 0.687 28.22 28.22 0 0 0-3.788 3.245 33.84 33.84 0 0 0-3.638 4.337v6e-3 -7e-3a32.73 32.73 0 0 0-5.2 11.74c-0.019 0.079-1.396 6.099-0.717 9.221z" fill="url(#h)"/>
|
||||||
|
<path d="m52.42 26.86a21.1 21.1 0 0 1 3.6 4.7c0.213 0.161 0.412 0.321 0.581 0.476 8.787 8.1 4.183 19.55 3.84 20.36 7.138-5.881 11.7-14.58 10.33-23.56-4.384-10.93-11.82-15.34-17.88-24.93-0.307-0.485-0.614-0.971-0.913-1.484-0.171-0.293-0.308-0.557-0.427-0.8a7.053 7.053 0 0 1-0.578-1.535 0.1 0.1 0 0 0-0.088-0.1 0.138 0.138 0 0 0-0.073 0c-5e-3 0-0.013 9e-3 -0.019 0.011s-0.019 0.011-0.028 0.015c-1.499 0.711-10.39 14.79 1.66 26.83z" fill="url(#i)"/>
|
||||||
|
<path d="m56.6 32.04c-0.169-0.155-0.368-0.315-0.581-0.476-0.079-0.059-0.157-0.118-0.241-0.177a13.38 13.38 0 0 0-9.345-2.269c13.94 6.97 10.2 30.97-9.119 30.07a17.24 17.24 0 0 1-5.043-0.973q-0.569-0.213-1.138-0.466c-0.219-0.1-0.438-0.2-0.654-0.312l0.027 0.017c2.694 1.839 16 6.332 29.91-5l0.022-0.05c0.347-0.81 4.951-12.26-3.84-20.36z" fill="url(#j)"/>
|
||||||
|
<path d="m21.35 44.74s1.789-6.667 12.81-6.667c1.191 0 4.6-3.325 4.661-4.289a19.3 19.3 0 0 1-14.55-0.572 14.62 14.62 0 0 0-14.25 0.572 9.953 9.953 0 0 0 9.181 5.775c-0.718 6.337 2.632 13.72 10.74 17.6 0.181 0.087 0.351 0.181 0.537 0.264-4.733-2.445-8.641-7.069-9.129-12.68z" fill="url(#k)"/>
|
||||||
|
<path d="m74.62 26.83c-1.684-4.052-5.1-8.427-7.775-9.81a40.27 40.27 0 0 1 3.925 11.76l7e-3 0.065c-4.382-10.92-11.81-15.33-17.88-24.92-0.307-0.485-0.614-0.971-0.913-1.484-0.171-0.293-0.308-0.557-0.427-0.8a7.053 7.053 0 0 1-0.578-1.535 0.1 0.1 0 0 0-0.088-0.1 0.138 0.138 0 0 0-0.073 0c-5e-3 0-0.013 9e-3 -0.019 0.011s-0.019 0.011-0.028 0.015l0.015-0.026c-9.735 5.7-13.04 16.25-13.34 21.53 0.452-0.031 0.9-0.069 1.362-0.069a19.56 19.56 0 0 1 16.98 9.917 13.38 13.38 0 0 0-9.345-2.269c13.94 6.97 10.2 30.97-9.119 30.07a17.24 17.24 0 0 1-5.043-0.973q-0.569-0.213-1.138-0.466c-0.219-0.1-0.438-0.2-0.654-0.312l0.027 0.017q-0.282-0.135-0.564-0.281c0.181 0.087 0.351 0.181 0.537 0.264-4.733-2.446-8.641-7.07-9.129-12.68 0 0 1.789-6.667 12.81-6.667 1.191 0 4.6-3.325 4.661-4.289-0.015-0.315-6.76-3-9.39-5.59-1.405-1.385-2.072-2.052-2.663-2.553a11.59 11.59 0 0 0-1-0.758 17.97 17.97 0 0 1-0.109-9.473 28.7 28.7 0 0 0-9.329 7.21h-0.018c-1.536-1.947-1.428-8.367-1.34-9.708a6.928 6.928 0 0 0-1.294 0.687 28.22 28.22 0 0 0-3.788 3.245 33.84 33.84 0 0 0-3.623 4.347v6e-3 -7e-3a32.73 32.73 0 0 0-5.2 11.74l-0.052 0.256c-0.073 0.341-0.4 2.073-0.447 2.445a45.09 45.09 0 0 0-0.572 5.403v0.2a38.76 38.76 0 0 0 76.95 6.554c0.065-0.5 0.118-0.995 0.176-1.5a39.86 39.86 0 0 0-2.514-19.47zm-3.845 1.991 7e-3 0.041z" fill="url(#l)"/>
|
||||||
|
</g>
|
||||||
|
<metadata>
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:title>Firefox Browser logo</dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
10
public/opensearch.xml
Normal file
10
public/opensearch.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<ShortName>Bang!</ShortName>
|
||||||
|
<Description>A better default search engine with bangs</Description>
|
||||||
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
|
<Image width="16" height="16" type="image/svg+xml">https://bang.gbrown.org/bang.svg</Image>
|
||||||
|
<Url type="text/html" method="get" template="https://bang.gbrown.org?q={searchTerms}"/>
|
||||||
|
<Url type="application/opensearchdescription+xml" rel="self" template="https://bang.gbrown.org/opensearch.xml"/>
|
||||||
|
<moz:SearchForm xmlns:moz="http://www.mozilla.org/2006/browser/search/">https://bang.gbrown.org</moz:SearchForm>
|
||||||
|
</OpenSearchDescription>
|
@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect width="1200" height="1200" fill="black"/>
|
|
||||||
<path fill="white" d="m980.48 905.76-198.84-199.08c89.203-125.34 77.953-300.14-34.406-412.64-125.26-125.44-328.03-125.44-453.32 0-125.26 125.44-125.26 328.45 0 453.84 112.36 112.5 286.97 123.74 412.18 34.406l198.84 199.08c53.25 53.297 132.05-19.078 75.562-75.609zm-610.87-233.58c-83.391-83.531-83.391-218.86 0-302.39s218.58-83.531 302.02 0c83.391 83.531 83.391 218.86 0 302.39-83.438 83.484-218.63 83.484-302.02 0z"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 624 B |
98
scripts/files_to_clipboard
Executable file
98
scripts/files_to_clipboard
Executable file
@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
import pyperclip
|
||||||
|
import questionary
|
||||||
|
|
||||||
|
# List of directories to exclude
|
||||||
|
EXCLUDED_DIRS = {'node_modules', '.next', '.venv', '.git', '__pycache__', '.idea', '.vscode', 'ui'}
|
||||||
|
|
||||||
|
def collect_files(project_path):
|
||||||
|
"""
|
||||||
|
Collects files from the project directory, excluding specified directories and filtering by extensions.
|
||||||
|
Returns a list of file paths relative to the project directory.
|
||||||
|
"""
|
||||||
|
collected_files = []
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(project_path):
|
||||||
|
# Exclude specified directories
|
||||||
|
dirs[:] = [d for d in dirs if d not in EXCLUDED_DIRS]
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
file_path = Path(root) / file
|
||||||
|
relative_path = file_path.relative_to(project_path)
|
||||||
|
collected_files.append(relative_path)
|
||||||
|
|
||||||
|
return collected_files
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Parse command-line arguments
|
||||||
|
parser = argparse.ArgumentParser(description='Generate Markdown from selected files.')
|
||||||
|
parser.add_argument('path', nargs='?', default='.', help='Path to the project directory')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
project_path = Path(args.path).resolve()
|
||||||
|
if not project_path.is_dir():
|
||||||
|
print(f"Error: '{project_path}' is not a directory.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Collect files from the project directory
|
||||||
|
file_list = collect_files(project_path)
|
||||||
|
|
||||||
|
if not file_list:
|
||||||
|
print("No files found in the project directory with the specified extensions.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Sort file_list for better organization
|
||||||
|
file_list.sort()
|
||||||
|
|
||||||
|
# Interactive file selection using questionary
|
||||||
|
print("\nSelect the files you want to include:")
|
||||||
|
selected_files = questionary.checkbox(
|
||||||
|
"Press space to select files, and Enter when you're done:",
|
||||||
|
choices=[str(f) for f in file_list]
|
||||||
|
).ask()
|
||||||
|
|
||||||
|
if not selected_files:
|
||||||
|
print("No files selected.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Generate markdown
|
||||||
|
markdown_lines = []
|
||||||
|
markdown_lines.append('')
|
||||||
|
|
||||||
|
for selected_file in selected_files:
|
||||||
|
file_path = project_path / selected_file
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
# Determine the language for code block from file extension
|
||||||
|
language = file_path.suffix.lstrip('.')
|
||||||
|
markdown_lines.append(f'{selected_file}')
|
||||||
|
markdown_lines.append(f'```{language}')
|
||||||
|
markdown_lines.append(content)
|
||||||
|
markdown_lines.append('```')
|
||||||
|
markdown_lines.append('')
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading file {selected_file}: {e}")
|
||||||
|
|
||||||
|
# Copy markdown content to clipboard
|
||||||
|
markdown_text = '\n'.join(markdown_lines)
|
||||||
|
pyperclip.copy(markdown_text)
|
||||||
|
print("Markdown content has been copied to the clipboard.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Check if required libraries are installed
|
||||||
|
try:
|
||||||
|
import questionary
|
||||||
|
import pyperclip
|
||||||
|
except ImportError as e:
|
||||||
|
missing_module = e.name
|
||||||
|
print(f"Error: Missing required module '{missing_module}'.")
|
||||||
|
print(f"Please install it by running: pip install {missing_module}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
main()
|
33
scripts/generateOpenSearch.ts
Normal file
33
scripts/generateOpenSearch.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import * as fs from 'node:fs';
|
||||||
|
import * as path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
// Get the current file's directory
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
// Get the Bang URL from environment or use a default for local development
|
||||||
|
const bangUrl = process.env.VITE_BANG_URL || 'https://bang.gbrown.org';
|
||||||
|
|
||||||
|
// Create the OpenSearch XML content
|
||||||
|
const openSearchXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<ShortName>Bang!</ShortName>
|
||||||
|
<Description>A better default search engine with bangs</Description>
|
||||||
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
|
<Image width="16" height="16" type="image/svg+xml">${bangUrl}/bang.svg</Image>
|
||||||
|
<Url type="text/html" method="get" template="${bangUrl}?q={searchTerms}"/>
|
||||||
|
<Url type="application/opensearchdescription+xml" rel="self" template="${bangUrl}/opensearch.xml"/>
|
||||||
|
<moz:SearchForm xmlns:moz="http://www.mozilla.org/2006/browser/search/">${bangUrl}</moz:SearchForm>
|
||||||
|
</OpenSearchDescription>`;
|
||||||
|
|
||||||
|
// Ensure the public directory exists
|
||||||
|
const publicDir = path.resolve(__dirname, '../public');
|
||||||
|
if (!fs.existsSync(publicDir)) {
|
||||||
|
fs.mkdirSync(publicDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the OpenSearch XML file
|
||||||
|
fs.writeFileSync(path.join(publicDir, 'opensearch.xml'), openSearchXml);
|
||||||
|
|
||||||
|
console.log('OpenSearch XML file generated successfully!');
|
211
src/bang.ts
211
src/bang.ts
@ -1,14 +1,190 @@
|
|||||||
// This file was (mostly) ripped from https://duckduckgo.com/bang.js
|
// This file was (mostly) ripped from https://duckduckgo.com/bang.js
|
||||||
|
|
||||||
|
const SEARXNG_URL = import.meta.env.VITE_SEARXNG_URL as string;
|
||||||
|
const GITEA_URL = import.meta.env.VITE_GITEA_URL as string;
|
||||||
|
const OPENWEBUI_URL = import.meta.env.VITE_OPENWEBUI_URL as string;
|
||||||
|
const PLEX_URL = import.meta.env.VITE_PLEX_URL as string;
|
||||||
|
const OVERSEERR_URL = import.meta.env.VITE_OVERSEERR_URL as string;
|
||||||
|
const SONARR_URL = import.meta.env.VITE_SONARR_URL as string;
|
||||||
|
const RADARR_URL = import.meta.env.VITE_RADARR_URL as string;
|
||||||
|
const LIDARR_URL = import.meta.env.VITE_LIDARR_URL as string;
|
||||||
|
|
||||||
|
const LLAMA_MODEL = import.meta.env.VITE_LLAMA_MODEL.replace(":", "%3A") as string;
|
||||||
|
const DEEPSEEK_MODEL = import.meta.env.VITE_DEEPSEEK_MODEL.replace(":", "%3A") as string;
|
||||||
|
const OPENAI_MODEL = import.meta.env.VITE_OPENAI_MODEL as string;
|
||||||
|
const CLAUDE_MODEL = import.meta.env.VITE_CLAUDE_MODEL.replace("/", "%2F") as string;
|
||||||
|
|
||||||
export const bangs = [
|
export const bangs = [
|
||||||
{
|
{
|
||||||
c: "Online Services",
|
c: "Online Services",
|
||||||
d: "search.gibbyb.com",
|
d: SEARXNG_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "Searxng",
|
||||||
sc: "Search",
|
sc: "Search",
|
||||||
t: "sg",
|
t: "s",
|
||||||
u: "https://search.gibbyb.com/?q={{{s}}}",
|
u: `${SEARXNG_URL}/?q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Tech",
|
||||||
|
d: GITEA_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Gitea",
|
||||||
|
sc: "Cryptocurrency",
|
||||||
|
t: "tea",
|
||||||
|
u: `${GITEA_URL}/?repo-search-query={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: PLEX_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Plex",
|
||||||
|
sc: "Movies",
|
||||||
|
t: "plex",
|
||||||
|
u: `${PLEX_URL}/web/index.html#!/search?pivot=top&query={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: OVERSEERR_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Overseerr",
|
||||||
|
sc: "Movies",
|
||||||
|
t: "ov",
|
||||||
|
u: `${OVERSEERR_URL}/search?query={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: LIDARR_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Lidarr",
|
||||||
|
sc: "Music",
|
||||||
|
t: "mp3",
|
||||||
|
u: `${LIDARR_URL}/add/new?term={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: SONARR_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Sonarr",
|
||||||
|
sc: "TV",
|
||||||
|
t: "tv",
|
||||||
|
u: `${SONARR_URL}/add/new?term={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: RADARR_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Radarr",
|
||||||
|
sc: "Movies",
|
||||||
|
t: "mv",
|
||||||
|
u: `${RADARR_URL}/add/new?term={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "ai",
|
||||||
|
u: `${OPENWEBUI_URL}/?q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "c",
|
||||||
|
u: `${OPENWEBUI_URL}/?q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "llama",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=${LLAMA_MODEL}&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "r1",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=${DEEPSEEK_MODEL}&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "r1-7b",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=deepseek-r1%3A7b&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "r1-32b",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=deepseek-r1%3A32b&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "claude",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=${CLAUDE_MODEL}&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "openai",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=${OPENAI_MODEL}&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "o3-mini",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=o3-mini&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "o1",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=o1&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "4o-mini",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=gpt-4o-mini&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "4o",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=gpt-4o&q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
@ -3175,7 +3351,7 @@ export const bangs = [
|
|||||||
r: 8351,
|
r: 8351,
|
||||||
s: "Duck.ai",
|
s: "Duck.ai",
|
||||||
sc: "Reference",
|
sc: "Reference",
|
||||||
t: "ai",
|
t: "ddgai",
|
||||||
u: "https://www.duckduckgo.com/?q={{{s}}}&ia=chat&bang=true ",
|
u: "https://www.duckduckgo.com/?q={{{s}}}&ia=chat&bang=true ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -15979,7 +16155,7 @@ export const bangs = [
|
|||||||
r: 165,
|
r: 165,
|
||||||
s: "CNET",
|
s: "CNET",
|
||||||
sc: "Downloads",
|
sc: "Downloads",
|
||||||
t: "c",
|
t: "cnet",
|
||||||
u: "http://www.cnet.com/1770-5_1-0.html?query={{{s}}}",
|
u: "http://www.cnet.com/1770-5_1-0.html?query={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -71297,7 +71473,7 @@ export const bangs = [
|
|||||||
r: 10,
|
r: 10,
|
||||||
s: "Myvideo",
|
s: "Myvideo",
|
||||||
sc: "Video",
|
sc: "Video",
|
||||||
t: "mv",
|
t: "myvideo",
|
||||||
u: "http://www.myvideo.de/Videos_A-Z?searchWord={{{s}}}",
|
u: "http://www.myvideo.de/Videos_A-Z?searchWord={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -73410,8 +73586,8 @@ export const bangs = [
|
|||||||
r: 0,
|
r: 0,
|
||||||
s: "Nextcloud App Store",
|
s: "Nextcloud App Store",
|
||||||
sc: "Sysadmin",
|
sc: "Sysadmin",
|
||||||
t: "nextcloudapp",
|
t: "cloudapp",
|
||||||
u: "https://apps.nextcloud.com/?search={{{s}}}",
|
u: "https://apps.nextcloud.com/search/?q={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "Entertainment",
|
c: "Entertainment",
|
||||||
@ -78736,7 +78912,7 @@ export const bangs = [
|
|||||||
r: 0,
|
r: 0,
|
||||||
s: "StackOverflow",
|
s: "StackOverflow",
|
||||||
sc: "Programming",
|
sc: "Programming",
|
||||||
t: "ov",
|
t: "ovfl",
|
||||||
u: "http://stackoverflow.com/search?q={{{s}}}",
|
u: "http://stackoverflow.com/search?q={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -98316,7 +98492,7 @@ export const bangs = [
|
|||||||
r: 12469,
|
r: 12469,
|
||||||
s: "startpage.com",
|
s: "startpage.com",
|
||||||
sc: "Search",
|
sc: "Search",
|
||||||
t: "s",
|
t: "startpage",
|
||||||
u: "http://startpage.com/do/metasearch.pl?query={{{s}}}",
|
u: "http://startpage.com/do/metasearch.pl?query={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -106689,15 +106865,6 @@ export const bangs = [
|
|||||||
t: "tva",
|
t: "tva",
|
||||||
u: "https://tweakers.net/aanbod/zoeken/?keyword={{{s}}}",
|
u: "https://tweakers.net/aanbod/zoeken/?keyword={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
c: "Entertainment",
|
|
||||||
d: "www.tv.com",
|
|
||||||
r: 0,
|
|
||||||
s: "TV.com",
|
|
||||||
sc: "TV",
|
|
||||||
t: "tvcom",
|
|
||||||
u: "http://www.tv.com/search?q={{{s}}}",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
c: "Entertainment",
|
c: "Entertainment",
|
||||||
d: "www.thetvdb.com",
|
d: "www.thetvdb.com",
|
||||||
@ -106857,8 +107024,8 @@ export const bangs = [
|
|||||||
r: 31,
|
r: 31,
|
||||||
s: "tv.com",
|
s: "tv.com",
|
||||||
sc: "TV",
|
sc: "TV",
|
||||||
t: "tv",
|
t: "tvcom",
|
||||||
u: "http://www.tv.com/search?q= {{{s}}}",
|
u: "http://www.tv.com/search?q={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "Shopping",
|
c: "Shopping",
|
||||||
|
171
src/global.css
171
src/global.css
@ -1,13 +1,10 @@
|
|||||||
/* @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"); */
|
/* --- Import and fonts unchanged --- */
|
||||||
|
|
||||||
/* Font fallback that closely matches Inter metrics */
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter Fallback";
|
font-family: "Inter Fallback";
|
||||||
size-adjust: 107%;
|
size-adjust: 107%;
|
||||||
ascent-override: 90%;
|
ascent-override: 90%;
|
||||||
src: local("Arial");
|
src: local("Arial");
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family:
|
font-family:
|
||||||
Inter,
|
Inter,
|
||||||
@ -27,27 +24,41 @@
|
|||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* --- Dark mode color variables --- */
|
||||||
|
--bg-color: #121212; /* Dark background */
|
||||||
|
--text-color: #e2e2e2; /* Light text */
|
||||||
|
--input-bg-color: #1e1e1e; /* Dark input background */
|
||||||
|
--input-border-color: #333; /* Darker border for inputs */
|
||||||
|
--accent-color: #bbb; /* Accent color for links/buttons */
|
||||||
|
--hover-bg-color: #2c2c2c; /* Hover state background color */
|
||||||
|
--active-bg-color: #3a3a3a; /* Active state background color */
|
||||||
|
--success-color: #28a745; /* Green for copy-success feedback */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Normalized layout reset stays the same --- */
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
background-color: var(--bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Modified to Dark mode --- */
|
||||||
body {
|
body {
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #1a1a1a;
|
background-color: var(--bg-color); /* Changed: Added dark background */
|
||||||
|
color: var(--text-color); /* Changed: Light text color */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Header and fonts remain unchanged (already good contrast with dark mode) */
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
@ -58,26 +69,43 @@ h6 {
|
|||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Link colors modified for contrast --- */
|
||||||
a {
|
a {
|
||||||
color: #444444;
|
color: var(--accent-color); /* Changed: Lighter accent/link color */
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #888888;
|
color: white; /* Changed: Bright when hovered */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Basic element reset unchanged --- */
|
||||||
button {
|
button {
|
||||||
font: inherit;
|
font: inherit;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
input,
|
input,
|
||||||
textarea {
|
textarea {
|
||||||
font: inherit;
|
font: inherit;
|
||||||
}
|
}
|
||||||
|
.bang-title {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add these new styles */
|
/* --- Container layout unchanged --- */
|
||||||
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 20px 0px;
|
||||||
|
}
|
||||||
|
.content-container {
|
||||||
|
max-width: 36rem;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
.url-container {
|
.url-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -85,67 +113,112 @@ textarea {
|
|||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add this new style */
|
/* --- URL input element styling adjustments --- */
|
||||||
.content-container {
|
|
||||||
max-width: 36rem;
|
|
||||||
text-align: center;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update url-input width to be 100% since container will control max width */
|
|
||||||
.url-input {
|
.url-input {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid var(--input-border-color); /* Changed: Darker border */
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #f5f5f5;
|
background: var(--input-bg-color); /* Changed: Dark input bg */
|
||||||
|
color: var(--text-color); /* Added: Input text color */
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.copy-button {
|
/* --- Copy-button style adjustments --- */
|
||||||
padding: 8px;
|
.copy-button, .copy-firefox, .copy-chrome {
|
||||||
color: #666;
|
padding: 6px;
|
||||||
border-radius: 4px;
|
color: var(--accent-color); /* Changed: Accent color instead of gray */
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
.copy-button:hover, .copy-firefox:hover, .copy-chrome:hover {
|
||||||
.copy-button:hover {
|
background: var(--hover-bg-color); /* Changed: Hover bg darker */
|
||||||
background: #f0f0f0;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
.copy-button:active, .copy-firefox:active, .copy-chrome:active {
|
||||||
.copy-button:active {
|
background: var(--active-bg-color); /* Changed: Active state even darker */
|
||||||
background: #e5e5e5;
|
|
||||||
}
|
}
|
||||||
|
.copy-button img, .copy-firefox img, .copy-chrome img {
|
||||||
.copy-button img {
|
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
/* Copy feedback unchanged (Green stands out in dark mode as well) */
|
||||||
.copy-button.copied {
|
.copy-button.copied, .copy-firefox.copied, .copy-chrome.copied {
|
||||||
background: #28a745;
|
background: var(--success-color);
|
||||||
|
color: white; /* Ensures contrast */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add footer styles */
|
.copy-textbox, .firefox-textbox, .chrome-textbox {
|
||||||
.footer {
|
padding: 6px 10px;
|
||||||
position: fixed;
|
border: 1px solid var(--input-border-color);
|
||||||
bottom: 16px;
|
border-radius: 4px;
|
||||||
left: 0;
|
background: var(--input-bg-color);
|
||||||
right: 0;
|
color: var(--text-color);
|
||||||
text-align: center;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
width: 220px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer a {
|
.copy-textbox:focus, .firefox-textbox:focus, .chrome-textbox:focus {
|
||||||
color: #666;
|
outline: none;
|
||||||
text-decoration: none;
|
border-color: var(--accent-color);
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer a:hover {
|
.settings-title {
|
||||||
color: #333;
|
margin-top: 36px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
.settings-links-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-link-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.browser-instruction {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-table {
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 16px auto;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.form-table td {
|
||||||
|
padding: 8px 6px;
|
||||||
|
border: 1px solid var(--input-border-color);
|
||||||
|
}
|
||||||
|
.form-table td:first-child {
|
||||||
|
background-color: var(--input-bg-color);
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Mobile --- */
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.settings-links-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
.main-container {
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
90
src/main.ts
90
src/main.ts
@ -4,39 +4,117 @@ import "./global.css";
|
|||||||
function noSearchDefaultPageRender() {
|
function noSearchDefaultPageRender() {
|
||||||
const app = document.querySelector<HTMLDivElement>("#app")!;
|
const app = document.querySelector<HTMLDivElement>("#app")!;
|
||||||
app.innerHTML = `
|
app.innerHTML = `
|
||||||
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh;">
|
<main class="main-container">
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<h1>Bang</h1>
|
<h1 class="bang-title">💣 Bang!</h1>
|
||||||
|
<p>
|
||||||
|
Add the following URL as a custom search engine to your browser in order to enable
|
||||||
|
<a href="https://duckduckgo.com/bang.html" target="_blank">
|
||||||
|
all of DuckDuckGo's bangs
|
||||||
|
</a>
|
||||||
|
right from your browser's search bar!
|
||||||
|
</p>
|
||||||
<div class="url-container">
|
<div class="url-container">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="url-input"
|
class="url-input"
|
||||||
value="bang.gbrown.org?q=%s"
|
value="${import.meta.env.VITE_BANG_URL}?q=%s"
|
||||||
readonly
|
readonly
|
||||||
/>
|
/>
|
||||||
<button class="copy-button">
|
<button class="copy-button">
|
||||||
<img src="/clipboard.svg" alt="Copy" />
|
<img src="/clipboard.svg" alt="Copy" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<h3 class="settings-title">How to add Bang! Search Engine</h3>
|
||||||
|
<p style="margin-bottom: 8px; font-size: 14px;">
|
||||||
|
Below are links to the search engine settings in your browser.
|
||||||
|
<br />
|
||||||
|
Copy the URL for the browser engine you are using & paste it into a new tab.
|
||||||
|
<br />
|
||||||
|
From there you should see an option to add a search engine. Copy the link above
|
||||||
|
& fill out the form as follows.
|
||||||
|
</p>
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<td><b>Name:</b></td>
|
||||||
|
<td>Bang!</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Engine URL:</b></td>
|
||||||
|
<td>${import.meta.env.VITE_BANG_URL}?q=%s</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Alias:</b></td>
|
||||||
|
<td>@bang</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div class="settings-links-container">
|
||||||
|
<div class="browser-link-container">
|
||||||
|
<img src="/firefox.svg" alt="Firefox" width="24" />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
readonly value="about:preferences#search"
|
||||||
|
class="firefox-textbox"
|
||||||
|
title="Click to copy Firefox settings URL"
|
||||||
|
/>
|
||||||
|
<button class="copy-firefox">
|
||||||
|
<img src="/clipboard.svg" alt="Copy" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="browser-link-container">
|
||||||
|
<img src="/chrome.svg" alt="Chrome" width="24" />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
readonly value="chrome://settings/searchEngines"
|
||||||
|
class="chrome-textbox"
|
||||||
|
title="Click to copy Chrome settings URL"
|
||||||
|
/>
|
||||||
|
<button class="copy-chrome">
|
||||||
|
<img src="/clipboard.svg" alt="Copy" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const copyButton = app.querySelector<HTMLButtonElement>(".copy-button")!;
|
const copyButton = app.querySelector<HTMLButtonElement>(".copy-button")!;
|
||||||
const copyIcon = copyButton.querySelector("img")!;
|
const copyIcon = copyButton.querySelector("img")!;
|
||||||
const urlInput = app.querySelector<HTMLInputElement>(".url-input")!;
|
const urlInput = app.querySelector<HTMLInputElement>(".url-input")!;
|
||||||
|
const copyFirefox = app.querySelector<HTMLInputElement>(".copy-firefox")!;
|
||||||
|
const copyFirefoxIcon = copyFirefox.querySelector("img")!;
|
||||||
|
const firefoxInput = app.querySelector<HTMLInputElement>(".firefox-textbox")!;
|
||||||
|
const copyChrome = app.querySelector<HTMLInputElement>(".copy-chrome")!;
|
||||||
|
const copyChromeIcon = copyChrome.querySelector("img")!;
|
||||||
|
const chromeInput = app.querySelector<HTMLInputElement>(".chrome-textbox")!;
|
||||||
|
|
||||||
copyButton.addEventListener("click", async () => {
|
copyButton.addEventListener("click", async () => {
|
||||||
await navigator.clipboard.writeText("https://" + urlInput.value);
|
await navigator.clipboard.writeText(urlInput.value);
|
||||||
copyIcon.src = "/clipboard-check.svg";
|
copyIcon.src = "/clipboard-check.svg";
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
copyIcon.src = "/clipboard.svg";
|
copyIcon.src = "/clipboard.svg";
|
||||||
}, 2000);
|
}, 2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
copyFirefox.addEventListener("click", async () => {
|
||||||
|
await navigator.clipboard.writeText(firefoxInput.value);
|
||||||
|
copyFirefoxIcon.src = "/clipboard-check.svg";
|
||||||
|
setTimeout(() => {
|
||||||
|
copyFirefoxIcon.src = "/clipboard.svg";
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
copyChrome.addEventListener("click", async () => {
|
||||||
|
await navigator.clipboard.writeText(chromeInput.value);
|
||||||
|
copyChromeIcon.src = "/clipboard-check.svg";
|
||||||
|
setTimeout(() => {
|
||||||
|
copyChromeIcon.src = "/clipboard.svg";
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const LS_DEFAULT_BANG = localStorage.getItem("default-bang") ?? "sg";
|
const envDefaultBang = import.meta.env.VITE_DEFAULT_BANG ?? "g";
|
||||||
|
const LS_DEFAULT_BANG = localStorage.getItem("default-bang") ?? envDefaultBang;
|
||||||
const defaultBang = bangs.find((b) => b.t === LS_DEFAULT_BANG);
|
const defaultBang = bangs.find((b) => b.t === LS_DEFAULT_BANG);
|
||||||
|
|
||||||
function getBangredirectUrl() {
|
function getBangredirectUrl() {
|
||||||
|
Reference in New Issue
Block a user