Initial commit (Projekt wurde lokal auf meinem PC gestartet)

This commit is contained in:
2026-01-10 02:27:35 +01:00
parent 8d9aa81298
commit 6be8679c99
22 changed files with 3234 additions and 1 deletions

View File

@@ -1,3 +1,27 @@
# Veil
Veil ist ein auf WebKit basierender Simpler Browser, in GTK
============================
DIES IST GERADE NUR EIN HOBBYPROJEKT VON MIR,
UND DAHER NOCH NICHT PRODUCTION READY!!!!
============================
(trozdem freue ich mich über jede pull/push, ein ganzer browser ist nämlich ein bisschen viel arbeit. (heul :,( ))
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Build ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
$ ./build.sh clean && ./build.sh build
nach einem erfolgreichem build landet die bin im build/linux ordner und wird in den veil ordner kopiert, die bin muss ich gleichen ordner wie die data/ directory liegen.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Code ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
ja, ich weiß er ist schlecht, und ja ich weiß, er könnte besser sein. bei verbesserungsvorschlägen bitte statt meckern:
1. Verbessern
2. Push
Dankii :)

43
Veil/Makefile Normal file
View File

@@ -0,0 +1,43 @@
CC = gcc
PKG_CFLAGS = $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.1)
PKG_LIBS = $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.1)
# === PERFORMANCE-OPTIMIZED BUILD FLAGS ===
# -O3: Maximum optimization level
# -march=native: Optimize for current CPU architecture
# -mtune=native: Tune for current CPU
# -flto: Link-time optimization for cross-file inlining
# -ffast-math: Faster floating point (safe for browser UI)
# -fomit-frame-pointer: Free up a register
# -pipe: Faster compilation
CFLAGS = $(PKG_CFLAGS) -O3 -march=native -mtune=native -flto \
-ffast-math -fomit-frame-pointer -pipe \
-Wall -Wextra -Wno-unused-parameter
LDFLAGS = $(PKG_LIBS) -flto -Wl,-O1 -Wl,--as-needed
TARGET = veil
SRC = src/veil.c
all: $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
# Debug build (slower but easier to debug)
debug: CFLAGS = $(PKG_CFLAGS) -O0 -g -Wall -Wextra
debug: LDFLAGS = $(PKG_LIBS)
debug: $(TARGET)
# Release build with stripped binary
release: $(TARGET)
strip --strip-all $(TARGET)
clean:
rm -f $(TARGET)
install: $(TARGET)
install -Dm755 $(TARGET) /usr/local/bin/$(TARGET)
.PHONY: all clean install debug release

Binary file not shown.

Binary file not shown.

88
Veil/build.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/bash
#
# Veil Browser Build Script
# Linux build only
#
set -e
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
BUILD_DIR="$PROJECT_DIR/build"
SRC="$PROJECT_DIR/src/veil.c"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() { echo -e "${GREEN}[*]${NC} $1"; }
print_warn() { echo -e "${YELLOW}[!]${NC} $1"; }
print_error() { echo -e "${RED}[x]${NC} $1"; }
show_help() {
echo "Veil Browser Build Script"
echo ""
echo "Usage: $0 [target]"
echo ""
echo "Targets:"
echo " build Build for Linux (default)"
echo " clean Remove build artifacts"
echo " help Show this help"
echo ""
}
build_linux() {
print_status "Building Veil for Linux..."
# Check dependencies
if ! pkg-config --exists gtk+-3.0 webkit2gtk-4.1 2>/dev/null; then
print_error "Missing dependencies. Install: gtk3 webkit2gtk"
exit 1
fi
CFLAGS=$(pkg-config --cflags gtk+-3.0 webkit2gtk-4.1)
LIBS=$(pkg-config --libs gtk+-3.0 webkit2gtk-4.1)
mkdir -p "$BUILD_DIR/linux"
gcc $CFLAGS \
-O3 -march=native -mtune=native -flto -ffast-math \
-fomit-frame-pointer -pipe \
-Wall -Wextra -Wno-unused-parameter \
-o "$BUILD_DIR/linux/veil" "$SRC" \
$LIBS -flto -Wl,-O1 -Wl,--as-needed
# Copy to project root
cp "$BUILD_DIR/linux/veil" "$PROJECT_DIR/veil"
print_status "Build complete: $BUILD_DIR/linux/veil"
print_status "Also copied to: $PROJECT_DIR/veil"
}
clean() {
print_status "Cleaning build artifacts..."
rm -rf "$BUILD_DIR"
rm -f "$PROJECT_DIR/veil"
print_status "Clean complete."
}
# Main
cd "$PROJECT_DIR"
case "${1:-build}" in
build|linux)
build_linux
;;
clean)
clean
;;
help|--help|-h)
show_help
;;
*)
print_error "Unknown target: $1"
show_help
exit 1
;;
esac

