Initial commit (Projekt wurde lokal auf meinem PC gestartet)
24
README.md
@@ -1,3 +1,27 @@
|
|||||||
# Veil
|
# Veil
|
||||||
|
|
||||||
Veil ist ein auf WebKit basierender Simpler Browser, in GTK
|
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
@@ -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
|
||||||
BIN
Veil/Projektdateien (EXTERN)/Weil Icon.afphoto
Normal file
BIN
Veil/Projektdateien (EXTERN)/Weil Icon.afphoto~lock~
Normal file
88
Veil/build.sh
Executable 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
BIN
Veil/data/icons/hicolor/128x128/apps/veil.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
Veil/data/icons/hicolor/16x16/apps/veil.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
Veil/data/icons/hicolor/24x24/apps/veil.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Veil/data/icons/hicolor/256x256/apps/veil.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
Veil/data/icons/hicolor/32x32/apps/veil.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
Veil/data/icons/hicolor/48x48/apps/veil.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
Veil/data/icons/hicolor/512x512/apps/veil.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
Veil/data/icons/hicolor/64x64/apps/veil.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
17
Veil/data/icons/hicolor/scalable/apps/veil.svg
Normal file
|
After Width: | Height: | Size: 901 KiB |
14
Veil/data/meson.build
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||||