feat: add themes and custom color options

feat: add italian translation
This commit is contained in:
Miguel Ribeiro 2024-04-19 14:22:07 +02:00 committed by GitHub
parent 2c186b4818
commit 70e42349ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
91 changed files with 751 additions and 98 deletions

View File

@ -1,7 +1,7 @@
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./images/wallossolidwhite.png"> <source media="(prefers-color-scheme: dark)" srcset="./images/siteicons/blue/walloswhite.png">
<source media="(prefers-color-scheme: light)" srcset="./images/wallossolid.png"> <source media="(prefers-color-scheme: light)" srcset="./images/siteicons/blue/wallos.png">
<img alt="Wallos" src="./images/wallossolid.png"> <img alt="Wallos" src="./images/siteicons/blue/wallos.png">
</picture> </picture>
Wallos: Open-Source Personal Subscription Tracker Wallos: Open-Source Personal Subscription Tracker

View File

@ -0,0 +1,34 @@
<?php
require_once '../../includes/connect_endpoint.php';
session_start();
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
die(json_encode([
"success" => false,
"message" => translate('session_expired', $i18n)
]));
}
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$postData = file_get_contents("php://input");
$data = json_decode($postData, true);
$color = $data['color'];
$stmt = $db->prepare('UPDATE settings SET color_theme = :color');
$stmt->bindParam(':color', $color, SQLITE3_TEXT);
if ($stmt->execute()) {
die(json_encode([
"success" => true,
"message" => translate("success", $i18n)
]));
} else {
die(json_encode([
"success" => false,
"message" => translate("error", $i18n)
]));
}
}
?>

View File

@ -0,0 +1,41 @@
<?php
require_once '../../includes/connect_endpoint.php';
session_start();
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
die(json_encode([
"success" => false,
"message" => translate('session_expired', $i18n)
]));
}
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$postData = file_get_contents("php://input");
$data = json_decode($postData, true);
$main_color = $data['mainColor'];
$accent_color = $data['accentColor'];
$hover_color = $data['hoverColor'];
$stmt = $db->prepare('DELETE FROM custom_colors');
$stmt->execute();
$stmt = $db->prepare('INSERT INTO custom_colors (main_color, accent_color, hover_color) VALUES (:main_color, :accent_color, :hover_color)');
$stmt->bindParam(':main_color', $main_color, SQLITE3_TEXT);
$stmt->bindParam(':accent_color', $accent_color, SQLITE3_TEXT);
$stmt->bindParam(':hover_color', $hover_color, SQLITE3_TEXT);
if ($stmt->execute()) {
die(json_encode([
"success" => true,
"message" => translate("success", $i18n)
]));
} else {
die(json_encode([
"success" => false,
"message" => translate("error", $i18n)
]));
}
}
?>

View File

@ -0,0 +1,28 @@
<?php
require_once '../../includes/connect_endpoint.php';
session_start();
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
die(json_encode([
"success" => false,
"message" => translate('session_expired', $i18n)
]));
}
if ($_SERVER["REQUEST_METHOD"] === "DELETE") {
$stmt = $db->prepare('DELETE FROM custom_colors');
if ($stmt->execute()) {
die(json_encode([
"success" => true,
"message" => translate("success", $i18n)
]));
} else {
die(json_encode([
"success" => false,
"message" => translate("error", $i18n)
]));
}
}
?>

View File