BIN
Veil/build/linux/veil Executable file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 901 KiB

14
Veil/data/meson.build Normal file
View File

@@ -0,0 +1,14 @@
# Desktop file installation
install_data('veil.desktop',
install_dir: join_paths(get_option('datadir'), 'applications')
)
# Icon installation (PNG at various sizes)
icon_sizes = ['16x16', '24x24', '32x32', '48x48', '64x64', '128x128', '256x256', '512x512']
foreach size : icon_sizes
install_data(
join_paths('icons/hicolor', size, 'apps/veil.png'),
install_dir: join_paths(get_option('datadir'), 'icons/hicolor', size, 'apps')
)
endforeach

10
Veil/data/veil.desktop Normal file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Veil
Comment=Minimalistischer WebKit-Browser
Exec=veil
Icon=veil
Terminal=false
Type=Application
Categories=Network;WebBrowser;
Keywords=browser;web;internet;

36
Veil/meson.build Normal file
View File

@@ -0,0 +1,36 @@
project('veil', 'c',
version: '0.1.0',
default_options: [
'warning_level=2',
'c_std=c11',
'optimization=3',
'b_lto=true',
'strip=true'
]
)
gtk3_dep = dependency('gtk+-3.0', version: '>= 3.24')
webkit2_dep = dependency('webkit2gtk-4.1')
# Performance-optimized compiler flags
add_project_arguments(
'-ffast-math',
'-fomit-frame-pointer',
'-pipe',
language: 'c'
)
# Native CPU optimization (comment out for portable builds)
add_project_arguments(
'-march=native',
'-mtune=native',
language: 'c'
)
executable('veil',
'src/veil.c',
dependencies: [gtk3_dep, webkit2_dep],
install: true
)
subdir('data')

189
Veil/src/pages/settings.h Normal file
View File

