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>
<source media="(prefers-color-scheme: dark)" srcset="./images/wallossolidwhite.png">
<source media="(prefers-color-scheme: light)" srcset="./images/wallossolid.png">
<img alt="Wallos" src="./images/wallossolid.png">
<source media="(prefers-color-scheme: dark)" srcset="./images/siteicons/blue/walloswhite.png">
<source media="(prefers-color-scheme: light)" srcset="./images/siteicons/blue/wallos.png">
<img alt="Wallos" src="./images/siteicons/blue/wallos.png">
</picture>
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'];
}
$colorTheme = "blue";
if (isset($settings['color_theme'])) {
$colorTheme = $settings['color_theme'];
}
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
$sort = "next_payment";
$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) {
$id = $subscription['id'];
$print[$id]['id'] = $id;
@ -97,7 +102,7 @@
}
if (isset($print)) {
printSubscriptions($print, $sort, $categories, $members, $i18n);
printSubscriptions($print, $sort, $categories, $members, $i18n, $colorTheme);
}
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);
setcookie('theme', $settings['dark_theme'] ? 'dark': 'light', $cookieExpire);
$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['convertCurrency'] = $settings['convert_currency'] ? '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'];
}
$colorTheme = "blue";
if (isset($settings['color_theme'])) {
$colorTheme = $settings['color_theme'];
}
?>
<!DOCTYPE html>
<html>
@ -34,8 +38,12 @@
<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="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/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/font-awesome.min.css">
<script type="text/javascript" src="scripts/all.js?<?= $version ?>"></script>
@ -43,11 +51,31 @@
<script type="text/javascript">
window.theme = "<?= $theme ?>";
window.lang = "<?=$lang ?>";
window.colorTheme = "<?= $colorTheme ?>";
</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/getlang.js?<?= $version ?>"></script>
</head>
<body>
<body class="<?= $theme ?>">
<header>
<div class="contain">
<div class="logo">

View File

