Proje dosyaları eklendi
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user