@@ -0,0 +1,189 @@
/*
* Veil Browser - Settings Page (about:settings)
*/
#ifndef VEIL_PAGE_SETTINGS_H
#define VEIL_PAGE_SETTINGS_H
static const char *SETTINGS_HTML =
"<!DOCTYPE html>"
"<html><head><meta charset='utf-8'><title>Settings</title>"
"<style>"
":root { --bg: %s; --accent: %s; --grad-start: %s; --grad-mid: %s; --grad-end: %s; }"
"* { box-sizing: border-box; margin: 0; padding: 0; }"
"body { font-family: 'JetBrains Mono', 'Fira Code', monospace; background: var(--bg); color: #e0e0e8; display: flex; height: 100vh; }"
".sidebar { width: 180px; background: rgba(255,255,255,0.02); padding: 20px 0; border-right: 1px solid rgba(255,255,255,0.05); }"
".sidebar h2 { font-size: 14px; padding: 0 20px; margin-bottom: 20px; background: linear-gradient(90deg, var(--grad-start), var(--grad-mid), var(--grad-end)); "
" -webkit-background-clip: text; -webkit-text-fill-color: transparent; }"
".nav-item { display: block; padding: 10px 20px; color: #707080; font-size: 12px; cursor: pointer; border-left: 2px solid transparent; }"
".nav-item:hover { background: rgba(255,255,255,0.03); color: #a0a0a8; }"
".nav-item.active { border-left-color: var(--accent); color: #e0e0e8; background: rgba(255,255,255,0.03); }"
".content { flex: 1; padding: 30px 40px; overflow-y: auto; }"
".page { display: none; }"
".page.active { display: block; }"
".page h3 { font-size: 16px; margin-bottom: 20px; color: #c0c0c8; }"
".setting { display: flex; align-items: center; margin: 12px 0; padding: 12px; background: rgba(255,255,255,0.03); border-radius: 8px; }"
".setting label { flex: 1; font-size: 12px; color: #909098; }"
".setting input[type=color] { width: 45px; height: 28px; border: none; border-radius: 4px; cursor: pointer; background: transparent; }"
".setting input[type=color]::-webkit-color-swatch-wrapper { padding: 2px; }"
".setting input[type=color]::-webkit-color-swatch { border-radius: 3px; border: 1px solid rgba(255,255,255,0.1); }"
".setting select { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); color: #e0e0e8; "
" padding: 6px 10px; border-radius: 4px; font-size: 11px; font-family: inherit; cursor: pointer; }"
".setting select option { background: #1a1a1f; }"
".setting input[type=text] { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); color: #e0e0e8; "
" padding: 6px 10px; border-radius: 4px; font-size: 11px; font-family: inherit; width: 250px; outline: none; }"
".setting input[type=text]:focus { border-color: var(--accent); }"
".setting input[type=text]::placeholder { color: #505060; }"
".reset-btn { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); color: #707080; "
" padding: 5px 10px; border-radius: 4px; cursor: pointer; font-size: 10px; margin-left: 8px; }"
".reset-btn:hover { background: rgba(255,255,255,0.1); color: #e0e0e8; }"
".reset-all { margin-top: 20px; padding: 8px 16px; background: var(--accent); "
" border: none; color: #0a0a0f; font-weight: bold; border-radius: 4px; cursor: pointer; font-size: 11px; }"
".reset-all:hover { opacity: 0.9; }"
".info-section { margin: 16px 0; padding: 16px; background: rgba(255,255,255,0.02); border-radius: 8px; }"
".info-section h4 { color: #909098; margin-bottom: 12px; font-size: 12px; }"
".info-section p { margin: 6px 0; font-size: 11px; color: #606070; }"
".info-section code { background: rgba(255,255,255,0.05); padding: 2px 6px; border-radius: 3px; color: #a0a0a8; }"
".version { margin-top: 30px; font-size: 10px; color: #404050; }"
"</style></head><body>"
"<div class='sidebar'>"
" <h2>Veil Einstellungen</h2>"
" <div class='nav-item active' onclick='showPage(\"general\")'>Allgemein</div>"
" <div class='nav-item' onclick='showPage(\"customize\")'>Anpassung</div>"
" <div class='nav-item' onclick='showPage(\"info\")'>Info</div>"
"</div>"
"<div class='content'>"
" <div id='general' class='page active'>"
" <h3>Allgemein</h3>"
" <div class='setting'>"
" <label>Suchmaschine</label>"
" <select id='search_engine' onchange='update(\"search_engine\", this.value)'>"
" <option value='0' %s>DuckDuckGo</option>"
" <option value='1' %s>Google</option>"
" <option value='2' %s>Brave</option>"
" <option value='3' %s>Startpage</option>"
" </select>"
" </div>"
" <div class='setting'>"
" <label>Lesezeichenleiste anzeigen</label>"
" <select id='show_bookmarks' onchange='update(\"show_bookmarks\", this.value)'>"
" <option value='1' %s>An</option>"
" <option value='0' %s>Aus</option>"
" </select>"
" </div>"
" <div class='setting'>"
" <label>Quick Links anzeigen</label>"
" <select id='show_quicklinks' onchange='update(\"show_quicklinks\", this.value)'>"
" <option value='1' %s>An</option>"
" <option value='0' %s>Aus</option>"
" </select>"
" </div>"
" <div class='setting'>"
" <label>Download-Speicherort</label>"
" <input type='text' id='download_dir' value='%s' placeholder='Standard: ~/Downloads' "
" onchange='update(\"download_dir\", this.value)'>"
" <button class='reset-btn' onclick='document.getElementById(\"download_dir\").value=\"\"; update(\"download_dir\", \"\")'>Reset</button>"
" </div>"
" </div>"
" <div id='customize' class='page'>"
" <h3>Anpassung</h3>"
" <div class='setting'>"
" <label>Hintergrundbild verwenden</label>"
" <select id='use_bg_image' onchange='update(\"use_bg_image\", this.value)'>"
" <option value='1' %s>An</option>"
" <option value='0' %s>Aus</option>"
" </select>"
" </div>"
" <div class='setting'>"
" <label>Hintergrundbild hochladen</label>"
" <input type='file' id='bg_image_file' accept='image/*' onchange='uploadBgImage(this)' "
" style='font-size:11px; color:#909098;'>"
" </div>"
" <div class='setting'>"
" <label>Bild-Deckkraft: <span id='opacity_val'>%d</span>%%</label>"
" <input type='range' id='bg_opacity' min='0' max='100' value='%d' "
" oninput='document.getElementById(\"opacity_val\").textContent=this.value' "
" onchange='update(\"bg_opacity\", this.value)' style='width:120px;'>"
" </div>"
" <div style='height:1px; background:rgba(255,255,255,0.1); margin:16px 0;'></div>"
" <h3 style='font-size:14px; color:#808090; margin-bottom:12px;'>Farben</h3>"
" <div class='setting'>"
" <label>Hintergrundfarbe</label>"
" <input type='color' id='bg' value='%s' onchange='update(\"bg\", this.value)'>"
" <button class='reset-btn' onclick='resetColor(\"bg\", \"%s\")'>Reset</button>"
" </div>"
" <div class='setting'>"
" <label>Akzentfarbe</label>"
" <input type='color' id='accent' value='%s' onchange='update(\"accent\", this.value)'>"
" <button class='reset-btn' onclick='resetColor(\"accent\", \"%s\")'>Reset</button>"
" </div>"
" <div class='setting'>"
" <label>Gradient Start</label>"
" <input type='color' id='grad_start' value='%s' onchange='update(\"grad_start\", this.value)'>"
" <button class='reset-btn' onclick='resetColor(\"grad_start\", \"%s\")'>Reset</button>"
" </div>"
" <div class='setting'>"
" <label>Gradient Mitte</label>"
" <input type='color' id='grad_mid' value='%s' onchange='update(\"grad_mid\", this.value)'>"
" <button class='reset-btn' onclick='resetColor(\"grad_mid\", \"%s\")'>Reset</button>"
" </div>"
" <div class='setting'>"
" <label>Gradient Ende</label>"
" <input type='color' id='grad_end' value='%s' onchange='update(\"grad_end\", this.value)'>"
" <button class='reset-btn' onclick='resetColor(\"grad_end\", \"%s\")'>Reset</button>"
" </div>"
" <button class='reset-all' onclick='resetAll()'>Alle zurücksetzen</button>"
" </div>"
" <div id='info' class='page'>"
" <h3>Info</h3>"
" <div class='info-section'>"
" <h4>Tastenkürzel</h4>"
" <p><code>Ctrl+T</code> Neuer Tab</p>"
" <p><code>Ctrl+W</code> Tab schließen</p>"
" <p><code>Ctrl+L</code> URL-Leiste fokussieren</p>"
" <p><code>Ctrl+R</code> / <code>F5</code> Neu laden</p>"
" <p><code>F11</code> Vollbild umschalten</p>"
" </div>"
" <div class='info-section'>"
" <h4>Über Veil</h4>"
" <p>Ein Privater WebKit-Browser, ohne unnötigen Müll :)</p>"
" <p>Gebaut mit GTK3 und WebKit2GTK</p>"
" <p>Entwickelt von Packed https://papp-box.de/</p>"
" </div>"
" <p class='version'>Veil Browser v1.0</p>"
" </div>"
"</div>"
"<script>"
"function showPage(id) {"
" document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));"
" document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));"
" document.getElementById(id).classList.add('active');"
" event.target.classList.add('active');"
"}"
"function update(key, val) {"
" window.webkit.messageHandlers.settings.postMessage(JSON.stringify({key:key, value:val}));"
"}"
"function resetColor(key, def) {"
" document.getElementById(key).value = def;"
" update(key, def);"
"}"
"function uploadBgImage(input) {"
" if (!input.files || !input.files[0]) return;"
" const file = input.files[0];"
" const reader = new FileReader();"
" reader.onload = function(e) {"
" const base64 = e.target.result.split(',')[1];"
" window.webkit.messageHandlers.settings.postMessage(JSON.stringify({key:'bg_image', value:base64}));"
" };"
" reader.readAsDataURL(file);"
"}"
"function resetAll() {"
" resetColor('bg', '%s');"
" resetColor('accent', '%s');"
" resetColor('grad_start', '%s');"
" resetColor('grad_mid', '%s');"
" resetColor('grad_end', '%s');"
"}"
"</script></body></html>";
#endif /* VEIL_PAGE_SETTINGS_H */