@ -139,6 +139,9 @@ $i18n = [
"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",
"display_settings" => "Display-Einstellungen",
"theme_settings" => "Themen-Einstellungen",
"custom_colors" => "Benutzerdefinierte Farben",
"dark_theme" => "Dark Theme",
"switch_theme" => "Light / Dark Theme umschalten",
"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)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test",
"add" => "Hinzufügen",
"save" => "Speichern",
"reset" => "Zurücksetzen",
"export_subscriptions" => "Abonnements exportieren",
"export_to_json" => "Nach JSON exportieren",
// Filters menu

View File

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

View File

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

View File

@ -139,6 +139,9 @@ $i18n = [
"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",
"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",
"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)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Probar",
"add" => "Agregar",
"save" => "Guardar",
"reset" => "Restablecer",
"export_subscriptions" => "Exportar suscripciones",
"export_to_json" => "Exportar a JSON",
// Filters menu

View File

@ -139,6 +139,9 @@ $i18n = [
"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",
"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",
"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)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test",
"add" => "Ajouter",
"save" => "Enregistrer",
"reset" => "Réinitialiser",
"export_subscriptions" => "Exporter les abonnements",
"export_to_json" => "Exporter en JSON",
// Menu des filtes

View File

@ -144,6 +144,9 @@ $i18n = [
'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',
'display_settings' => 'Impostazioni di visualizzazione',
"theme_settings" => 'Impostazioni del tema',
"custom_colors" => 'Colori personalizzati',
"dark_theme" => 'Tema scuro',
'switch_theme' => 'Cambia tema chiaro/scuro',
'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)',
@ -166,6 +169,7 @@ $i18n = [
'test' => 'Test',
'add' => 'Aggiungi',
'save' => 'Salva',
"reset" => 'Ripristina',
'export_subscriptions' => 'Esporta abbonamenti',
'export_to_json' => 'Esporta in JSON',

View File

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

View File

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

View File

@ -139,6 +139,9 @@ $i18n = [
"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",
"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",
"calculate_monthly_price" => "Oblicz i pokaż miesięczną cenę wszystkich subskrypcji",
"convert_prices" => "Zawsze przeliczaj i pokazuj ceny w mojej głównej walucie (wolniej)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test",
"add" => "Dodaj",
"save" => "Zapisz",
"reset" => "Resetuj",
"export_subscriptions" => "Eksportuj subskrypcje",
"export_to_json" => "Eksportuj do JSON",
// Filters menu

View File

@ -139,6 +139,9 @@ $i18n = [
"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",
"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",
"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)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Testar",
"add" => "Adicionar",
"save" => "Guardar",
"reset" => "Repor",
"export_subscriptions" => "Exportar Subscrições",
"export_to_json" => "Exportar para JSON",
// Filters menu

View File

@ -137,6 +137,9 @@ $i18n = [
"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",
"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",
"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)",
@ -159,6 +162,7 @@ $i18n = [
"test" => "Testar",
"add" => "Adicionar",
"save" => "Salvar",
"reset" => "Redefinir",
"export_subscriptions" => "Exportar assinaturas",
"export_to_json" => "Exportar para JSON",
// Filters menu

View File

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

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Pronađite besplatni Fixer API ključ",
"get_key_alternative" => "Alternativno, možete dobiti besplatni Fixer API ključ na",
"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",
"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)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test",
"add" => "Dodaj",
"save" => "Sačuvaj",
"reset" => "Resetuj",
"export_subscriptions" => "Izvezi pretplate",
"export_to_json" => "Izvezi u JSON format",
// Meni sa filterima

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "Ücretsiz Fixer API Anahtarı alın",
"get_key_alternative" => "Alternatif olarak, şu adresten ücretsiz bir fixer api anahtarı edinebilirsiniz",
"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",
"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ş)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "Test Et",
"add" => "Ekle",
"save" => "Kaydet",
"reset" => "Sıfırla",
"export_subscriptions" => "Abonelikleri Dışa Aktar",
"export_to_json" => "JSON'a dışa aktar",
// Filters menu

View File

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

View File

@ -139,6 +139,9 @@ $i18n = [
"get_free_fixer_api_key" => "申請免費的 Fixer API 金鑰",
"get_key_alternative" => "或者,您可以從以下網址取得一個免費的修復 api 金鑰",
"display_settings" => "顯示設定",
"theme_settings" => "主題設定",
"custom_colors" => "自訂顏色",
"dark_theme" => "深色主題",
"switch_theme" => "切換淺色/深色主題",
"calculate_monthly_price" => "計算並顯示所有訂閱的每月價格",
"convert_prices" => "始終按照我的主要貨幣單位轉換和顯示價格(較慢)",
@ -161,6 +164,7 @@ $i18n = [
"test" => "測試",
"add" => "新增",
"save" => "儲存",
"reset" => "重設",
"export_subscriptions" => "匯出訂閱",
"export_to_json" => "匯出為 JSON 檔案",
// 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") {
usort($subscriptions, function($a, $b) {
return $a['price'] < $b['price'] ? 1 : -1;
@ -110,14 +110,14 @@
</span>
<span class="actions">
<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>
</span>
</div>
<div class="subscription-secondary">
<span class="name"><img src="images/siteicons/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="category" title="<?= translate('category', $i18n) ?>" ><img src="images/siteicons/category.png" alt="<?= translate('category', $i18n) ?>" /><?= $categories[$subscription['category_id']]['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/<?= $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/<?= $colorTheme ?>/category.png" alt="<?= translate('category', $i18n) ?>" /><?= $categories[$subscription['category_id']]['name'] ?></span>
<?php
if ($subscription['url'] != "") {
$url = $subscription['url'];
@ -125,7 +125,7 @@
$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
}
?>
@ -135,7 +135,7 @@
?>
<div class="subscription-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'] ?>
</span>
</div>

View File

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

View File

@ -37,7 +37,7 @@
}
$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>
.logo-preview:after {
@ -188,7 +188,7 @@
}
if (isset($print)) {
printSubscriptions($print, $sort, $categories, $members, $i18n);
printSubscriptions($print, $sort, $categories, $members, $i18n, $colorTheme);
}
$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="hidden" id="logo-url" name="logo-url">
<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>
<input type="hidden" id="id" name="id">
<div id="logo-search-results" class="logo-search">

View File

@ -25,6 +25,11 @@ if (isset($_COOKIE['theme'])) {
$theme = $_COOKIE['theme'];
}
$colorTheme = "blue";
if (isset($_COOKIE['colorTheme'])) {
$colorTheme = $_COOKIE['colorTheme'];
}
$loginFailed = false;
if (isset($_POST['username']) && isset($_POST['password'])) {
$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="apple-touch-icon" sizes="180x180" href="images/icon/apple-touch-icon.png">
<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/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/login-dark-theme.css?<?= $version ?>" id="dark-theme" <?= $theme == "light" ? "disabled" : "" ?>>
</head>
@ -90,9 +99,9 @@ if (isset($_POST['username']) && isset($_POST['password'])) {
<header>
<?php
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 {
?> <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>

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="apple-touch-icon" sizes="180x180" href="images/icon/apple-touch-icon.png">
<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-dark-theme.css?<?= $version ?>" id="dark-theme" <?= $theme == "light" ? "disabled" : "" ?>>
<link rel="stylesheet" href="styles/barlow.css">
@ -106,9 +107,9 @@ if (isset($_POST['username'])) {
<header>
<?php
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 {
?> <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>

View File

@ -37,7 +37,7 @@ function fillEditFormFields(subscription) {
const formTitle = document.querySelector("#form-title");
formTitle.textContent = translate('edit_subscription');
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;
logo.src = logoFile;
logo.style = 'display: block';

View File

@ -108,7 +108,7 @@ function addMemberButton(memberId) {
};
let editImage = document.createElement("img");
editImage.src = "images/siteicons/save.png";
editImage.src = "images/siteicons/" + colorTheme + "/save.png";
editImage.title = translate('save_member');
editLink.appendChild(editImage);
@ -121,7 +121,7 @@ function addMemberButton(memberId) {
};
let deleteImage = document.createElement("img");
deleteImage.src = "images/siteicons/delete.png";
deleteImage.src = "images/siteicons/" + colorTheme + "/delete.png";
deleteImage.title = translate('delete_member');
deleteLink.appendChild(deleteImage);
@ -237,7 +237,7 @@ function addCategoryButton(categoryId) {
};
let editImage = document.createElement("img");
editImage.src = "images/siteicons/save.png";
editImage.src = "images/siteicons/" + colorTheme + "/save.png";
editImage.title = translate('save_category');
editLink.appendChild(editImage);
@ -250,7 +250,7 @@ function addCategoryButton(categoryId) {
};
let deleteImage = document.createElement("img");
deleteImage.src = "images/siteicons/delete.png";
deleteImage.src = "images/siteicons/" + colorTheme + "/delete.png";
deleteImage.title = translate('delete_category');
deleteLink.appendChild(deleteImage);
@ -375,7 +375,7 @@ function addCurrencyButton(currencyId) {
};
let editImage = document.createElement("img");
editImage.src = "images/siteicons/save.png";
editImage.src = "images/siteicons/" + colorTheme + "/save.png";
editImage.title = translate('save_currency');
editLink.appendChild(editImage);
@ -388,7 +388,7 @@ function addCurrencyButton(currencyId) {
};
let deleteImage = document.createElement("img");
deleteImage.src = "images/siteicons/delete.png";
deleteImage.src = "images/siteicons/" + colorTheme + "/delete.png";
deleteImage.title = translate('delete_currency');
deleteLink.appendChild(deleteImage);
@ -937,6 +937,8 @@ function switchTheme() {
const themeChoice = darkThemeCss.disabled ? 'light' : 'dark';
document.cookie = `theme=${themeChoice}; expires=Fri, 31 Dec 9999 23:59:59 GMT`;
document.body.className = themeChoice;
const button = document.getElementById("switchTheme");
button.disabled = true;
@ -1040,3 +1042,115 @@ var sortable = Sortable.create(el, {
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/font-awesome.min.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.ttf',
'scripts/common.js',
@ -21,16 +24,16 @@ self.addEventListener('install', function(event) {
'scripts/stats.js',
'scripts/settings.js',
'scripts/registration.js',
'scripts/i18n/en.js',
'scripts/i18n/de.js',
'scripts/i18n/el.js',
'scripts/i18n/en.js',
'scripts/i18n/es.js',
'scripts/i18n/fr.js',
'scripts/i18n/it.js',
'scripts/i18n/jp.js',
'scripts/i18n/pl.js',
'scripts/i18n/pt_br.js',
'scripts/i18n/pt.js',
'scripts/i18n/pt_br.js',
'scripts/i18n/tr.js',
'scripts/i18n/zh_cn.js',
'scripts/i18n/zh_tw.js',
@ -40,8 +43,14 @@ self.addEventListener('install', function(event) {
'images/icon/favicon.ico',
'images/icon/android-chrome-192x192.png',
'images/screenshots/desktop.png',
'images/wallossolid.png',
'images/wallossolidwhite.png',
'images/siteicons/blue/wallos.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/avatars/1.svg',
'images/avatars/2.svg',
@ -52,19 +61,46 @@ self.addEventListener('install', function(event) {
'images/avatars/7.svg',
'images/avatars/8.svg',
'images/avatars/9.svg',
'images/siteicons/edit.png',
'images/siteicons/websearch.png',
'images/siteicons/save.png',
'images/siteicons/delete.png',
'images/siteicons/category.png',
'images/siteicons/check.png',
'images/siteicons/editavatar.png',
'images/siteicons/notes.png',
'images/siteicons/payment.png',
'images/siteicons/plusicon.png',
'images/siteicons/sort.png',
'images/siteicons/subscription.png',
'images/siteicons/web.png',
'images/siteicons/blue/category.png',
'images/siteicons/blue/check.png',
'images/siteicons/blue/delete.png',
'images/siteicons/blue/edit.png',
'images/siteicons/blue/notes.png',
'images/siteicons/blue/payment.png',
'images/siteicons/blue/save.png',
'images/siteicons/blue/subscription.png',
'images/siteicons/blue/web.png',
'images/siteicons/blue/websearch.png',
'images/siteicons/red/category.png',
'images/siteicons/red/check.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/settings.png',
'images/siteicons/pwa/about.png',

View File

@ -142,19 +142,19 @@
}
?>
<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>
<?php
if ($member['id'] != 1) {
?>
<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>
<?php
} else {
?>
<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>
<?php
}
@ -292,19 +292,19 @@
<div class="drag-icon"></div>
<input type="text" name="category" value="<?= $category['name'] ?>" placeholder="Category">
<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>
<?php
if ($canDelete) {
?>
<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>
<?php
} else {
?>
<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>
<?php
}
@ -375,20 +375,20 @@
<input type="text" name="currency" value="<?= $currency['name'] ?>" placeholder="Currency Name">
<input type="text" name="code" value="<?= $currency['code'] ?>" placeholder="Currency Code" <?= !$canDelete ? 'disabled' : '' ?>>
<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>
<?php
if ($canDelete) {
?>
<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>
<?php
} else {
$cantDeleteMessage = $isMainCurrency ? translate('cant_delete_main_currency', $i18n) : translate('cant_delete_currency_in_use', $i18n);
?>
<button class="image-button medium disabled">
<img src="images/siteicons/delete.png" title="<?= $cantDeleteMessage ?>">
<img src="images/siteicons/<?= $colorTheme ?>/delete.png" title="<?= $cantDeleteMessage ?>">
</button>
<?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="hidden" id="icon-url" name="icon-url">
<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 id="icon-search-results" class="icon-search">
<header>
@ -571,14 +571,73 @@
</div>
</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">
<header>
<h2><?= translate('display_settings', $i18n) ?></h2>
</header>
<div class="account-settings-list">
<div>
<input id="switchTheme" type="button" value="<?= translate('switch_theme', $i18n) ?>" onClick="switchTheme()">
</div>
<div>
<div class="form-group-inline">
<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 {
background-image: url("../images/wallossolidwhite.png");
background-image: url("../images/siteicons/blue/walloswhite.png");
}
.split-header > h2 .header-subtitle {
@ -96,6 +96,10 @@ input[type="button"].secondary-button:hover {
background-color: #111;
}
input[type="color"] {
background-color: #F2F2F2;
}
.avatar-select .avatar-list .remove-avatar {
background-color: #222;
}
@ -133,7 +137,7 @@ input[type="button"].secondary-button:hover {
}
.logo-preview:after {
color: #007bff;
color: var(--main-color);
}
.sort-options > ul > li {

View File

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

View File

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