feature: Dark mode switch

This commit is contained in:
Keith Solomon
2025-02-09 16:24:31 -06:00
parent 3220a88fb3
commit bc2d0d8f97
4 changed files with 246 additions and 30 deletions

View File

@@ -521,6 +521,9 @@
}
}
@layer utilities {
.collapse {
visibility: collapse;
}
.absolute {
position: absolute;
}
@@ -539,9 +542,15 @@
.top-2 {
top: calc(var(--spacing) * 2);
}
.top-\[2px\] {
top: 2px;
}
.right-2 {
right: calc(var(--spacing) * 2);
}
.left-1 {
left: calc(var(--spacing) * 1);
}
.container {
width: 100%;
@media (width >= 40rem) {
@@ -566,6 +575,9 @@
.mt-4 {
margin-top: calc(var(--spacing) * 4);
}
.mr-2 {
margin-right: calc(var(--spacing) * 2);
}
.mb-0 {
margin-bottom: calc(var(--spacing) * 0);
}
@@ -596,9 +608,39 @@
.inline-block {
display: inline-block;
}
.inline-flex {
display: inline-flex;
}
.list-item {
display: list-item;
}
.table {
display: table;
}
.h-4 {
height: calc(var(--spacing) * 4);
}
.h-5 {
height: calc(var(--spacing) * 5);
}
.h-6 {
height: calc(var(--spacing) * 6);
}
.w-4 {
width: calc(var(--spacing) * 4);
}
.w-5 {
width: calc(var(--spacing) * 5);
}
.w-5\/6 {
width: calc(5/6 * 100%);
}
.w-6 {
width: calc(var(--spacing) * 6);
}
.w-10 {
width: calc(var(--spacing) * 10);
}
.w-96 {
width: calc(var(--spacing) * 96);
}
@@ -608,6 +650,18 @@
.w-full {
width: 100%;
}
.border-collapse {
border-collapse: collapse;
}
.transform {
transform: var(--tw-rotate-x) var(--tw-rotate-y) var(--tw-rotate-z) var(--tw-skew-x) var(--tw-skew-y);
}
.cursor-pointer {
cursor: pointer;
}
.resize {
resize: both;
}
.list-none {
list-style-type: none;
}
@@ -646,6 +700,9 @@
.rounded {
border-radius: 0.25rem;
}
.rounded-full {
border-radius: calc(infinity * 1px);
}
.rounded-lg {
border-radius: var(--radius-lg);
}
@@ -665,6 +722,9 @@
.bg-gray-100 {
background-color: var(--color-gray-100);
}
.bg-gray-300 {
background-color: var(--color-gray-300);
}
.bg-green-500 {
background-color: var(--color-green-500);
}
@@ -742,10 +802,20 @@
.text-white {
color: var(--color-white);
}
.text-yellow-500 {
color: var(--color-yellow-500);
}
.underline {
text-decoration-line: underline;
}
.shadow {
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.shadow-inner {
--tw-shadow: inset 0 2px 4px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.shadow-lg {
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -754,6 +824,15 @@
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
.transition-transform {
transition-property: transform, translate, scale, rotate;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
.hover\:bg-blue-600 {
&:hover {
@media (hover: hover) {
@@ -761,6 +840,13 @@
}
}
}
.hover\:bg-gray-200 {
&:hover {
@media (hover: hover) {
background-color: var(--color-gray-200);
}
}
}
.hover\:bg-green-600 {
&:hover {
@media (hover: hover) {
@@ -775,6 +861,12 @@
}
}
}
.focus\:outline-none {
&:focus {
--tw-outline-style: none;
outline-style: none;
}
}
.md\:grid-cols-2 {
@media (width >= 48rem) {
grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -795,6 +887,37 @@
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
.dark\:bg-gray-600 {
@media (prefers-color-scheme: dark) {
background-color: var(--color-gray-600);
}
}
.dark\:bg-gray-900 {
@media (prefers-color-scheme: dark) {
background-color: var(--color-gray-900);
}
}
.dark\:hover\:bg-gray-700 {
@media (prefers-color-scheme: dark) {
&:hover {
@media (hover: hover) {
background-color: var(--color-gray-700);
}
}
}
}
}
.dark body {
background-color: var(--color-gray-900);
color: var(--color-gray-100);
[class*="bg-white"] {
background-color: var(--color-gray-800);
color: var(--color-gray-100);
}
[class*="bg-gray-100"], [class*="bg-gray-50"] {
background-color: var(--color-gray-700);
color: var(--color-gray-100);
}
}
@keyframes spin {
to {
@@ -822,6 +945,31 @@
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
}
@property --tw-rotate-x {
syntax: "*";
inherits: false;
initial-value: rotateX(0);
}
@property --tw-rotate-y {
syntax: "*";
inherits: false;
initial-value: rotateY(0);
}
@property --tw-rotate-z {
syntax: "*";
inherits: false;
initial-value: rotateZ(0);
}
@property --tw-skew-x {
syntax: "*";
inherits: false;
initial-value: skewX(0);
}
@property --tw-skew-y {
syntax: "*";
inherits: false;
initial-value: skewY(0);
}
@property --tw-space-y-reverse {
syntax: "*";
inherits: false;
@@ -896,3 +1044,8 @@
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-outline-style {
syntax: "*";
inherits: false;
initial-value: solid;
}

View File

@@ -14,23 +14,36 @@
<body class="bg-gray-100">
<div class="container mx-auto p-4">
<h1 class="text-4xl font-bold mb-4">Bill Tracker</h1>
<div class="flex justify-between">
<h1 class="text-4xl font-bold p-4">Bill Tracker</h1>
<div class="flex justify-end p-4">
<button id="darkModeToggle" class="flex items-center focus:outline-none p-2 rounded hover:bg-gray-200 dark:hover:bg-gray-700">
<svg id="sunIcon" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-yellow-500 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M 11 0 L 11 3 L 13 3 L 13 0 L 11 0 z M 4.2226562 2.8085938 L 2.8085938 4.2226562 L 4.9296875 6.34375 L 6.34375 4.9296875 L 4.2226562 2.8085938 z M 19.777344 2.8085938 L 17.65625 4.9296875 L 19.070312 6.34375 L 21.191406 4.2226562 L 19.777344 2.8085938 z M 12 5 C 8.1458514 5 5 8.1458514 5 12 C 5 15.854149 8.1458514 19 12 19 C 15.854149 19 19 15.854149 19 12 C 19 8.1458514 15.854149 5 12 5 z M 12 7 C 14.773268 7 17 9.2267316 17 12 C 17 14.773268 14.773268 17 12 17 C 9.2267316 17 7 14.773268 7 12 C 7 9.2267316 9.2267316 7 12 7 z M 0 11 L 0 13 L 3 13 L 3 11 L 0 11 z M 21 11 L 21 13 L 24 13 L 24 11 L 21 11 z M 4.9296875 17.65625 L 2.8085938 19.777344 L 4.2226562 21.191406 L 6.34375 19.070312 L 4.9296875 17.65625 z M 19.070312 17.65625 L 17.65625 19.070312 L 19.777344 21.191406 L 21.191406 19.777344 L 19.070312 17.65625 z M 11 21 L 11 24 L 13 24 L 13 21 L 11 21 z"></path>
</svg>
<svg id="moonIcon" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-500 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12.79A9 9 0 1111.21 3a7 7 0 109.79 9.79z" />
</svg>
</button>
</div>
</div>
<!-- Add Bill Form -->
<form id="billForm" class="bg-white p-4 mb-6 rounded shadow">
<h2 class="text-2xl font-bold mb-4">Add New Payment</h2>
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
<input type="date" name="date" required class="p-2 border rounded">
<input type="date" name="date" required class="p-2 border rounded bg-gray-50">
<select required id="payeeId" name="payeeId" class="border rounded p-2">
<select required id="payeeId" name="payeeId" class="border rounded p-2 bg-gray-50">
<!-- Payees will be populated here -->
</select>
<input type="number" step="0.01" name="amount" placeholder="Amount" required class="p-2 border rounded">
<input type="text" name="paymentId" placeholder="Payment ID" class="p-2 border rounded">
<input type="number" step="0.01" name="amount" placeholder="Amount" required class="p-2 border rounded bg-gray-50">
<input type="text" name="paymentId" placeholder="Payment ID" class="p-2 border rounded bg-gray-50">
<input type="text" name="comment" class="p-2 border rounded" placeholder="Add a comment (optional)"></input>
<input type="text" name="comment" class="p-2 border rounded bg-gray-50" placeholder="Add a comment (optional)"></input>
</div>
<button type="submit" class="mt-4 bg-blue-500 text-white px-4 py-2 rounded">Add Bill</button>
@@ -88,7 +101,7 @@
<div class="">
<label for="yearSelect" class="block mb-2 font-bold">Select Year:</label>
<select id="yearSelect" class="border rounded px-3 py-2 bg-gray-50">
<select id="yearSelect" class="border rounded px-3 py-2 bg-gray-50 w-full">
<option value="2025">2025</option>
<option value="2024">2024</option>
<option value="2023">2023</option>

View File

@@ -174,10 +174,10 @@ document.addEventListener('DOMContentLoaded', () => {
datasets: [{
data: totals,
backgroundColor: [
'#003962', '#00607F', '#008B9C', '#00B8B9', '#00E6D6', '#00FFF4'
'#003962', '#00607F', '#008B9C', '#00B8B9', '#00E6D6', '#00FFF4', '#007ACC' // New color added
], // Add more colors if needed
hoverBackgroundColor: [
'#042c4c', '#004968', '#007384', '#009FA1', '#00CCBD', '#00FBDA'
'#042c4c', '#004968', '#007384', '#009FA1', '#00CCBD', '#00FBDA', '#005BB5' // New hover color added
]
}]
},
@@ -291,6 +291,45 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('editModal').classList.remove('flex');
});
// Dark mode toggle
const darkModeToggle = document.getElementById('darkModeToggle');
const htmlElement = document.documentElement;
const sunIcon = document.getElementById('sunIcon');
const moonIcon = document.getElementById('moonIcon');
// Function to update icons based on the current theme
function updateIcons() {
const isDarkMode = htmlElement.classList.contains('dark');
if (isDarkMode) {
sunIcon.classList.remove('hidden');
moonIcon.classList.add('hidden');
} else {
sunIcon.classList.add('hidden');
moonIcon.classList.remove('hidden');
}
}
// Check and apply the saved preference
const isDarkMode = localStorage.getItem('theme') === 'dark';
if (isDarkMode) {
htmlElement.classList.add('dark');
}
updateIcons();
// Add toggle functionality
darkModeToggle.addEventListener('click', () => {
if (htmlElement.classList.contains('dark')) {
htmlElement.classList.remove('dark');
localStorage.setItem('theme', 'light');
} else {
htmlElement.classList.add('dark');
localStorage.setItem('theme', 'dark');
}
updateIcons();
});
// On page load
loadPayees('payeeId'); // Load payees
loadYears(); // Load years

View File

@@ -2,4 +2,15 @@
@import "tailwindcss";
/* Basic project styles */
.dark body {
@apply bg-gray-900 text-gray-100;
[class*="bg-white"] {
@apply bg-gray-800 text-gray-100;
}
[class*="bg-gray-100"],
[class*="bg-gray-50"] {
@apply bg-gray-700 text-gray-100;
}
}