398
Veil/src/pages/start.h Normal file
View File

@@ -0,0 +1,398 @@
/*
* Veil Browser - Start Page (about:start)
*/
#ifndef VEIL_PAGE_START_H
#define VEIL_PAGE_START_H
static const char *START_HTML =
"<!DOCTYPE html>"
"<html><head><meta charset='utf-8'><title>Veil</title>"
"<style>"
":root { --bg: %s; --accent: %s; --grad-start: %s; --grad-mid: %s; --grad-end: %s; }"
"* { box-sizing: border-box; margin: 0; padding: 0; }"
"body {"
" font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', monospace;"
" background: var(--bg);"
" color: #e0e0e8;"
" min-height: 100vh;"
" display: flex;"
" flex-direction: column;"
" align-items: center;"
" justify-content: center;"
" padding: 20px;"
" %s" /* background-image style if set */
"}"
".container {"
" display: flex;"
" flex-direction: column;"
" align-items: center;"
" width: 100%%;"
" max-width: 700px;"
" margin-top: -80px;"
"}"
".hero {"
" display: flex;"
" align-items: center;"
" gap: 30px;"
" margin-bottom: 40px;"
"}"
".logo {"
" width: 100px;"
" height: 100px;"
" position: relative;"
"}"
".logo img {"
" width: 100%%;"
" height: 100%%;"
" object-fit: contain;"
" border-radius: 50%%;"
"}"
".logo::after {"
" content: '';"
" position: absolute;"
" top: 0; left: 0; right: 0; bottom: 0;"
" background: linear-gradient(135deg, var(--grad-start), var(--grad-mid), var(--grad-end));"
" border-radius: 50%%;"
" mix-blend-mode: color;"
" pointer-events: none;"
"}"
".ascii-brand {"
" font-size: 14px;"
" line-height: 1.1;"
" font-weight: bold;"
" white-space: pre;"
" background: linear-gradient(135deg, var(--grad-start), var(--grad-mid), var(--grad-end));"
" -webkit-background-clip: text;"
" -webkit-text-fill-color: transparent;"
" background-clip: text;"
"}"
".search-container {"
" width: 100%%;"
" position: relative;"
"}"
".search-box {"
" width: 100%%;"
" padding: 16px 50px 16px 20px;"
" font-size: 15px;"
" font-family: inherit;"
" background: rgba(255,255,255,0.03);"
" border: 1px solid rgba(255,255,255,0.08);"
" border-radius: 12px;"
" color: #e0e0e8;"
" outline: none;"
" transition: all 0.2s ease;"
"}"
".search-box::placeholder { color: #505060; }"
".search-box:focus {"
" border-color: var(--accent);"
" background: rgba(255,255,255,0.05);"
" box-shadow: 0 0 0 3px rgba(74, 158, 255, 0.1);"
"}"
".search-icon {"
" position: absolute;"
" right: 16px;"
" top: 50%%;"
" transform: translateY(-50%%);"
" width: 20px;"
" height: 20px;"
" opacity: 0.4;"
" pointer-events: none;"
"}"
".quicklinks-section {"
" display: %s;"
"}"
".shortcuts-header {"
" display: flex;"
" align-items: center;"
" gap: 12px;"
" margin-top: 50px;"
" margin-bottom: 16px;"
"}"
".shortcuts-title {"
" font-size: 11px;"
" color: #505060;"
" text-transform: uppercase;"
" letter-spacing: 2px;"
"}"
".edit-btn {"
" background: transparent;"
" border: 1px solid rgba(255,255,255,0.1);"
" color: #606070;"
" padding: 4px 10px;"
" border-radius: 6px;"
" font-size: 10px;"
" cursor: pointer;"
" font-family: inherit;"
" transition: all 0.2s;"
"}"
".edit-btn:hover { border-color: var(--accent); color: var(--accent); }"
".edit-btn.active { background: var(--accent); color: var(--bg); border-color: var(--accent); }"
".shortcuts {"
" display: flex;"
" gap: 16px;"
" flex-wrap: wrap;"
" justify-content: center;"
"}"
".shortcut {"
" display: flex;"
" flex-direction: column;"
" align-items: center;"
" padding: 16px 20px;"
" background: rgba(255,255,255,0.02);"
" border: 1px solid rgba(255,255,255,0.05);"
" border-radius: 12px;"
" cursor: pointer;"
" transition: all 0.2s ease;"
" text-decoration: none;"
" color: inherit;"
" min-width: 90px;"
" position: relative;"
"}"
".shortcut:hover {"
" background: rgba(255,255,255,0.05);"
" border-color: rgba(255,255,255,0.1);"
" transform: translateY(-2px);"
"}"
".shortcut-icon {"
" width: 32px;"
" height: 32px;"
" margin-bottom: 8px;"
" display: flex;"
" align-items: center;"
" justify-content: center;"
" font-size: 20px;"
"}"
".shortcut-icon img {"
" width: 24px;"
" height: 24px;"
" border-radius: 4px;"
" object-fit: contain;"
"}"
".shortcut-icon .emoji {"
" font-size: 20px;"
"}"
".shortcut-label {"
" font-size: 11px;"
" color: #707080;"
"}"
".shortcut .delete-btn {"
" position: absolute;"
" top: -8px;"
" right: -8px;"
" width: 20px;"
" height: 20px;"
" background: #f85149;"
" border: none;"
" border-radius: 50%%;"
" color: white;"
" font-size: 14px;"
" cursor: pointer;"
" display: none;"
" align-items: center;"
" justify-content: center;"
" line-height: 1;"
"}"
".editing .shortcut .delete-btn { display: flex; }"
".editing .shortcut:hover { transform: none; }"
".add-shortcut {"
" display: none;"
" flex-direction: column;"
" align-items: center;"
" justify-content: center;"
" padding: 16px 20px;"
" background: transparent;"
" border: 2px dashed rgba(255,255,255,0.1);"
" border-radius: 12px;"
" cursor: pointer;"
" min-width: 90px;"
" color: #505060;"
" transition: all 0.2s;"
"}"
".editing .add-shortcut { display: flex; }"
".add-shortcut:hover { border-color: var(--accent); color: var(--accent); }"
".add-shortcut span { font-size: 24px; }"
".modal {"
" display: none;"
" position: fixed;"
" top: 0; left: 0; right: 0; bottom: 0;"
" background: rgba(0,0,0,0.8);"
" align-items: center;"
" justify-content: center;"
" z-index: 100;"
"}"
".modal.show { display: flex; }"
".modal-content {"
" background: #151520;"
" padding: 24px;"
" border-radius: 12px;"
" border: 1px solid rgba(255,255,255,0.1);"
" width: 300px;"
"}"
".modal-title {"
" font-size: 14px;"
" margin-bottom: 16px;"
" color: #e0e0e8;"
"}"
".modal input {"
" width: 100%%;"
" padding: 10px 12px;"
" margin-bottom: 12px;"
" background: rgba(255,255,255,0.05);"
" border: 1px solid rgba(255,255,255,0.1);"
" border-radius: 8px;"
" color: #e0e0e8;"
" font-family: inherit;"
" font-size: 13px;"
" outline: none;"
"}"
".modal input:focus { border-color: var(--accent); }"
".modal-buttons {"
" display: flex;"
" gap: 8px;"
" justify-content: flex-end;"
" margin-top: 8px;"
"}"
".modal-buttons button {"
" padding: 8px 16px;"
" border-radius: 6px;"
" font-family: inherit;"
" font-size: 12px;"
" cursor: pointer;"
" border: none;"
"}"
".modal-buttons .cancel { background: rgba(255,255,255,0.1); color: #a0a0a0; }"
".modal-buttons .save { background: var(--accent); color: #000; }"
".footer {"
" position: fixed;"
" bottom: 20px;"
" font-size: 10px;"
" color: #303040;"
"}"
"</style></head><body>"
"<div class='container'>"
" <div class='hero'>"
" <div class='logo'>"
" <img src='%s' alt='Veil'>"
" </div>"
" <pre class='ascii-brand'>██╗ ██╗███████╗██╗██╗ \n"
"██║ ██║██╔════╝██║██║ \n"
"██║ ██║█████╗ ██║██║ \n"
"╚██╗ ██╔╝██╔══╝ ██║██║ \n"
" ╚████╔╝ ███████╗██║███████╗\n"
" ╚═══╝ ╚══════╝╚═╝╚══════╝</pre>"
" </div>"
" <div class='search-container'>"
" <input type='text' class='search-box' id='search' placeholder='Suchen oder URL eingeben...' autofocus>"
" <svg class='search-icon' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'>"
" <circle cx='11' cy='11' r='8'/><path d='m21 21-4.35-4.35'/>"
" </svg>"
" </div>"
" <div class='quicklinks-section'>"
" <div class='shortcuts-header'>"
" <span class='shortcuts-title'>Quick Links</span>"
" <button class='edit-btn' id='editBtn'>Bearbeiten</button>"
" </div>"
" <div class='shortcuts' id='shortcuts'></div>"
" </div>"
"</div>"
"<div class='modal' id='modal'>"
" <div class='modal-content'>"
" <div class='modal-title'>Neuer Quick Link</div>"
" <input type='text' id='linkName' placeholder='Name (z.B. Google)'>"
" <input type='text' id='linkUrl' placeholder='URL (z.B. https://google.com)'>"
" <input type='text' id='linkIcon' placeholder='Icon Emoji (z.B. 🔍)' maxlength='2'>"
" <div class='modal-buttons'>"
" <button class='cancel' onclick='closeModal()'>Abbrechen</button>"
" <button class='save' onclick='saveLink()'>Speichern</button>"
" </div>"
" </div>"
"</div>"
"<div class='footer'>Veil Browser</div>"
"<script>"
"const defaultLinks = ["
" {name: 'DuckDuckGo', url: 'https://duckduckgo.com', icon: '🦆'},"
" {name: 'GitHub', url: 'https://github.com', icon: '⚙'},"
" {name: 'YouTube', url: 'https://youtube.com', icon: '▶'},"
" {name: 'Settings', url: 'veil:settings', icon: '⚙'}"
"];"
"let links = JSON.parse(localStorage.getItem('veil_quicklinks')) || defaultLinks;"
"let editing = false;"
""
"function getFaviconUrl(url) {"
" try {"
" const u = new URL(url);"
" return 'https://www.google.com/s2/favicons?domain=' + u.hostname + '&sz=64';"
" } catch { return null; }"
"}"
""
"function renderLinks() {"
" const container = document.getElementById('shortcuts');"
" container.innerHTML = '';"
" links.forEach((link, i) => {"
" const el = document.createElement('a');"
" el.className = 'shortcut';"
" el.href = link.url;"
" const isInternal = link.url.startsWith('veil:') || link.url.startsWith('about:');"
" const faviconUrl = !isInternal ? getFaviconUrl(link.url) : null;"
" const iconHtml = faviconUrl "
" ? `<img src='${faviconUrl}' onerror=\"this.parentNode.innerHTML='<span class=emoji>${link.icon}</span>'\">`"
" : `<span class='emoji'>${link.icon}</span>`;"
" el.innerHTML = `"
" <button class='delete-btn' onclick='deleteLink(event, ${i})'>×</button>"
" <div class='shortcut-icon'>${iconHtml}</div>"
" <div class='shortcut-label'>${link.name}</div>"
" `;"
" container.appendChild(el);"
" });"
" const addBtn = document.createElement('div');"
" addBtn.className = 'add-shortcut';"
" addBtn.innerHTML = '<span>+</span>';"
" addBtn.onclick = () => document.getElementById('modal').classList.add('show');"
" container.appendChild(addBtn);"
"}"
""
"function deleteLink(e, index) {"
" e.preventDefault();"
" e.stopPropagation();"
" links.splice(index, 1);"
" localStorage.setItem('veil_quicklinks', JSON.stringify(links));"
" renderLinks();"
"}"
""
"function closeModal() {"
" document.getElementById('modal').classList.remove('show');"
" document.getElementById('linkName').value = '';"
" document.getElementById('linkUrl').value = '';"
" document.getElementById('linkIcon').value = '';"
"}"
""
"function saveLink() {"
" const name = document.getElementById('linkName').value.trim();"
" let url = document.getElementById('linkUrl').value.trim();"
" const icon = document.getElementById('linkIcon').value || '🔗';"
" if (!name || !url) return;"
" if (!url.startsWith('http') && !url.startsWith('about:')) url = 'https://' + url;"
" links.push({name, url, icon});"
" localStorage.setItem('veil_quicklinks', JSON.stringify(links));"
" closeModal();"
" renderLinks();"
"}"
""
"document.getElementById('editBtn').onclick = function() {"
" editing = !editing;"
" this.classList.toggle('active', editing);"
" this.textContent = editing ? 'Fertig' : 'Bearbeiten';"
" document.querySelector('.container').classList.toggle('editing', editing);"
"};"
""
"document.getElementById('search').addEventListener('keydown', function(e) {"
" if (e.key === 'Enter' && this.value.trim()) {"
" window.webkit.messageHandlers.navigate.postMessage(this.value.trim());"
" }"
"});"
""
"renderLinks();"
"</script></body></html>";
#endif /* VEIL_PAGE_START_H */

2414
Veil/src/veil.c Normal file

File diff suppressed because it is too large Load Diff

BIN
Veil/veil Executable file

Binary file not shown.