@ -14,6 +14,11 @@
$theme = $settings['theme']; $theme = $settings['theme'];
} }
$colorTheme = "blue";
if (isset($settings['color_theme'])) {
$colorTheme = $settings['color_theme'];
}
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) { if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
$sort = "next_payment"; $sort = "next_payment";
$order = "ASC"; $order = "ASC";
@ -63,7 +68,7 @@
} }
} }
$defaultLogo = $theme == "light" ? "images/wallos.png" : "images/walloswhite.png"; $defaultLogo = $theme == "light" ? "images/siteicons/" . $colorTheme . "/wallos.png" : "images/siteicons/" . $colorTheme . "/walloswhite.png";
foreach ($subscriptions as $subscription) { foreach ($subscriptions as $subscription) {
$id = $subscription['id']; $id = $subscription['id'];
$print[$id]['id'] = $id; $print[$id]['id'] = $id;
@ -97,7 +102,7 @@
} }
if (isset($print)) { if (isset($print)) {
printSubscriptions($print, $sort, $categories, $members, $i18n); printSubscriptions($print, $sort, $categories, $members, $i18n, $colorTheme);
} }
if (count($subscriptions) == 0) { if (count($subscriptions) == 0) {

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 846 B

After

Width:  |  Height:  |  Size: 846 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -7,9 +7,18 @@ if ($settings) {
$cookieExpire = time() + (30 * 24 * 60 * 60); $cookieExpire = time() + (30 * 24 * 60 * 60);
setcookie('theme', $settings['dark_theme'] ? 'dark': 'light', $cookieExpire); setcookie('theme', $settings['dark_theme'] ? 'dark': 'light', $cookieExpire);
$settings['theme'] = $settings['dark_theme'] ? 'dark': 'light'; $settings['theme'] = $settings['dark_theme'] ? 'dark': 'light';
$settings['color_theme'] = $settings['color_theme'] ? $settings['color_theme'] : "blue";
$settings['showMonthlyPrice'] = $settings['monthly_price'] ? 'true': 'false'; $settings['showMonthlyPrice'] = $settings['monthly_price'] ? 'true': 'false';
$settings['convertCurrency'] = $settings['convert_currency'] ? 'true': 'false'; $settings['convertCurrency'] = $settings['convert_currency'] ? 'true': 'false';
$settings['removeBackground'] = $settings['remove_background'] ? 'true': 'false'; $settings['removeBackground'] = $settings['remove_background'] ? 'true': 'false';
} }
$query = "SELECT * FROM custom_colors";
$result = $db->query($query);
$customColors = $result->fetchArray(SQLITE3_ASSOC);
if ($customColors) {
$settings['customColors'] = $customColors;
}
?> ?>

View File

@ -23,6 +23,10 @@
$theme = $settings['theme']; $theme = $settings['theme'];
} }
$colorTheme = "blue";
if (isset($settings['color_theme'])) {
$colorTheme = $settings['color_theme'];
}
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
@ -34,8 +38,12 @@
<link rel="icon" type="image/png" href="images/icon/favicon.ico" sizes="16x16"> <link rel="icon" type="image/png" href="images/icon/favicon.ico" sizes="16x16">
<link rel="apple-touch-icon" sizes="180x180" href="images/icon/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="images/icon/apple-touch-icon.png">
<link rel="manifest" href="manifest.json" crossorigin="use-credentials"> <link rel="manifest" href="manifest.json" crossorigin="use-credentials">
<link rel="stylesheet" href="styles/theme.css?<?= $version ?>">
<link rel="stylesheet" href="styles/styles.css?<?= $version ?>"> <link rel="stylesheet" href="styles/styles.css?<?= $version ?>">
<link rel="stylesheet" href="styles/dark-theme.css?<?= $version ?>" id="dark-theme" <?= $theme == "light" ? "disabled" : "" ?>> <link rel="stylesheet" href="styles/dark-theme.css?<?= $version ?>" id="dark-theme" <?= $theme == "light" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/themes/red.css?<?= $version ?>" id="red-theme" <?= $colorTheme != "red" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/themes/green.css?<?= $version ?>" id="green-theme" <?= $colorTheme != "green" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/themes/yellow.css?<?= $version ?>" id="yellow-theme" <?= $colorTheme != "yellow" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/barlow.css"> <link rel="stylesheet" href="styles/barlow.css">
<link rel="stylesheet" href="styles/font-awesome.min.css"> <link rel="stylesheet" href="styles/font-awesome.min.css">
<script type="text/javascript" src="scripts/all.js?<?= $version ?>"></script> <script type="text/javascript" src="scripts/all.js?<?= $version ?>"></script>
@ -43,11 +51,31 @@
<script type="text/javascript"> <script type="text/javascript">
window.theme = "<?= $theme ?>"; window.theme = "<?= $theme ?>";
window.lang = "<?=$lang ?>"; window.lang = "<?=$lang ?>";
window.colorTheme = "<?= $colorTheme ?>";
</script> </script>
<?php
if (isset($settings['customColors'])) {
?>
<style id="custom_theme_colors">
:root {
<?php if (isset($settings['customColors']['main_color']) && !empty($settings['customColors']['main_color'])): ?>
--main-color: <?= $settings['customColors']['main_color'] ?>;
<?php endif; ?>
<?php if (isset($settings['customColors']['accent_color']) && !empty($settings['customColors']['accent_color'])): ?>
--accent-color: <?= $settings['customColors']['accent_color'] ?>;
<?php endif; ?>
<?php if (isset($settings['customColors']['hover_color']) && !empty($settings['customColors']['hover_color'])): ?>
--hover-color: <?= $settings['customColors']['hover_color'] ?>;
<?php endif; ?>
}
</style>
<?php
}
?>
<script type="text/javascript" src="scripts/i18n/<?= $lang ?>.js?<?= $version ?>"></script> <script type="text/javascript" src="scripts/i18n/<?= $lang ?>.js?<?= $version ?>"></script>
<script type="text/javascript" src="scripts/i18n/getlang.js?<?= $version ?>"></script> <script type="text/javascript" src="scripts/i18n/getlang.js?<?= $version ?>"></script>
</head> </head>
<body> <body class="<?= $theme ?>">
<header> <header>
<div class="contain"> <div class="contain">
<div class="logo"> <div class="logo">

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Erhalte deinen kostenfreien Fixer API Key", "get_free_fixer_api_key" => "Erhalte deinen kostenfreien Fixer API Key",
"get_key_alternative" => "Alternativ können Sie einen kostenlosen Fixer-Api-Schlüssel erhalten von", "get_key_alternative" => "Alternativ können Sie einen kostenlosen Fixer-Api-Schlüssel erhalten von",
"display_settings" => "Display-Einstellungen", "display_settings" => "Display-Einstellungen",
"theme_settings" => "Themen-Einstellungen",
"custom_colors" => "Benutzerdefinierte Farben",
"dark_theme" => "Dark Theme",
"switch_theme" => "Light / Dark Theme umschalten", "switch_theme" => "Light / Dark Theme umschalten",
"calculate_monthly_price" => "Berechne und zeige monatlichen Preis für alle Abonnements an", "calculate_monthly_price" => "Berechne und zeige monatlichen Preis für alle Abonnements an",
"convert_prices" => "Preise immer in meine Hauptwährung umrechnen und darin anzeigen (langsamer)", "convert_prices" => "Preise immer in meine Hauptwährung umrechnen und darin anzeigen (langsamer)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test", "test" => "Test",
"add" => "Hinzufügen", "add" => "Hinzufügen",
"save" => "Speichern", "save" => "Speichern",
"reset" => "Zurücksetzen",
"export_subscriptions" => "Abonnements exportieren", "export_subscriptions" => "Abonnements exportieren",
"export_to_json" => "Nach JSON exportieren", "export_to_json" => "Nach JSON exportieren",
// Filters menu // Filters menu

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Απόκτησε ΔΩΡΕΑΝ Fixer API κλειδί", "get_free_fixer_api_key" => "Απόκτησε ΔΩΡΕΑΝ Fixer API κλειδί",
"get_key_alternative" => "Εναλλακτικά, μπορείτε να λάβετε ένα δωρεάν κλειδί api fixer από το", "get_key_alternative" => "Εναλλακτικά, μπορείτε να λάβετε ένα δωρεάν κλειδί api fixer από το",
"display_settings" => "Ρυθμίσεις εμφάνισης", "display_settings" => "Ρυθμίσεις εμφάνισης",
"theme_settings" => "Ρυθμίσεις θέματος",
"custom_colors" => "Προσαρμοσμένα χρώματα",
"dark_theme" => "Dark Theme",
"switch_theme" => "Διακόπτης Light / Dark Theme", "switch_theme" => "Διακόπτης Light / Dark Theme",
"calculate_monthly_price" => "Υπολογισμός και εμφάνιση της μηνιαίας τιμής για όλες τις συνδρομές", "calculate_monthly_price" => "Υπολογισμός και εμφάνιση της μηνιαίας τιμής για όλες τις συνδρομές",
"convert_prices" => "Πάντα να μετατρέπει και να εμφανίζει τις τιμές στο κύριο νόμισμά μου (πιο αργό)", "convert_prices" => "Πάντα να μετατρέπει και να εμφανίζει τις τιμές στο κύριο νόμισμά μου (πιο αργό)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Δοκιμή", "test" => "Δοκιμή",
"add" => "Προσθήκη", "add" => "Προσθήκη",
"save" => "Αποθήκευση", "save" => "Αποθήκευση",
"reset" => "Επαναφορά",
"export_subscriptions" => "Εξαγωγή συνδρομών", "export_subscriptions" => "Εξαγωγή συνδρομών",
"export_to_json" => "Εξαγωγή σε JSON", "export_to_json" => "Εξαγωγή σε JSON",
// Filters menu // Filters menu

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Get free Fixer API Key", "get_free_fixer_api_key" => "Get free Fixer API Key",
"get_key_alternative" => "Alternatively, you can get a free fixer api key from", "get_key_alternative" => "Alternatively, you can get a free fixer api key from",
"display_settings" => "Display Settings", "display_settings" => "Display Settings",
"theme_settings" => "Theme Settings",
"custom_colors" => "Custom Colors",
"dark_theme" => "Dark Theme",
"switch_theme" => "Switch Light / Dark Theme", "switch_theme" => "Switch Light / Dark Theme",
"calculate_monthly_price" => "Calculate and show monthly price for all subscriptions", "calculate_monthly_price" => "Calculate and show monthly price for all subscriptions",
"convert_prices" => "Always convert and show prices on my main currency (slower)", "convert_prices" => "Always convert and show prices on my main currency (slower)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test", "test" => "Test",
"add" => "Add", "add" => "Add",
"save" => "Save", "save" => "Save",
"reset" => "Reset",
"export_subscriptions" => "Export Subscriptions", "export_subscriptions" => "Export Subscriptions",
"export_to_json" => "Export to JSON", "export_to_json" => "Export to JSON",
// Filters menu // Filters menu

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Obtén una API Key de Fixer gratuita", "get_free_fixer_api_key" => "Obtén una API Key de Fixer gratuita",
"get_key_alternative" => "También puede obtener una clave api gratuita de Fixer en", "get_key_alternative" => "También puede obtener una clave api gratuita de Fixer en",
"display_settings" => "Configuración de Pantalla", "display_settings" => "Configuración de Pantalla",
"theme_settings" => "Configuración de Tema",
"custom_collors" => "Colores Personalizados",
"dark_theme" => "Tema Oscuro",
"switch_theme" => "Cambiar entre Tema Claro / Oscuro", "switch_theme" => "Cambiar entre Tema Claro / Oscuro",
"calculate_monthly_price" => "Calcular y mostrar el precio mensual de todas las suscripciones", "calculate_monthly_price" => "Calcular y mostrar el precio mensual de todas las suscripciones",
"convert_prices" => "Convertir y mostrar siempre los precios en mi moneda principal (más lento)", "convert_prices" => "Convertir y mostrar siempre los precios en mi moneda principal (más lento)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Probar", "test" => "Probar",
"add" => "Agregar", "add" => "Agregar",
"save" => "Guardar", "save" => "Guardar",
"reset" => "Restablecer",
"export_subscriptions" => "Exportar suscripciones", "export_subscriptions" => "Exportar suscripciones",
"export_to_json" => "Exportar a JSON", "export_to_json" => "Exportar a JSON",
// Filters menu // Filters menu

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Obtenez une clé API Fixer gratuite", "get_free_fixer_api_key" => "Obtenez une clé API Fixer gratuite",
"get_key_alternative" => "Vous pouvez également obtenir une clé api de fixation gratuite auprès de", "get_key_alternative" => "Vous pouvez également obtenir une clé api de fixation gratuite auprès de",
"display_settings" => "Paramètres d'affichage", "display_settings" => "Paramètres d'affichage",
"theme_settings" => "Paramètres de thème",
"custom_colors" => "Couleurs personnalisées",
"dark_theme" => "Thème sombre",
"switch_theme" => "Basculer entre le thème clair et sombre", "switch_theme" => "Basculer entre le thème clair et sombre",
"calculate_monthly_price" => "Calculer et afficher le prix mensuel pour tous les abonnements", "calculate_monthly_price" => "Calculer et afficher le prix mensuel pour tous les abonnements",
"convert_prices" => "Convertir toujours et afficher les prix dans ma devise principale (plus lent)", "convert_prices" => "Convertir toujours et afficher les prix dans ma devise principale (plus lent)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test", "test" => "Test",
"add" => "Ajouter", "add" => "Ajouter",
"save" => "Enregistrer", "save" => "Enregistrer",
"reset" => "Réinitialiser",
"export_subscriptions" => "Exporter les abonnements", "export_subscriptions" => "Exporter les abonnements",
"export_to_json" => "Exporter en JSON", "export_to_json" => "Exporter en JSON",
// Menu des filtes // Menu des filtes

View File

