Proje dosyaları eklendi

This commit is contained in:
2026-08-29 15:53:53 +03:00
commit d3313400ca
440 changed files with 24827 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
:root {
--tp-brand-rgb: 91, 75, 255;
--bs-primary-rgb: var(--tp-brand-rgb);
--bs-link-color-rgb: var(--tp-brand-rgb);
}
[data-bs-theme="light"] {
--tp-page-accent: rgba(var(--tp-brand-rgb), .08);
}
[data-bs-theme="dark"] {
--tp-page-accent: rgba(var(--tp-brand-rgb), .16);
}
body {
min-height: 100vh;
background:
radial-gradient(circle at 85% 15%, var(--tp-page-accent), transparent 32rem),
var(--bs-body-bg);
}
.card,
.navbar,
.dropdown-menu,
.btn {
transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}
@media (prefers-reduced-motion: reduce) {
.card,
.navbar,
.dropdown-menu,
.btn {
transition: none;
}
}
+41
View File
@@ -0,0 +1,41 @@
(function (window, document) {
'use strict';
var labels = { light: 'Açık', dark: 'Karanlık', system: 'Sistem' };
var icons = { light: '☀', dark: '☾', system: '◐' };
function updateThemeControls(event) {
var state = event && event.detail ? event.detail : {
preference: window.ThemeManager.getPreference(),
resolved: window.ThemeManager.getResolvedTheme()
};
document.querySelectorAll('[data-theme-value]').forEach(function (button) {
var active = button.dataset.themeValue === state.preference;
button.classList.toggle('active', active);
button.setAttribute('aria-pressed', String(active));
});
document.querySelectorAll('[data-theme-current-label]').forEach(function (node) {
node.textContent = labels[state.preference];
});
document.querySelectorAll('[data-theme-current-icon]').forEach(function (node) {
node.textContent = icons[state.preference];
});
document.querySelectorAll('[data-theme-preference]').forEach(function (node) {
node.textContent = labels[state.preference];
});
document.querySelectorAll('[data-theme-resolved]').forEach(function (node) {
node.textContent = labels[state.resolved];
});
}
document.addEventListener('click', function (event) {
var button = event.target.closest('[data-theme-value]');
if (button) {
window.ThemeManager.setPreference(button.dataset.themeValue);
}
});
window.addEventListener('trafficpumper:theme-change', updateThemeControls);
updateThemeControls();
}(window, document));
@@ -0,0 +1,76 @@
(function (window, document) {
'use strict';
var STORAGE_KEY = 'trafficpumper.theme';
var DEFAULT_PREFERENCE = 'system';
var VALID_PREFERENCES = ['light', 'dark', 'system'];
var mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
var preference = readPreference();
function isValid(value) {
return VALID_PREFERENCES.indexOf(value) !== -1;
}
function readPreference() {
try {
var stored = window.localStorage.getItem(STORAGE_KEY);
return isValid(stored) ? stored : DEFAULT_PREFERENCE;
} catch (error) {
return DEFAULT_PREFERENCE;
}
}
function resolve(value) {
return value === 'system' ? (mediaQuery.matches ? 'dark' : 'light') : value;
}
function apply() {
var resolved = resolve(preference);
document.documentElement.setAttribute('data-bs-theme', resolved);
document.documentElement.style.colorScheme = resolved;
window.dispatchEvent(new window.CustomEvent('trafficpumper:theme-change', {
detail: { preference: preference, resolved: resolved }
}));
return resolved;
}
function setPreference(value) {
if (!isValid(value)) {
return false;
}
preference = value;
try {
window.localStorage.setItem(STORAGE_KEY, value);
} catch (error) {
// Depolama kapalıysa tema oturum boyunca yine çalışır.
}
apply();
return true;
}
function onSystemThemeChange() {
if (preference === 'system') {
apply();
}
}
if (typeof mediaQuery.addEventListener === 'function') {
mediaQuery.addEventListener('change', onSystemThemeChange);
} else if (typeof mediaQuery.addListener === 'function') {
mediaQuery.addListener(onSystemThemeChange);
}
window.ThemeManager = Object.freeze({
storageKey: STORAGE_KEY,
getPreference: function () { return preference; },
getResolvedTheme: function () { return resolve(preference); },
setPreference: setPreference,
apply: apply
});
// Bu dosya <head> içinde senkron çalıştığı için ilk boyadan önce uygulanır.
apply();
}(window, document));
+83
View File
@@ -0,0 +1,83 @@
<!doctype html>
<html lang="tr" data-bs-theme="light">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<title>TrafficPumper Tema Altyapısı</title>
<!-- Senkron yüklenir: ilk boya yapılmadan önce kayıtlı/aktif temayı uygular. -->
<script src="assets/js/theme-manager.js"></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"
crossorigin="anonymous"
>
<link rel="stylesheet" href="assets/css/app.css">
</head>
<body>
<nav class="navbar border-bottom bg-body-tertiary" aria-label="Ana navigasyon">
<div class="container py-2 gap-3">
<a class="navbar-brand fw-semibold" href="#">TrafficPumper</a>
<div class="dropdown ms-auto">
<button
class="btn btn-outline-secondary dropdown-toggle d-flex align-items-center gap-2"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
aria-label="Tema seç"
>
<span data-theme-current-icon aria-hidden="true"></span>
<span data-theme-current-label>Sistem</span>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow-sm" data-theme-picker>
<li><button class="dropdown-item d-flex gap-2" type="button" data-theme-value="light"><span aria-hidden="true"></span> Açık</button></li>
<li><button class="dropdown-item d-flex gap-2" type="button" data-theme-value="dark"><span aria-hidden="true"></span> Karanlık</button></li>
<li><button class="dropdown-item d-flex gap-2" type="button" data-theme-value="system"><span aria-hidden="true"></span> Sistem</button></li>
</ul>
</div>
</div>
</nav>
<main class="container py-5">
<section class="row align-items-center g-5 py-lg-5">
<div class="col-lg-7">
<span class="badge text-bg-primary mb-3">Ortak tema temeli</span>
<h1 class="display-5 fw-bold">Açık, karanlık ve sistem teması hazır.</h1>
<p class="lead text-body-secondary mt-3">
Seçiminiz bu tarayıcıda saklanır ve tüm TrafficPumper ekranlarında ortak kullanılabilir.
</p>
<div class="d-flex flex-wrap gap-2 mt-4" role="group" aria-label="Hızlı tema seçimi" data-theme-picker>
<button class="btn btn-outline-primary" type="button" data-theme-value="light">☀ Açık</button>
<button class="btn btn-outline-primary" type="button" data-theme-value="dark">☾ Karanlık</button>
<button class="btn btn-outline-primary" type="button" data-theme-value="system">◐ Sistem</button>
</div>
</div>
<div class="col-lg-5">
<div class="card border-0 shadow-sm">
<div class="card-body p-4 p-md-5">
<h2 class="h4">Tema durumu</h2>
<dl class="row mb-0 mt-4">
<dt class="col-6 text-body-secondary">Tercih</dt>
<dd class="col-6 text-end fw-semibold" data-theme-preference>Sistem</dd>
<dt class="col-6 text-body-secondary">Etkin tema</dt>
<dd class="col-6 text-end fw-semibold" data-theme-resolved></dd>
</dl>
<hr>
<p class="small text-body-secondary mb-0">
“Sistem” seçiliyken işletim sistemi teması değiştiğinde bu alan anında güncellenir.
</p>
</div>
</div>
</div>
</section>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
<script src="assets/js/app.js"></script>
</body>
</html>