@ -144,6 +144,9 @@ $i18n = [
'get_free_fixer_api_key' => 'Ottieni gratuitamente la chiave API di Fixer', 'get_free_fixer_api_key' => 'Ottieni gratuitamente la chiave API di Fixer',
'get_key_alternative' => 'In alternativa, puoi ottenere gratuitamente una chiave API di Fixer da', 'get_key_alternative' => 'In alternativa, puoi ottenere gratuitamente una chiave API di Fixer da',
'display_settings' => 'Impostazioni di visualizzazione', 'display_settings' => 'Impostazioni di visualizzazione',
"theme_settings" => 'Impostazioni del tema',
"custom_colors" => 'Colori personalizzati',
"dark_theme" => 'Tema scuro',
'switch_theme' => 'Cambia tema chiaro/scuro', 'switch_theme' => 'Cambia tema chiaro/scuro',
'calculate_monthly_price' => 'Calcola e mostra il prezzo mensile per tutti gli abbonamenti', 'calculate_monthly_price' => 'Calcola e mostra il prezzo mensile per tutti gli abbonamenti',
'convert_prices' => 'Converti sempre e mostra i prezzi nella mia valuta principale (più lento)', 'convert_prices' => 'Converti sempre e mostra i prezzi nella mia valuta principale (più lento)',
@ -166,6 +169,7 @@ $i18n = [
'test' => 'Test', 'test' => 'Test',
'add' => 'Aggiungi', 'add' => 'Aggiungi',
'save' => 'Salva', 'save' => 'Salva',
"reset" => 'Ripristina',
'export_subscriptions' => 'Esporta abbonamenti', 'export_subscriptions' => 'Esporta abbonamenti',
'export_to_json' => 'Esporta in JSON', 'export_to_json' => 'Esporta in JSON',

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "無料のFixer APIキーを取得", "get_free_fixer_api_key" => "無料のFixer APIキーを取得",
"get_key_alternative" => "または、以下のサイトから無料のフィクサーapiキーを入手することもできます。", "get_key_alternative" => "または、以下のサイトから無料のフィクサーapiキーを入手することもできます。",
"display_settings" => "表示設定", "display_settings" => "表示設定",
"theme_settings" => "テーマ設定",
"custom_colors" => "カスタムカラー",
"dark_theme" => "ダークテーマ",
"switch_theme" => "ライト/ダーク テーマの切り替え", "switch_theme" => "ライト/ダーク テーマの切り替え",
"calculate_monthly_price" => "すべての定期購入の月額料金を計算して表示する", "calculate_monthly_price" => "すべての定期購入の月額料金を計算して表示する",
"convert_prices" => "常にメイン通貨で価格を換算して表示する (遅い)", "convert_prices" => "常にメイン通貨で価格を換算して表示する (遅い)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "テスト", "test" => "テスト",
"add" => "追加", "add" => "追加",
"save" => "保存", "save" => "保存",
"reset" => "リセット",
"export_subscriptions" => "購読をエクスポート", "export_subscriptions" => "購読をエクスポート",
"export_to_json" => "JSONにエクスポート", "export_to_json" => "JSONにエクスポート",
// Filters menu // Filters menu

View File

@ -12,8 +12,8 @@
"it" => "Italiano", "it" => "Italiano",
"jp" => "日本語", "jp" => "日本語",
"pl" => "Polski", "pl" => "Polski",
"pt_br" => "Português Brasileiro",
"pt" => "Português", "pt" => "Português",
"pt_br" => "Português Brasileiro",
"sr_lat" => "Srpski", "sr_lat" => "Srpski",
"sr" => "Српски", "sr" => "Српски",
"tr" => "Türkçe", "tr" => "Türkçe",

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Uzyskaj bezpłatny klucz API Fixer'a", "get_free_fixer_api_key" => "Uzyskaj bezpłatny klucz API Fixer'a",
"get_key_alternative" => "Alternatywnie, możesz uzyskać darmowy klucz api fixer'a od", "get_key_alternative" => "Alternatywnie, możesz uzyskać darmowy klucz api fixer'a od",
"display_settings" => "Ustawienia wyświetlania", "display_settings" => "Ustawienia wyświetlania",
"theme_settings" => "Ustawienia motywu",
"custom_colors" => "Kolory niestandardowe",
"dark_theme" => "Przełącz na jasny/ciemny motyw",
"switch_theme" => "Przełącz na jasny/ciemny motyw", "switch_theme" => "Przełącz na jasny/ciemny motyw",
"calculate_monthly_price" => "Oblicz i pokaż miesięczną cenę wszystkich subskrypcji", "calculate_monthly_price" => "Oblicz i pokaż miesięczną cenę wszystkich subskrypcji",
"convert_prices" => "Zawsze przeliczaj i pokazuj ceny w mojej głównej walucie (wolniej)", "convert_prices" => "Zawsze przeliczaj i pokazuj ceny w mojej głównej walucie (wolniej)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test", "test" => "Test",
"add" => "Dodaj", "add" => "Dodaj",
"save" => "Zapisz", "save" => "Zapisz",
"reset" => "Resetuj",
"export_subscriptions" => "Eksportuj subskrypcje", "export_subscriptions" => "Eksportuj subskrypcje",
"export_to_json" => "Eksportuj do JSON", "export_to_json" => "Eksportuj do JSON",
// Filters menu // Filters menu

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Obtenha a sua API Key grátis do Fixer", "get_free_fixer_api_key" => "Obtenha a sua API Key grátis do Fixer",
"get_key_alternative" => "Como alternativa obtenha a sua API Key em", "get_key_alternative" => "Como alternativa obtenha a sua API Key em",
"display_settings" => "Definições de visualização", "display_settings" => "Definições de visualização",
"theme_settings" => "Definições de Tema",
"custom_colors" => "Cores Personalizadas",
"dark_theme" => "Tema Escuro",
"switch_theme" => "Trocar Tema Claro / Escuro", "switch_theme" => "Trocar Tema Claro / Escuro",
"calculate_monthly_price" => "Calcular e mostrar preço mensal para todas as subscrições", "calculate_monthly_price" => "Calcular e mostrar preço mensal para todas as subscrições",
"convert_prices" => "Converter e mostrar todas as subscrições na moeda principal (mais lento)", "convert_prices" => "Converter e mostrar todas as subscrições na moeda principal (mais lento)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Testar", "test" => "Testar",
"add" => "Adicionar", "add" => "Adicionar",
"save" => "Guardar", "save" => "Guardar",
"reset" => "Repor",
"export_subscriptions" => "Exportar Subscrições", "export_subscriptions" => "Exportar Subscrições",
"export_to_json" => "Exportar para JSON", "export_to_json" => "Exportar para JSON",
// Filters menu // Filters menu

View File

@ -137,6 +137,9 @@ $i18n = [
"get_free_fixer_api_key" => "Obtenha a sua chave API do Fixer gratuitamente", "get_free_fixer_api_key" => "Obtenha a sua chave API do Fixer gratuitamente",
"get_key_alternative" => "Como alternativa, você pode obter uma chave de API grátis em", "get_key_alternative" => "Como alternativa, você pode obter uma chave de API grátis em",
"display_settings" => "Configurações de visualização", "display_settings" => "Configurações de visualização",
"theme_settings" => "Configurações de tema",
"custom_colors" => "Cores personalizadas",
"dark_theme" => "Tema Escuro",
"switch_theme" => "Alternar entre tema Claro / Escuro", "switch_theme" => "Alternar entre tema Claro / Escuro",
"calculate_monthly_price" => "Calcular e exibir o custo mensal para todas as assinaturas", "calculate_monthly_price" => "Calcular e exibir o custo mensal para todas as assinaturas",
"convert_prices" => "Sempre converter e exibir preços na moeda principal (mais lento)", "convert_prices" => "Sempre converter e exibir preços na moeda principal (mais lento)",
@ -159,6 +162,7 @@ $i18n = [
"test" => "Testar", "test" => "Testar",
"add" => "Adicionar", "add" => "Adicionar",
"save" => "Salvar", "save" => "Salvar",
"reset" => "Redefinir",
"export_subscriptions" => "Exportar assinaturas", "export_subscriptions" => "Exportar assinaturas",
"export_to_json" => "Exportar para JSON", "export_to_json" => "Exportar para JSON",
// Filters menu // Filters menu

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Добијте бесплатни Fixer API кључ", "get_free_fixer_api_key" => "Добијте бесплатни Fixer API кључ",
"get_key_alternative" => "Алтернативно, можете добити бесплатни Fixer API кључ са", "get_key_alternative" => "Алтернативно, можете добити бесплатни Fixer API кључ са",
"display_settings" => "Подешавања приказа", "display_settings" => "Подешавања приказа",
"theme_settings" => "Подешавања теме",
"custom_colors" => "Прилагођене боје",
"dark_theme" => "Тамна тема",
"switch_theme" => "Промени светлу / тамну тему", "switch_theme" => "Промени светлу / тамну тему",
"calculate_monthly_price" => "Израчунајте и прикажите месечну цену за све претплате", "calculate_monthly_price" => "Израчунајте и прикажите месечну цену за све претплате",
"convert_prices" => "Увек конвертујте и прикажите цене на мојој главној валути (спорије)", "convert_prices" => "Увек конвертујте и прикажите цене на мојој главној валути (спорије)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Тест", "test" => "Тест",
"add" => "Додај", "add" => "Додај",
"save" => "Сачувај", "save" => "Сачувај",
"reset" => "Ресетуј",
"export_subscriptions" => "Извоз претплата", "export_subscriptions" => "Извоз претплата",
"export_to_json" => "Извоз у JSON формат", "export_to_json" => "Извоз у JSON формат",
// Мени са филтерима // Мени са филтерима

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Pronađite besplatni Fixer API ključ", "get_free_fixer_api_key" => "Pronađite besplatni Fixer API ključ",
"get_key_alternative" => "Alternativno, možete dobiti besplatni Fixer API ključ na", "get_key_alternative" => "Alternativno, možete dobiti besplatni Fixer API ključ na",
"display_settings" => "Podešavanja prikaza", "display_settings" => "Podešavanja prikaza",
"theme_settings" => "Podešavanja teme",
"custom_colors" => "Prilagođene boje",
"dark_theme" => "Tamna tema",
"switch_theme" => "Promeni svetli / tamni temu", "switch_theme" => "Promeni svetli / tamni temu",
"calculate_monthly_price" => "Izračunaj i prikaži mesečnu cenu za sve pretplate", "calculate_monthly_price" => "Izračunaj i prikaži mesečnu cenu za sve pretplate",
"convert_prices" => "Uvek konvertuj i prikaži cene u mojoj glavnoj valuti (sporije)", "convert_prices" => "Uvek konvertuj i prikaži cene u mojoj glavnoj valuti (sporije)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test", "test" => "Test",
"add" => "Dodaj", "add" => "Dodaj",
"save" => "Sačuvaj", "save" => "Sačuvaj",
"reset" => "Resetuj",
"export_subscriptions" => "Izvezi pretplate", "export_subscriptions" => "Izvezi pretplate",
"export_to_json" => "Izvezi u JSON format", "export_to_json" => "Izvezi u JSON format",
// Meni sa filterima // Meni sa filterima

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Ücretsiz Fixer API Anahtarı alın", "get_free_fixer_api_key" => "Ücretsiz Fixer API Anahtarı alın",
"get_key_alternative" => "Alternatif olarak, şu adresten ücretsiz bir fixer api anahtarı edinebilirsiniz", "get_key_alternative" => "Alternatif olarak, şu adresten ücretsiz bir fixer api anahtarı edinebilirsiniz",
"display_settings" => "Görüntüleme Ayarları", "display_settings" => "Görüntüleme Ayarları",
"theme_settings" => "Tema Ayarları",
"custom_colors" => "Özel Renkler",
"dark_theme" => "Koyu Temayı",
"switch_theme" => "ık / Koyu Temayı Değiştir", "switch_theme" => "ık / Koyu Temayı Değiştir",
"calculate_monthly_price" => "Tüm aboneliklerin aylık fiyatını hesaplayın ve gösterin", "calculate_monthly_price" => "Tüm aboneliklerin aylık fiyatını hesaplayın ve gösterin",
"convert_prices" => "Fiyatları her zaman ana para birimimde dönüştürün ve gösterin (daha yavaş)", "convert_prices" => "Fiyatları her zaman ana para birimimde dönüştürün ve gösterin (daha yavaş)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test Et", "test" => "Test Et",
"add" => "Ekle", "add" => "Ekle",
"save" => "Kaydet", "save" => "Kaydet",
"reset" => "Sıfırla",
"export_subscriptions" => "Abonelikleri Dışa Aktar", "export_subscriptions" => "Abonelikleri Dışa Aktar",
"export_to_json" => "JSON'a dışa aktar", "export_to_json" => "JSON'a dışa aktar",
// Filters menu // Filters menu

View File

@ -146,6 +146,9 @@ $i18n = [
"get_free_fixer_api_key" => "申请免费 Fixer API 密钥", "get_free_fixer_api_key" => "申请免费 Fixer API 密钥",
"get_key_alternative" => "或者,您也可以从以下网站获取免费的修复程序 api 密钥", "get_key_alternative" => "或者,您也可以从以下网站获取免费的修复程序 api 密钥",
"display_settings" => "显示设置", "display_settings" => "显示设置",
"theme_settings" => "主题设置",
"custom_colors" => "自定义颜色",
"dark_theme" => "深色主题",
"switch_theme" => "切换浅色/深色主题", "switch_theme" => "切换浅色/深色主题",
"calculate_monthly_price" => "计算并显示所有订阅的月价格", "calculate_monthly_price" => "计算并显示所有订阅的月价格",
"convert_prices" => "始终按我的主要货币转换和显示价格(较慢)", "convert_prices" => "始终按我的主要货币转换和显示价格(较慢)",
@ -168,6 +171,7 @@ $i18n = [
"test" => "测试", "test" => "测试",
"add" => "添加", "add" => "添加",
"save" => "保存", "save" => "保存",
"reset" => "重置",
"export_subscriptions" => "导出订阅", "export_subscriptions" => "导出订阅",
"export_to_json" => "导出为 JSON", "export_to_json" => "导出为 JSON",

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "申請免費的 Fixer API 金鑰", "get_free_fixer_api_key" => "申請免費的 Fixer API 金鑰",
"get_key_alternative" => "或者,您可以從以下網址取得一個免費的修復 api 金鑰", "get_key_alternative" => "或者,您可以從以下網址取得一個免費的修復 api 金鑰",
"display_settings" => "顯示設定", "display_settings" => "顯示設定",
"theme_settings" => "主題設定",
"custom_colors" => "自訂顏色",
"dark_theme" => "深色主題",
"switch_theme" => "切換淺色/深色主題", "switch_theme" => "切換淺色/深色主題",
"calculate_monthly_price" => "計算並顯示所有訂閱的每月價格", "calculate_monthly_price" => "計算並顯示所有訂閱的每月價格",
"convert_prices" => "始終按照我的主要貨幣單位轉換和顯示價格(較慢)", "convert_prices" => "始終按照我的主要貨幣單位轉換和顯示價格(較慢)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "測試", "test" => "測試",
"add" => "新增", "add" => "新增",
"save" => "儲存", "save" => "儲存",
"reset" => "重設",
"export_subscriptions" => "匯出訂閱", "export_subscriptions" => "匯出訂閱",
"export_to_json" => "匯出為 JSON 檔案", "export_to_json" => "匯出為 JSON 檔案",
// Filters menu // Filters menu

View File

@ -56,7 +56,7 @@
} }
} }
function printSubscriptions($subscriptions, $sort, $categories, $members, $i18n) { function printSubscriptions($subscriptions, $sort, $categories, $members, $i18n, $colorTheme) {
if ($sort === "price") { if ($sort === "price") {
usort($subscriptions, function($a, $b) { usort($subscriptions, function($a, $b) {
return $a['price'] < $b['price'] ? 1 : -1; return $a['price'] < $b['price'] ? 1 : -1;
@ -110,14 +110,14 @@
</span> </span>
<span class="actions"> <span class="actions">
<button class="image-button medium" onClick="openEditSubscription(event, <?= $subscription['id'] ?>)" name="edit"> <button class="image-button medium" onClick="openEditSubscription(event, <?= $subscription['id'] ?>)" name="edit">
<img src="images/siteicons/edit.png" title="<?= translate('edit_subscription', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/edit.png" title="<?= translate('edit_subscription', $i18n) ?>">
</button> </button>
</span> </span>
</div> </div>
<div class="subscription-secondary"> <div class="subscription-secondary">
<span class="name"><img src="images/siteicons/subscription.png" alt="<?= translate('subscription', $i18n) ?>" /><?= $subscription['name'] ?></span> <span class="name"><img src="images/siteicons/<?= $colorTheme ?>/subscription.png" alt="<?= translate('subscription', $i18n) ?>" /><?= $subscription['name'] ?></span>
<span class="payer_user" title="<?= translate('paid_by', $i18n) ?>"><img src="images/siteicons/payment.png" alt="<?= translate('paid_by', $i18n) ?>" /><?= $members[$subscription['payer_user_id']]['name'] ?></span> <span class="payer_user" title="<?= translate('paid_by', $i18n) ?>"><img src="images/siteicons/<?= $colorTheme ?>/payment.png" alt="<?= translate('paid_by', $i18n) ?>" /><?= $members[$subscription['payer_user_id']]['name'] ?></span>
<span class="category" title="<?= translate('category', $i18n) ?>" ><img src="images/siteicons/category.png" alt="<?= translate('category', $i18n) ?>" /><?= $categories[$subscription['category_id']]['name'] ?></span> <span class="category" title="<?= translate('category', $i18n) ?>" ><img src="images/siteicons/<?= $colorTheme ?>/category.png" alt="<?= translate('category', $i18n) ?>" /><?= $categories[$subscription['category_id']]['name'] ?></span>
<?php <?php
if ($subscription['url'] != "") { if ($subscription['url'] != "") {
$url = $subscription['url']; $url = $subscription['url'];
@ -125,7 +125,7 @@
$url = "https://" . $url; $url = "https://" . $url;
} }
?> ?>
<span class="url" title="<?= translate('external_url', $i18n) ?>"><a href="<?= $url ?>" target="_blank"><img src="images/siteicons/web.png" alt="<?= translate('url', $i18n) ?>" /></a></span> <span class="url" title="<?= translate('external_url', $i18n) ?>"><a href="<?= $url ?>" target="_blank"><img src="images/siteicons/<?= $colorTheme ?>/web.png" alt="<?= translate('url', $i18n) ?>" /></a></span>
<?php <?php
} }
?> ?>
@ -135,7 +135,7 @@
?> ?>
<div class="subscription-notes"> <div class="subscription-notes">
<span class="notes"> <span class="notes">
<img src="images/siteicons/notes.png" alt="<?= translate('notes', $i18n) ?>" /> <img src="images/siteicons/<?= $colorTheme ?>/notes.png" alt="<?= translate('notes', $i18n) ?>" />
<?= $subscription['notes'] ?> <?= $subscription['notes'] ?>
</span> </span>
</div> </div>

View File

@ -1,3 +1,3 @@
<?php <?php
$version = "v1.20.2"; $version = "v1.21.0";
?> ?>

View File

@ -37,7 +37,7 @@
} }
$headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden"; $headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden";
$defaultLogo = $theme == "light" ? "images/wallos.png" : "images/walloswhite.png"; $defaultLogo = $theme == "light" ? "images/siteicons/" . $colorTheme . "/wallos.png" : "images/siteicons/" . $colorTheme . "/walloswhite.png";
?> ?>
<style> <style>
.logo-preview:after { .logo-preview:after {
@ -188,7 +188,7 @@
} }
if (isset($print)) { if (isset($print)) {
printSubscriptions($print, $sort, $categories, $members, $i18n); printSubscriptions($print, $sort, $categories, $members, $i18n, $colorTheme);
} }
$db->close(); $db->close();
@ -224,7 +224,7 @@
<input type="file" id="logo" name="logo" accept="image/jpeg, image/png, image/gif, image/webp" onchange="handleFileSelect(event)" class="hidden-input"> <input type="file" id="logo" name="logo" accept="image/jpeg, image/png, image/gif, image/webp" onchange="handleFileSelect(event)" class="hidden-input">
<input type="hidden" id="logo-url" name="logo-url"> <input type="hidden" id="logo-url" name="logo-url">
<div id="logo-search-button" class="image-button medium disabled" title="<?= translate('search_logo', $i18n) ?>" onClick="searchLogo()"> <div id="logo-search-button" class="image-button medium disabled" title="<?= translate('search_logo', $i18n) ?>" onClick="searchLogo()">
<img src="images/siteicons/websearch.png"> <img src="images/siteicons/<?= $colorTheme ?>/websearch.png">
</div> </div>
<input type="hidden" id="id" name="id"> <input type="hidden" id="id" name="id">
<div id="logo-search-results" class="logo-search"> <div id="logo-search-results" class="logo-search">

View File

@ -25,6 +25,11 @@ if (isset($_COOKIE['theme'])) {
$theme = $_COOKIE['theme']; $theme = $_COOKIE['theme'];
} }
$colorTheme = "blue";
if (isset($_COOKIE['colorTheme'])) {
$colorTheme = $_COOKIE['colorTheme'];
}
$loginFailed = false; $loginFailed = false;
if (isset($_POST['username']) && isset($_POST['password'])) { if (isset($_POST['username']) && isset($_POST['password'])) {
$username = $_POST['username']; $username = $_POST['username'];
@ -80,7 +85,11 @@ if (isset($_POST['username']) && isset($_POST['password'])) {
<link rel="icon" type="image/png" href="images/icon/favicon.ico" sizes="16x16"> <link rel="icon" type="image/png" href="images/icon/favicon.ico" sizes="16x16">
<link rel="apple-touch-icon" sizes="180x180" href="images/icon/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="images/icon/apple-touch-icon.png">
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="styles/theme.css?<?= $version ?>">
<link rel="stylesheet" href="styles/login.css?<?= $version ?>"> <link rel="stylesheet" href="styles/login.css?<?= $version ?>">
<link rel="stylesheet" href="styles/themes/red.css?<?= $version ?>" id="red-theme" <?= $colorTheme != "red" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/themes/green.css?<?= $version ?>" id="green-theme" <?= $colorTheme != "green" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/themes/yellow.css?<?= $version ?>" id="yellow-theme" <?= $colorTheme != "yellow" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/barlow.css"> <link rel="stylesheet" href="styles/barlow.css">
<link rel="stylesheet" href="styles/login-dark-theme.css?<?= $version ?>" id="dark-theme" <?= $theme == "light" ? "disabled" : "" ?>> <link rel="stylesheet" href="styles/login-dark-theme.css?<?= $version ?>" id="dark-theme" <?= $theme == "light" ? "disabled" : "" ?>>
</head> </head>
@ -90,9 +99,9 @@ if (isset($_POST['username']) && isset($_POST['password'])) {
<header> <header>
<?php <?php
if ($theme == "light") { if ($theme == "light") {
?> <img src="images/wallossolid.png" alt="Wallos Logo" title="Wallos - Subscription Tracker" /> <?php ?> <img src="images/siteicons/<?= $colorTheme ?>/wallos.png" alt="Wallos Logo" title="Wallos - Subscription Tracker" width="215" /> <?php
} else { } else {
?> <img src="images/wallossolidwhite.png" alt="Wallos Logo" title="Wallos - Subscription Tracker" /> <?php ?> <img src="images/siteicons/<?= $colorTheme ?>/walloswhite.png" alt="Wallos Logo" title="Wallos - Subscription Tracker" width="215" /> <?php
} }
?> ?>
<p> <p>

25
migrations/000014.php Normal file
View File

@ -0,0 +1,25 @@
<?php
// This migration adds a "color_theme" column to the settings table and sets it to blue as default.
/** @noinspection PhpUndefinedVariableInspection */
$columnQuery = $db->query("SELECT * FROM pragma_table_info('settings') where name='color_theme'");
$columnRequired = $columnQuery->fetchArray(SQLITE3_ASSOC) === false;
if ($columnRequired) {
$db->exec("ALTER TABLE settings ADD COLUMN color_theme TEXT DEFAULT 'blue'");
$db->exec('UPDATE settings SET `color_theme` = "blue"');
}
// This migrations adds custom_colors table to the database, so the user can set custom accent colors to the application
$customColorsTableQuery = $db->query("SELECT * FROM sqlite_master WHERE type='table' AND name='custom_colors'");
$customColorsTableRequired = $customColorsTableQuery->fetchArray(SQLITE3_ASSOC) === false;
if ($customColorsTableRequired) {
$db->exec("CREATE TABLE custom_colors (
main_color TEXT NOT NULL,
accent_color TEXT NOT NULL,
hover_color TEXT NOT NULL
)");
}

View File

@ -95,6 +95,7 @@ if (isset($_POST['username'])) {
<link rel="icon" type="image/png" href="images/icon/favicon.ico" sizes="16x16"> <link rel="icon" type="image/png" href="images/icon/favicon.ico" sizes="16x16">
<link rel="apple-touch-icon" sizes="180x180" href="images/icon/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="images/icon/apple-touch-icon.png">
<link rel="manifest" href="manifes.json"> <link rel="manifest" href="manifes.json">
<link rel="stylesheet" href="styles/theme.css?<?= $version ?>">
<link rel="stylesheet" href="styles/login.css?<?= $version ?>"> <link rel="stylesheet" href="styles/login.css?<?= $version ?>">
<link rel="stylesheet" href="styles/login-dark-theme.css?<?= $version ?>" id="dark-theme" <?= $theme == "light" ? "disabled" : "" ?>> <link rel="stylesheet" href="styles/login-dark-theme.css?<?= $version ?>" id="dark-theme" <?= $theme == "light" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/barlow.css"> <link rel="stylesheet" href="styles/barlow.css">
@ -106,9 +107,9 @@ if (isset($_POST['username'])) {
<header> <header>
<?php <?php
if ($theme == "light") { if ($theme == "light") {
?> <img src="images/wallossolid.png" alt="Wallos Logo" title="Wallos - Subscription Tracker" /> <?php ?> <img src="images/siteicons/blue/wallos.png" alt="Wallos Logo" title="Wallos - Subscription Tracker" /> <?php
} else { } else {
?> <img src="images/wallossolidwhite.png" alt="Wallos Logo" title="Wallos - Subscription Tracker" /> <?php ?> <img src="images/siteicons/blue/walloswhite.png" alt="Wallos Logo" title="Wallos - Subscription Tracker" /> <?php
} }
?> ?>
<p> <p>

View File

@ -37,7 +37,7 @@ function fillEditFormFields(subscription) {
const formTitle = document.querySelector("#form-title"); const formTitle = document.querySelector("#form-title");
formTitle.textContent = translate('edit_subscription'); formTitle.textContent = translate('edit_subscription');
const logo = document.querySelector("#form-logo"); const logo = document.querySelector("#form-logo");
const defaultLogo = window.theme && window.theme == "light" ? "images/wallos.png" : "images/walloswhite.png"; const defaultLogo = window.theme && window.theme == "light" ? "images/siteicons/" + colorTheme + "/wallos.png" : "images/siteicons/" + colorTheme + "/walloswhite.png";
const logoFile = subscription.logo !== null ? "images/uploads/logos/" + subscription.logo : defaultLogo; const logoFile = subscription.logo !== null ? "images/uploads/logos/" + subscription.logo : defaultLogo;
logo.src = logoFile; logo.src = logoFile;
logo.style = 'display: block'; logo.style = 'display: block';

View File

@ -108,7 +108,7 @@ function addMemberButton(memberId) {
}; };
let editImage = document.createElement("img"); let editImage = document.createElement("img");
editImage.src = "images/siteicons/save.png"; editImage.src = "images/siteicons/" + colorTheme + "/save.png";
editImage.title = translate('save_member'); editImage.title = translate('save_member');
editLink.appendChild(editImage); editLink.appendChild(editImage);
@ -121,7 +121,7 @@ function addMemberButton(memberId) {
}; };
let deleteImage = document.createElement("img"); let deleteImage = document.createElement("img");
deleteImage.src = "images/siteicons/delete.png"; deleteImage.src = "images/siteicons/" + colorTheme + "/delete.png";
deleteImage.title = translate('delete_member'); deleteImage.title = translate('delete_member');
deleteLink.appendChild(deleteImage); deleteLink.appendChild(deleteImage);
@ -237,7 +237,7 @@ function addCategoryButton(categoryId) {
}; };
let editImage = document.createElement("img"); let editImage = document.createElement("img");
editImage.src = "images/siteicons/save.png"; editImage.src = "images/siteicons/" + colorTheme + "/save.png";
editImage.title = translate('save_category'); editImage.title = translate('save_category');
editLink.appendChild(editImage); editLink.appendChild(editImage);
@ -250,7 +250,7 @@ function addCategoryButton(categoryId) {
}; };
let deleteImage = document.createElement("img"); let deleteImage = document.createElement("img");
deleteImage.src = "images/siteicons/delete.png"; deleteImage.src = "images/siteicons/" + colorTheme + "/delete.png";
deleteImage.title = translate('delete_category'); deleteImage.title = translate('delete_category');
deleteLink.appendChild(deleteImage); deleteLink.appendChild(deleteImage);
@ -375,7 +375,7 @@ function addCurrencyButton(currencyId) {
}; };
let editImage = document.createElement("img"); let editImage = document.createElement("img");
editImage.src = "images/siteicons/save.png"; editImage.src = "images/siteicons/" + colorTheme + "/save.png";
editImage.title = translate('save_currency'); editImage.title = translate('save_currency');
editLink.appendChild(editImage); editLink.appendChild(editImage);
@ -388,7 +388,7 @@ function addCurrencyButton(currencyId) {
}; };
let deleteImage = document.createElement("img"); let deleteImage = document.createElement("img");
deleteImage.src = "images/siteicons/delete.png"; deleteImage.src = "images/siteicons/" + colorTheme + "/delete.png";
deleteImage.title = translate('delete_currency'); deleteImage.title = translate('delete_currency');
deleteLink.appendChild(deleteImage); deleteLink.appendChild(deleteImage);
@ -937,6 +937,8 @@ function switchTheme() {
const themeChoice = darkThemeCss.disabled ? 'light' : 'dark'; const themeChoice = darkThemeCss.disabled ? 'light' : 'dark';
document.cookie = `theme=${themeChoice}; expires=Fri, 31 Dec 9999 23:59:59 GMT`; document.cookie = `theme=${themeChoice}; expires=Fri, 31 Dec 9999 23:59:59 GMT`;
document.body.className = themeChoice;
const button = document.getElementById("switchTheme"); const button = document.getElementById("switchTheme");
button.disabled = true; button.disabled = true;
@ -1040,3 +1042,115 @@ var sortable = Sortable.create(el, {
saveCategorySorting(); saveCategorySorting();
}, },
}); });
function setTheme(themeColor) {
var currentTheme = 'blue';
var themeIds = ['red-theme', 'green-theme', 'yellow-theme'];
themeIds.forEach(function(id) {
var themeStylesheet = document.getElementById(id);
if (themeStylesheet && !themeStylesheet.disabled) {
currentTheme = id.replace('-theme', '');
themeStylesheet.disabled = true;
}
});
if (themeColor !== "blue") {
var enableTheme = document.getElementById(themeColor + '-theme');
enableTheme.disabled = false;
}
var images = document.querySelectorAll('img');
images.forEach(function(img) {
if (img.src.includes('siteicons/' + currentTheme)) {
img.src = img.src.replace(currentTheme, themeColor);
}
});
var labels = document.querySelectorAll('.theme-preview');
labels.forEach(function(label) {
label.classList.remove('is-selected');
});
var targetLabel = document.querySelector(`.theme-preview.${themeColor}`);
if (targetLabel) {
targetLabel.classList.add('is-selected');
}
document.cookie = `colorTheme=${themeColor}; expires=Fri, 31 Dec 9999 23:59:59 GMT`;
fetch('endpoints/settings/colortheme.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ color: themeColor })
})
.then(response => response.json())
.then(data => {
if (data.success) {
showSuccessMessage(data.message);
} else {
showErrorMessage(data.message);
}
})
.catch(error => {
showErrorMessage(translate('unknown_error'));
});
}
function resetCustomColors() {
fetch('endpoints/settings/resettheme.php', {
method: 'DELETE',
})
.then(response => response.json())
.then(data => {
if (data.success) {
showSuccessMessage(data.message);
const custom_theme_colors = document.getElementById('custom_theme_colors');
custom_theme_colors.remove();
document.documentElement.style.removeProperty('--main-color');
document.documentElement.style.removeProperty('--accent-color');
document.documentElement.style.removeProperty('--hover-color');
document.getElementById("mainColor").value = "#FFFFFF";
document.getElementById("accentColor").value = "#FFFFFF";
document.getElementById("hoverColor").value = "#FFFFFF";
} else {
showErrorMessage(data.message);
}
})
.catch(error => {
showErrorMessage(translate('unknown_error'));
});
}
function saveCustomColors() {
const mainColor = document.getElementById("mainColor").value;
const accentColor = document.getElementById("accentColor").value;
const hoverColor = document.getElementById("hoverColor").value;
fetch('endpoints/settings/customtheme.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ mainColor: mainColor, accentColor: accentColor, hoverColor: hoverColor })
})
.then(response => response.json())
.then(data => {
if (data.success) {
showSuccessMessage(data.message);
document.documentElement.style.setProperty('--main-color', mainColor);
document.documentElement.style.setProperty('--accent-color', accentColor);
document.documentElement.style.setProperty('--hover-color', hoverColor);
} else {
showErrorMessage(data.message);
}
})
.catch(error => {
showErrorMessage(translate('unknown_error'));
});
}

View File

@ -14,6 +14,9 @@ self.addEventListener('install', function(event) {
'styles/login.css', 'styles/login.css',
'styles/font-awesome.min.css', 'styles/font-awesome.min.css',
'styles/barlow.css', 'styles/barlow.css',
'styles/themes/red.css',
'styles/themes/green.css',
'styles/themes/yellow.css',
'webfonts/fa-solid-900.woff2', 'webfonts/fa-solid-900.woff2',
'webfonts/fa-solid-900.ttf', 'webfonts/fa-solid-900.ttf',
'scripts/common.js', 'scripts/common.js',
@ -21,16 +24,16 @@ self.addEventListener('install', function(event) {
'scripts/stats.js', 'scripts/stats.js',
'scripts/settings.js', 'scripts/settings.js',
'scripts/registration.js', 'scripts/registration.js',
'scripts/i18n/en.js',
'scripts/i18n/de.js', 'scripts/i18n/de.js',
'scripts/i18n/el.js', 'scripts/i18n/el.js',
'scripts/i18n/en.js',
'scripts/i18n/es.js', 'scripts/i18n/es.js',
'scripts/i18n/fr.js', 'scripts/i18n/fr.js',
'scripts/i18n/it.js', 'scripts/i18n/it.js',
'scripts/i18n/jp.js', 'scripts/i18n/jp.js',
'scripts/i18n/pl.js', 'scripts/i18n/pl.js',
'scripts/i18n/pt_br.js',
'scripts/i18n/pt.js', 'scripts/i18n/pt.js',
'scripts/i18n/pt_br.js',
'scripts/i18n/tr.js', 'scripts/i18n/tr.js',
'scripts/i18n/zh_cn.js', 'scripts/i18n/zh_cn.js',
'scripts/i18n/zh_tw.js', 'scripts/i18n/zh_tw.js',
@ -40,8 +43,14 @@ self.addEventListener('install', function(event) {
'images/icon/favicon.ico', 'images/icon/favicon.ico',
'images/icon/android-chrome-192x192.png', 'images/icon/android-chrome-192x192.png',
'images/screenshots/desktop.png', 'images/screenshots/desktop.png',
'images/wallossolid.png', 'images/siteicons/blue/wallos.png',
'images/wallossolidwhite.png', 'images/siteicons/blue/walloswhite.png',
'images/siteicons/green/wallos.png',
'images/siteicons/green/walloswhite.png',
'images/siteicons/red/wallos.png',
'images/siteicons/red/walloswhite.png',
'images/siteicons/yellow/wallos.png',
'images/siteicons/yellow/walloswhite.png',
'images/siteimages/empty.png', 'images/siteimages/empty.png',
'images/avatars/1.svg', 'images/avatars/1.svg',
'images/avatars/2.svg', 'images/avatars/2.svg',
@ -52,19 +61,46 @@ self.addEventListener('install', function(event) {
'images/avatars/7.svg', 'images/avatars/7.svg',
'images/avatars/8.svg', 'images/avatars/8.svg',
'images/avatars/9.svg', 'images/avatars/9.svg',
'images/siteicons/edit.png', 'images/siteicons/blue/category.png',
'images/siteicons/websearch.png', 'images/siteicons/blue/check.png',
'images/siteicons/save.png', 'images/siteicons/blue/delete.png',
'images/siteicons/delete.png', 'images/siteicons/blue/edit.png',
'images/siteicons/category.png', 'images/siteicons/blue/notes.png',
'images/siteicons/check.png', 'images/siteicons/blue/payment.png',
'images/siteicons/editavatar.png', 'images/siteicons/blue/save.png',
'images/siteicons/notes.png', 'images/siteicons/blue/subscription.png',
'images/siteicons/payment.png', 'images/siteicons/blue/web.png',
'images/siteicons/plusicon.png', 'images/siteicons/blue/websearch.png',
'images/siteicons/sort.png', 'images/siteicons/red/category.png',
'images/siteicons/subscription.png', 'images/siteicons/red/check.png',
'images/siteicons/web.png', 'images/siteicons/red/delete.png',
'images/siteicons/red/edit.png',
'images/siteicons/red/notes.png',
'images/siteicons/red/payment.png',
'images/siteicons/red/save.png',
'images/siteicons/red/subscription.png',
'images/siteicons/red/web.png',
'images/siteicons/red/websearch.png',
'images/siteicons/green/category.png',
'images/siteicons/green/check.png',
'images/siteicons/green/delete.png',
'images/siteicons/green/edit.png',
'images/siteicons/green/notes.png',
'images/siteicons/green/payment.png',
'images/siteicons/green/save.png',
'images/siteicons/green/subscription.png',
'images/siteicons/green/web.png',
'images/siteicons/green/websearch.png',
'images/siteicons/yellow/category.png',
'images/siteicons/yellow/check.png',
'images/siteicons/yellow/delete.png',
'images/siteicons/yellow/edit.png',
'images/siteicons/yellow/notes.png',
'images/siteicons/yellow/payment.png',
'images/siteicons/yellow/save.png',
'images/siteicons/yellow/subscription.png',
'images/siteicons/yellow/web.png',
'images/siteicons/yellow/websearch.png',
'images/siteicons/pwa/stats.png', 'images/siteicons/pwa/stats.png',
'images/siteicons/pwa/settings.png', 'images/siteicons/pwa/settings.png',
'images/siteicons/pwa/about.png', 'images/siteicons/pwa/about.png',

View File

@ -142,19 +142,19 @@
} }
?> ?>
<button class="image-button medium" onClick="editMember(<?= $member['id'] ?>)" name="save"> <button class="image-button medium" onClick="editMember(<?= $member['id'] ?>)" name="save">
<img src="images/siteicons/save.png" title="<?= translate('save_member', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/save.png" title="<?= translate('save_member', $i18n) ?>">
</button> </button>
<?php <?php
if ($member['id'] != 1) { if ($member['id'] != 1) {
?> ?>
<button class="image-button medium" onClick="removeMember(<?= $member['id'] ?>)"> <button class="image-button medium" onClick="removeMember(<?= $member['id'] ?>)">
<img src="images/siteicons/delete.png" title="<?= translate('delete_member', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/delete.png" title="<?= translate('delete_member', $i18n) ?>">
</button> </button>
<?php <?php
} else { } else {
?> ?>
<button class="image-button medium disabled"> <button class="image-button medium disabled">
<img src="images/siteicons/delete.png" title="<?= translate('cant_delete_member', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/delete.png" title="<?= translate('cant_delete_member', $i18n) ?>">
</button> </button>
<?php <?php
} }
@ -292,19 +292,19 @@
<div class="drag-icon"></div> <div class="drag-icon"></div>
<input type="text" name="category" value="<?= $category['name'] ?>" placeholder="Category"> <input type="text" name="category" value="<?= $category['name'] ?>" placeholder="Category">
<button class="image-button medium" onClick="editCategory(<?= $category['id'] ?>)" name="save"> <button class="image-button medium" onClick="editCategory(<?= $category['id'] ?>)" name="save">
<img src="images/siteicons/save.png" title="<?= translate('save_category', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/save.png" title="<?= translate('save_category', $i18n) ?>">
</button> </button>
<?php <?php
if ($canDelete) { if ($canDelete) {
?> ?>
<button class="image-button medium" onClick="removeCategory(<?= $category['id'] ?>)"> <button class="image-button medium" onClick="removeCategory(<?= $category['id'] ?>)">
<img src="images/siteicons/delete.png" title="<?= translate('delete_category', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/delete.png" title="<?= translate('delete_category', $i18n) ?>">
</button> </button>
<?php <?php
} else { } else {
?> ?>
<button class="image-button medium disabled"> <button class="image-button medium disabled">
<img src="images/siteicons/delete.png" title="<?= translate('cant_delete_category_in_use', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/delete.png" title="<?= translate('cant_delete_category_in_use', $i18n) ?>">
</button> </button>
<?php <?php
} }
@ -375,20 +375,20 @@
<input type="text" name="currency" value="<?= $currency['name'] ?>" placeholder="Currency Name"> <input type="text" name="currency" value="<?= $currency['name'] ?>" placeholder="Currency Name">
<input type="text" name="code" value="<?= $currency['code'] ?>" placeholder="Currency Code" <?= !$canDelete ? 'disabled' : '' ?>> <input type="text" name="code" value="<?= $currency['code'] ?>" placeholder="Currency Code" <?= !$canDelete ? 'disabled' : '' ?>>
<button class="image-button medium" onClick="editCurrency(<?= $currency['id'] ?>)" name="save"> <button class="image-button medium" onClick="editCurrency(<?= $currency['id'] ?>)" name="save">
<img src="images/siteicons/save.png" title="<?= translate('save_currency', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/save.png" title="<?= translate('save_currency', $i18n) ?>">
</button> </button>
<?php <?php
if ($canDelete) { if ($canDelete) {
?> ?>
<button class="image-button medium" onClick="removeCurrency(<?= $currency['id'] ?>)"> <button class="image-button medium" onClick="removeCurrency(<?= $currency['id'] ?>)">
<img src="images/siteicons/delete.png" title="<?= translate('delete_currency', $i18n) ?>"> <img src="images/siteicons/<?= $colorTheme ?>/delete.png" title="<?= translate('delete_currency', $i18n) ?>">
</button> </button>
<?php <?php
} else { } else {
$cantDeleteMessage = $isMainCurrency ? translate('cant_delete_main_currency', $i18n) : translate('cant_delete_currency_in_use', $i18n); $cantDeleteMessage = $isMainCurrency ? translate('cant_delete_main_currency', $i18n) : translate('cant_delete_currency_in_use', $i18n);
?> ?>
<button class="image-button medium disabled"> <button class="image-button medium disabled">
<img src="images/siteicons/delete.png" title="<?= $cantDeleteMessage ?>"> <img src="images/siteicons/<?= $colorTheme ?>/delete.png" title="<?= $cantDeleteMessage ?>">
</button> </button>
<?php <?php
} }
@ -555,7 +555,7 @@
<input type="file" id="paymenticon" name="paymenticon" accept="image/jpeg, image/png, image/gif, image/webp" onchange="handleFileSelect(event)" class="hidden-input"> <input type="file" id="paymenticon" name="paymenticon" accept="image/jpeg, image/png, image/gif, image/webp" onchange="handleFileSelect(event)" class="hidden-input">
<input type="hidden" id="icon-url" name="icon-url"> <input type="hidden" id="icon-url" name="icon-url">
<div id="icon-search-button" class="image-button medium disabled" title="<?= translate('search_logo', $i18n) ?>" onClick="searchPaymentIcon()"> <div id="icon-search-button" class="image-button medium disabled" title="<?= translate('search_logo', $i18n) ?>" onClick="searchPaymentIcon()">
<img src="images/siteicons/websearch.png"> <img src="images/siteicons/<?= $colorTheme ?>/websearch.png">
</div> </div>
<div id="icon-search-results" class="icon-search"> <div id="icon-search-results" class="icon-search">
<header> <header>
@ -571,14 +571,73 @@
</div> </div>
</section> </section>
<section class="account-section">
<header>
<h2><?= translate('theme_settings', $i18n) ?></h2>
</header>
<div class="account-settings-theme">
<div>
<div class="theme-selector">
<div class="theme">
<label for="theme-blue" class="theme-preview blue <?= $settings['color_theme'] == 'blue' ? 'is-selected' : '' ?>">
<input type="radio" name="theme" id="theme-blue" value="blue" onClick="setTheme('blue')" <?= $settings['color_theme'] == 'blue' ? 'checked' : '' ?>>
<span class="main-color"></span>
<span class="accent-color"></span>
<span class="hover-color"></span>
</label>
</div>
<div class="theme">
<label for="theme-green" class="theme-preview green <?= $settings['color_theme'] == 'green' ? 'is-selected' : '' ?>">
<input type="radio" name="theme" id="theme-green" value="green" onClick="setTheme('green')" <?= $settings['color_theme'] == 'green' ? 'checked' : '' ?>>
<span class="main-color"></span>
<span class="accent-color"></span>
<span class="hover-color"></span>
</label>
</div>
<div class="theme">
<label for="theme-red" class="theme-preview red <?= $settings['color_theme'] == 'red' ? 'is-selected' : '' ?>">
<input type="radio" name="theme" id="theme-red" value="red" onClick="setTheme('red')" <?= $settings['color_theme'] == 'red' ? 'checked' : '' ?>>
<span class="main-color"></span>
<span class="accent-color"></span>
<span class="hover-color"></span>
</label>
</div>
<div class="theme">
<label for="theme-yellow" class="theme-preview yellow <?= $settings['color_theme'] == 'yellow' ? 'is-selected' : '' ?>">
<input type="radio" name="theme" id="theme-yellow" value="yellow" onClick="setTheme('yellow')" <?= $settings['color_theme'] == 'yellow' ? 'checked' : '' ?>>
<span class="main-color"></span>
<span class="accent-color"></span>
<span class="hover-color"></span>
</label>
</div>
</div>
</div>
<div>
<h2><?= translate('custom_colors', $i18n) ?></h2>
<div class="form-group-inline wrap">
<div class="color-picker-wrapper wrap">
<input type="color" id="mainColor" name="mainColor" value="<?= isset($settings['customColors']['main_color']) ? $settings['customColors']['main_color'] : '#FFFFFF' ?>" class="color-picker fa-solid fa-eye-dropper">
<input type="color" id="accentColor" name="accentColor" value="<?= isset($settings['customColors']['accent_color']) ? $settings['customColors']['accent_color'] : '#FFFFFF' ?>" class="color-picker fa-solid fa-eye-dropper">
<input type="color" id="hoverColor" name="hoverColor" value="<?= isset($settings['customColors']['hover_color']) ? $settings['customColors']['hover_color'] : '#FFFFFF' ?>" class="color-picker fa-solid fa-eye-dropper">
</div>
<div class="color-picker-wrapper wrap">
<input type="button" value="<?= translate('reset', $i18n) ?>" onClick="resetCustomColors()" class="secondary-button">
<input type="button" value="<?= translate('save', $i18n) ?>" onClick="saveCustomColors()" class="buton">
</div>
</div>
</div>
<h2><?= translate('dark_theme', $i18n) ?></h2>
<div>
<input id="switchTheme" type="button" value="<?= translate('switch_theme', $i18n) ?>" onClick="switchTheme()" class="button">
</div>
</div>
</section>
<section class="account-section"> <section class="account-section">
<header> <header>
<h2><?= translate('display_settings', $i18n) ?></h2> <h2><?= translate('display_settings', $i18n) ?></h2>
</header> </header>
<div class="account-settings-list"> <div class="account-settings-list">
<div>
<input id="switchTheme" type="button" value="<?= translate('switch_theme', $i18n) ?>" onClick="switchTheme()">
</div>
<div> <div>
<div class="form-group-inline"> <div class="form-group-inline">
<input type="checkbox" id="monthlyprice" name="monthlyprice" onChange="setShowMonthlyPrice()" <?php if ($settings['monthly_price']) echo 'checked'; ?>> <input type="checkbox" id="monthlyprice" name="monthlyprice" onChange="setShowMonthlyPrice()" <?php if ($settings['monthly_price']) echo 'checked'; ?>>

View File

@ -8,7 +8,7 @@ body > header {
} }
header .logo .logo-image { header .logo .logo-image {
background-image: url("../images/wallossolidwhite.png"); background-image: url("../images/siteicons/blue/walloswhite.png");
} }
.split-header > h2 .header-subtitle { .split-header > h2 .header-subtitle {
@ -96,6 +96,10 @@ input[type="button"].secondary-button:hover {
background-color: #111; background-color: #111;
} }
input[type="color"] {
background-color: #F2F2F2;
}
.avatar-select .avatar-list .remove-avatar { .avatar-select .avatar-list .remove-avatar {
background-color: #222; background-color: #222;
} }
@ -133,7 +137,7 @@ input[type="button"].secondary-button:hover {
} }
.logo-preview:after { .logo-preview:after {
color: #007bff; color: var(--main-color);
} }
.sort-options > ul > li { .sort-options > ul > li {

View File

@ -94,7 +94,7 @@ input[type="submit"] {
width: 100%; width: 100%;
padding: 15px; padding: 15px;
font-size: 16px; font-size: 16px;
background-color: #007bff; background-color: var(--main-color);
color: #fff; color: #fff;
border: none; border: none;
border-radius: 8px; border-radius: 8px;
@ -102,7 +102,7 @@ input[type="submit"] {
} }
input[type="submit"]:hover { input[type="submit"]:hover {
background-color: #0056b3; background-color: var(--hover-color);
} }
input[type="checkbox"] { input[type="checkbox"] {
@ -120,6 +120,6 @@ input[type="checkbox"] {
.error { .error {
display: block; display: block;
color: red; color: var(--error-color);
margin-bottom: 20px; margin-bottom: 20px;
} }

View File

@ -52,7 +52,7 @@ h2, h3 {
} }
body > header { body > header {
border-bottom: 7px solid #007bff; border-bottom: 7px solid var(--main-color);
background-color: white; background-color: white;
} }
@ -67,7 +67,7 @@ header .logo .logo-image {
height: 50px; height: 50px;
width: 134px; width: 134px;
margin-right: 10px; margin-right: 10px;
background-image: url("../images/wallossolid.png"); background-image: url("../images/siteicons/blue/wallos.png");
background-size: 100%; background-size: 100%;
} }
@ -193,8 +193,8 @@ main > .contain {
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
color: #fff; color: #fff;
border: 1px solid #007bff; border: 1px solid var(--main-color);
background-color: #007bff; background-color: var(--main-color);
padding: 15px 30px; padding: 15px 30px;
font-size: 1rem; font-size: 1rem;
border-radius: 8px; border-radius: 8px;
@ -203,8 +203,8 @@ main > .contain {
} }
.button:hover { .button:hover {
background-color: #0056b3; background-color: var(--hover-color);
border-color: #0056b3; border-color: var(--hover-color);
} }
.button.thin { .button.thin {
@ -229,7 +229,7 @@ main > .contain {
margin-top: -35px; margin-top: -35px;
position: relative; position: relative;
z-index: 2; z-index: 2;
color: #007bff; color: var(--main-color);
font-size: 20px; font-size: 20px;
} }
@ -603,17 +603,17 @@ header #avatar {
justify-content: center; justify-content: center;
width: 60px; width: 60px;
height: 60px; height: 60px;
border: 1px solid #007bff; border: 1px solid var(--main-color);
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
margin: 0px; margin: 0px;
box-sizing: border-box; box-sizing: border-box;
color: #007bff; color: var(--main-color);
} }
.avatar-select label.add-avatar:hover { .avatar-select label.add-avatar:hover {
border-color: #8FBFFA; border-color: var(--accent-color);
color: #8FBFFA; color: var(--accent-color);
} }
.avatar-select .avatar-list .remove-avatar { .avatar-select .avatar-list .remove-avatar {
@ -667,7 +667,7 @@ header #avatar {
} }
.image-button > i { .image-button > i {
color: #0056b3; color: var(--hover-color);
font-size: 28px; font-size: 28px;
padding: 2px; padding: 2px;
} }
@ -709,7 +709,7 @@ header #avatar {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
background-color: #8FBFFA; background-color: var(--accent-color);
padding: 6px 12px; padding: 6px 12px;
border-radius: 8px; border-radius: 8px;
transition: filter 300ms; transition: filter 300ms;
@ -766,17 +766,17 @@ header #avatar {
.settings-notes > p > span > a { .settings-notes > p > span > a {
margin-left: 5px; margin-left: 5px;
font-size: 13px; font-size: 13px;
color: #8FBFFA; color: var(--accent-color);
} }
.credits-list > p > span > a:visited, .credits-list > p > span > a:visited,
.settings-notes > p > span > a:visited { .settings-notes > p > span > a:visited {
color: #8FBFFA; color: var(--accent-color);
} }
.settings-notes > p > i, .settings-notes > p > i,
.account-section .notes > p > i { .account-section .notes > p > i {
color: #007bff; color: var(--main-color);
margin-right: 5px; margin-right: 5px;
} }
@ -844,6 +844,19 @@ select {
box-sizing: border-box; box-sizing: border-box;
} }
input[type="color"] {
height: 46px;
width: 46px;
background-color: #222;
border: 1px solid var(--hover-color);
outline: none;
box-sizing: border-box;
cursor: pointer;
font-size: 16px;
position: relative;
border-radius: 5px;
}
.one-third { .one-third {
max-width: 33%; max-width: 33%;
} }
@ -874,26 +887,26 @@ input[type="button"],
button.button { button.button {
padding: 12px 30px; padding: 12px 30px;
font-size: 16px; font-size: 16px;
background-color: #007bff; background-color: var(--main-color);
color: #fff; color: #fff;
border: none; border: none;
border-radius: 8px; border-radius: 8px;
cursor: pointer; cursor: pointer;
box-sizing: border-box; box-sizing: border-box;
border: 2px solid #007bff; border: 2px solid var(--main-color);
} }
input[type="button"].secondary-button, input[type="button"].secondary-button,
button.button.secondary-button { button.button.secondary-button {
background-color: #FFFFFF; background-color: #FFFFFF;
color: #007bff; color: var(--main-color);
} }
input[type="button"].secondary-button:hover, input[type="button"].secondary-button:hover,
button.button.secondary-button:hover { button.button.secondary-button:hover {
background-color: #EEEEEE; background-color: #EEEEEE;
color: #0056b3; color: var(--hover-color);
border-color: #0056b3; border-color: var(--hover-color);
} }
input[type="button"].warning-button { input[type="button"].warning-button {
@ -907,8 +920,8 @@ input[type="button"].warning-button:hover {
} }
input[type="submit"]:hover { input[type="submit"]:hover {
background-color: #0056b3; background-color: var(--hover-color);
border-color: #0056b3; border-color: var(--hover-color);
} }
input[type="submit"]:disabled, input[type="submit"]:disabled,
@ -1113,7 +1126,7 @@ input[type="text"]:disabled {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; height: 100%;
color: #0056b3; color: var(--hover-color);
font-size: 16px; font-size: 16px;
text-align: center; text-align: center;
} }
@ -1141,7 +1154,7 @@ input[type="text"]:disabled {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; height: 100%;
color: #0056b3; color: var(--hover-color);
font-size: 16px; font-size: 16px;
text-align: center; text-align: center;
} }
@ -1281,11 +1294,11 @@ input[type="text"]:disabled {
} }
.toast-content .toast-icon.error { .toast-content .toast-icon.error {
background-color: #f45a40; background-color: var(--error-color);
} }
.toast-content .toast-icon.success { .toast-content .toast-icon.success {
background-color: #188823; background-color: var(--success-color);
} }
@ -1338,11 +1351,11 @@ input[type="text"]:disabled {
} }
.toast .progress.error:before { .toast .progress.error:before {
background-color: #f45a40; background-color: var(--error-color);
} }
.toast .progress.success:before { .toast .progress.success:before {
background-color: #188823; background-color: var(--success-color);
} }
.progress.active:before { .progress.active:before {
@ -1401,7 +1414,7 @@ input[type="text"]:disabled {
.statistic > span { .statistic > span {
font-size: 42px; font-size: 42px;
color: #0056b3; color: var(--hover-color);
} }
.statistic > .title { .statistic > .title {
@ -1411,7 +1424,7 @@ input[type="text"]:disabled {
.statistic > .subtitle { .statistic > .subtitle {
font-size: 25px; font-size: 25px;
color: #8FBFFA; color: var(--accent-color);
margin-top: 10px; margin-top: 10px;
text-align: center; text-align: center;
} }
@ -1486,8 +1499,8 @@ input[type="text"]:disabled {
.sortable-list .sortable-ghost { .sortable-list .sortable-ghost {
border-radius: 16px; border-radius: 16px;
background-color: #c1d9f7; background-color: rgba(var(--accent-color-rgb), 0.6);
border: 1px solid #8FBFFA; border: 1px solid var(--accent-color);
} }
/* Fitler dropdown */ /* Fitler dropdown */
@ -1567,7 +1580,7 @@ input[type="text"]:disabled {
} }
.filtermenu-content .filter-title.filter-clear { .filtermenu-content .filter-title.filter-clear {
color: #0056b3; color: var(--hover-color);
font-weight: normal; font-weight: normal;
border-bottom: none; border-bottom: none;
} }
@ -1588,3 +1601,115 @@ input[type="text"]:disabled {
.filtermenu-submenu-content.is-open { .filtermenu-submenu-content.is-open {
display: block; display: block;
} }
/* Theme Selector */
.theme-selector {
display: flex;
flex-direction: row;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.theme-preview {
display: flex;
flex-direction: row;
gap: 10px;
align-items: center;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 8px;
padding: 20px 15px 20px 10px;
}
.theme-preview.is-selected {
border: 1px solid var(--main-color);
}
.theme-preview:hover {
background-color: rgba(var(--accent-color-rgb), 0.6);
}
.theme-preview > .main-color,
.theme-preview > .accent-color,
.theme-preview > .hover-color {
display: inline-block;
width: 25px;
height: 25px;
border: 1px solid #FFF;
}
.theme-preview.blue > .main-color {
background-color: #007bff;
}
.theme-preview.blue > .accent-color {
background-color: #8fbffa;
}
.theme-preview.blue > .hover-color {
background-color: #0056b3;
}
.theme-preview.green > .main-color {
background-color: #6B8E23;
}
.theme-preview.green > .accent-color {
background-color: #9ACD32;
}
.theme-preview.green > .hover-color {
background-color: #556B2F;
}
.theme-preview.red > .main-color {
background-color: #f45a40;
}
.theme-preview.red > .accent-color {
background-color: #f79988;
}
.theme-preview.red > .hover-color {
background-color: #c73f29;
}
.theme-preview.yellow > .main-color {
background-color: #ffae00;
}
.theme-preview.yellow > .accent-color {
background-color: #faea8f;
}
.theme-preview.yellow > .hover-color {
background-color: #cd930c;
}
.color-picker-wrapper {
display: flex;
flex-direction: row;
gap: 16px;
}
.color-picker {
flex-shrink: 0;
}
.color-picker::before {
color: var(--hover-color);
position: absolute;
top: -5px;
right: -5px;
border: 1px solid;
border-radius: 15px;
background-color: white;
padding: 4px;
}
.wrap {
flex-wrap: wrap;
}

12
styles/theme.css Normal file
View File

@ -0,0 +1,12 @@
:root {
--main-color: #007bff;
--main-color-rgb: 0, 123, 255;
--accent-color: #8fbffa;
--accent-color-rgb: 143, 191, 250;
--hover-color: #0056b3;
--hover-color-rgb: 0, 86, 179;
--error-color: #f45a40;
--error-color-rgb: 244, 90, 64;
--success-color: #188823;
--success-color-rgb: 24, 136, 35;
}

21
styles/themes/green.css Normal file
View File

@ -0,0 +1,21 @@
:root {
--main-color: #6B8E23; /* Dark Olive Green */
--main-color-rgb: 107, 142, 35;
--accent-color: #9ACD32; /* Yellow-Green */
--accent-color-rgb: 154, 205, 50;
--hover-color: #556B2F; /* Olive Drab */
--hover-color-rgb: 85, 107, 47;
}
header .logo .logo-image {
background-image: url("../../images/siteicons/green/wallos.png");
}
.dark header .logo .logo-image {
background-image: url("../../images/siteicons/green/walloswhite.png");
}
.sort-options > ul > li.selected,
.filtermenu-content .filter-item.selected {
background-image: url("../../images/siteicons/green/check.png");
}

21
styles/themes/red.css Normal file
View File

@ -0,0 +1,21 @@
:root {
--main-color: #f45a40;
--main-color-rgb: 244, 90, 64;
--accent-color: #f79988;
--accent-color-rgb: 239, 134, 116;
--hover-color: #c73f29;
--hover-color-rgb: 199, 63, 41;
}
header .logo .logo-image {
background-image: url("../../images/siteicons/red/wallos.png");
}
.dark header .logo .logo-image {
background-image: url("../../images/siteicons/red/walloswhite.png");
}
.sort-options > ul > li.selected,
.filtermenu-content .filter-item.selected {
background-image: url("../../images/siteicons/red/check.png");
}

21
styles/themes/yellow.css Normal file
View File

@ -0,0 +1,21 @@
:root {
--main-color: #ffae00;
--main-color-rgb: 255, 174, 0;
--accent-color: #faea8f;
--accent-color-rgb: 250, 234, 143;
--hover-color: #cd930c;
--hover-color-rgb: 179, 124, 0;
}
header .logo .logo-image {
background-image: url("../../images/siteicons/yellow/wallos.png");
}
.dark header .logo .logo-image {
background-image: url("../../images/siteicons/yellow/walloswhite.png");
}
.sort-options > ul > li.selected,
.filtermenu-content .filter-item.selected {
background-image: url("../../images/siteicons/yellow/check.png");
}