countdown.html
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.6;
padding: 2rem;
}
h1 {
margin-bottom: 1rem;
}
.controls {
display: flex;
align-items: center;
gap: 1.5rem;
margin-bottom: 1.5rem;
}
/* :root {
--std-gap: 0.5rem;
--border-radius: 0.25rem;
color-scheme: light dark;
} */
/* Light theme */
html.light {
--bg-color: hsl(0, 0%, 100%);
--text-color: hsl(0, 0%, 10%);
--text-secondary: hsl(0, 0%, 30%);
--text-tertiary: hsl(0, 0%, 40%);
--border-color: hsl(0, 0%, 80%);
--list-background: hsl(210, 20%, 95%);
--list-hover: hsl(210, 20%, 92%);
--dialog-bg: hsl(0, 0%, 100%);
--dialog-backdrop: hsl(0, 0%, 0%, 0.5);
--input-bg: hsl(0, 0%, 100%);
--led-on-color: hsl(120, 100%, 50%);
--led-on-glow-color: hsl(120, 100%, 70%);
--led-off-color: hsl(0, 0%, 20%);
--led-graph-background: hsl(0, 0%, 10%);
--button-primary-color: hsl(210, 80%, 50%);
--button-primary-hover: hsl(210, 80%, 45%);
--button-secondary-color: hsl(0, 0%, 95%);
--button-secondary-hover: hsl(0, 0%, 90%);
--elapsed-color: hsl(210, 80%, 40%);
--past-color: hsl(0, 60%, 50%);
--result-bg: hsl(120, 30%, 95%);
--result-border: hsl(120, 30%, 80%);
}
/* Dark theme (default) */
:root,
html.dark {
--bg-color: hsl(0, 0%, 12%);
--text-color: hsl(0, 0%, 90%);
--text-secondary: hsl(0, 0%, 75%);
--text-tertiary: hsl(0, 0%, 65%);
--border-color: hsl(0, 0%, 30%);
--list-background: hsl(210, 10%, 20%);
--list-hover: hsl(210, 10%, 25%);
--dialog-bg: hsl(0, 0%, 15%);
--dialog-backdrop: hsl(0, 0%, 0%, 0.7);
--input-bg: hsl(0, 0%, 20%);
--led-on-color: hsl(120, 100%, 10%);
--led-on-glow-color: hsl(120, 100%, 30%);
--led-off-color: hsl(0, 0%, 30%);
--led-graph-background: hsl(0, 0%, 8%);
--button-primary-color: hsl(210, 80%, 55%);
--button-primary-hover: hsl(210, 80%, 60%);
--button-secondary-color: hsl(0, 0%, 25%);
--button-secondary-hover: hsl(0, 0%, 30%);
--elapsed-color: hsl(210, 80%, 60%);
--past-color: hsl(0, 60%, 60%);
--result-bg: hsl(120, 20%, 18%);
--result-border: hsl(120, 30%, 35%);
}
/* body {
background: var(--bg-color);
color: var(--text-color);
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.6;
padding: 2rem;
} */
/* h1 {
margin-bottom: 1rem;
} */
.controls {
display: flex;
align-items: center;
gap: 1.5rem;
margin-bottom: 1.5rem;
}
/* #region countdown graph */
#add-countdown-btn {
padding: 0.5rem 1rem;
font-size: 1rem;
cursor: pointer;
background: var(--button-primary-color);
color: white;
border: 1px solid var(--button-primary-color);
border-radius: var(--border-radius);
transition: background 0.2s ease;
}
#add-countdown-btn:hover {
background: var(--button-primary-hover);
}
.led-bar {
display: flex;
flex-direction: column-reverse;
gap: 0.125rem;
padding: 0.25rem;
background: var(--led-graph-background);
border-radius: var(--border-radius);
box-shadow: inset 0 0 0.5rem hsl(0, 0%, 0%, 0.5);
}
.led-segment {
width: 1.5rem;
height: 0.125rem;
background: var(--led-off-color);
border-radius: 0.0625rem;
transition: background 0.3s ease, box-shadow 0.3s ease;
}
.led-segment.on {
background: var(--led-on-color);
box-shadow:
0 0 0.5rem var(--led-on-color),
inset 0 0 0.25rem var(--led-on-glow-color);
}
/* #endregion countdown graph */
/* #region Countdown List Styles */
#countdown-list {
list-style: none;
/* margin-top: 1rem; */
display: grid;
/* grid-template-columns: auto 1fr auto auto; */
grid-template-columns: auto auto auto auto;
/* gap: 0.5rem 1rem; */
align-items: center;
}
#countdown-list li {
/* Aligns columns accross the whole list */
display: contents;
cursor: pointer;
background-color:var(--elapsed-color);
}
#countdown-list li > * {
background: var(--list-background);
padding: 0.1rem 0.5rem;
}
#countdown-list li > :first-child {
padding-left: 1rem;
border-top-left-radius: 0.25rem;
border-bottom-left-radius: 0.25rem;
}
#countdown-list li > :last-child {
padding-right: 1rem;
border-top-right-radius: 0.25rem;
border-bottom-right-radius: 0.25rem;
}
#countdown-list input[type="checkbox"] {
width: 1.25rem;
height: 1.25rem;
justify-self: center;
}
#countdown-list .description {
/* color: hsl(0, 0%, 30%); */
min-width: 10rem;
max-width: min(40vw, 30rem);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#countdown-list .elapsed {
font-weight: bold;
color: var(--elapsed-color);
text-align: right;
min-width: 8rem;
}
#countdown-list .target {
color: var(--text-tertiary);
white-space: nowrap;
max-width: min(30vw, 20rem);
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 634px) {
#countdown-list {
grid-template-columns: 1fr;
gap: 0;
}
#countdown-list li {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto auto;
gap: 0.5rem;
margin-bottom: 0.5rem;
background: var(--list-background);
padding: 0.75rem;
border-radius: 0.25rem;
}
#countdown-list li > * {
background: transparent;
padding: 0;
}
#countdown-list li > :first-child,
#countdown-list li > :last-child {
padding: 0;
border-radius: 0;
}
#countdown-list input[type="checkbox"] {
grid-row: 1 / 3;
align-self: start;
margin-top: 0.25rem;
}
#countdown-list .description {
grid-column: 2;
grid-row: 1;
min-width: 0;
max-width: none;
font-weight: 600;
}
#countdown-list .elapsed {
grid-column: 2;
grid-row: 2;
text-align: left;
min-width: 0;
font-size: 0.9rem;
}
#countdown-list .target {
grid-column: 2;
grid-row: 2;
justify-self: end;
max-width: none;
font-size: 0.9rem;
}
}
#countdown-list .description {
/* color: hsl(0, 0%, 30%); */
flex: 1;
}
#countdown-list .target {
color: hsl(0, 0%, 40%);
}
#countdown-list .past {
color: var(--past-color);
}
/* #endregion Countdown List Styles */
/* #region Dialog Styles */
dialog {
padding: .5rem;
border: 3px solid var(--border-color);
border-radius: var(--border-radius);
max-width: 100%;
min-width: 10em;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin: 0;
}
.main-input {
display: block;
#description {
width: 100%;
}
#target-date {
width: min-content;
}
#target-time {
width: min-content;
}
div {
margin-top: 0.5em;
}
}
.adjustment-section {
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
padding: 0.5rem;
/* margin: 0.5em 0; */
min-width: min-content;
width: 100%;
}
.adjustment-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.75rem 1rem;
label {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.9rem;
input {
width: 3em;
}
}
}
.adjustment-row {
display: flex;
gap: 0.5rem;
align-items: center;
flex-wrap: wrap;
margin-right: 0.5em;
label {
display: flex;
flex-direction: column;
gap: 0.25rem;
text-align: center;
}
input[type="radio"] {
margin-right: 0.25rem;
}
}
.result-section {
background: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: 0.25rem;
padding: 0.5rem;
margin-bottom: 0.5rem;
output {
display: block;
}
.result-datetime {
font-weight: bold;
}
.result-duration {
font-size: 0.9rem;
color: hsl(0, 0%, 40%);
}
}
.dialog-buttons {
display: flex;
gap: 0.5rem;
justify-content: flex-end;
button {
padding: 0.5rem 1rem;
font-size: 1rem;
cursor: pointer;
border-radius: var(--border-radius);
border: 1px solid var(--border-color);
}
button[type="submit"] {
background: var(--button-primary-color);
color: white;
border-color: var(--border-color);
}
button[type="reset"] {
background: var(--button-secondary-color);
}
.dialog-buttons button[type="button"] {
background: var(--button-secondary-color);
}
}
/* #endregion Dialog Styles */
/* For accessibility: visually hidden class */
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
</style>
<h2>Countdown List</h2>
<div class="controls">
<button id="add-countdown-btn" type="button">Add Countdown</button>
<div class="led-bar" id="led-bar" aria-label="Update timer">
<div class="led-segment"></div>
<div class="led-segment"></div>
<div class="led-segment"></div>
<div class="led-segment"></div>
<div class="led-segment"></div>
<div class="led-segment"></div>
<div class="led-segment"></div>
<div class="led-segment"></div>
<div class="led-segment"></div>
<div class="led-segment"></div>
</div>
</div>
<ul id="countdown-list" aria-live="polite"></ul>
<dialog id="countdown-dialog" aria-labelledby="dialog-title">
<h3 id="dialog-title">Add a new timer</h3>
<form id="countdown-form" method="dialog">
<div class="main-input">
<label for="description" class="visually-hidden">Description:</label>
<input type="text" id="description" placeholder="Enter description" title="Description" required>
<div>
<label for="target-date" class="visually-hidden">Date:</label>
<input type="date" id="target-date" title="Date" required>
<label for="target-time" class="visually-hidden">Time:</label>
<input type="time" id="target-time" title="Time" required>
</div>
</div>
<div class="adjustment-section">
<div class="adjustment-row">
<label>
<input type="radio" name="adjust-mode" value="add" checked>
Add
</label>
<label>
<input type="radio" name="adjust-mode" value="subtract">
Subtract
</label>
</div>
<div class="adjustment-grid">
<label>
Years:
<input type="number" id="adjust-years" min="0" value="0">
</label>
<label>
Weeks:
<input type="number" id="adjust-weeks" min="0" value="0">
</label>
<label>
Days:
<input type="number" id="adjust-days" min="0" value="0">
</label>
<label>
Hours:
<input type="number" id="adjust-hours" min="0" max="23" value="0">
</label>
<label>
Minutes:
<input type="number" id="adjust-minutes" min="0" max="59" value="0">
</label>
<label>
Seconds:
<input type="number" id="adjust-seconds" min="0" max="59" value="0">
</label>
</div>
</div>
<div class="result-section">
<output class="result-datetime" id="result-datetime" title="Target date/time">--</output>
<output id="result-duration" title="Duration from now">--</output>
</div>
<div class="dialog-buttons">
<button type="submit">Add</button>
<button type="reset">Reset</button>
<button type="button" id="cancel-btn">Cancel</button>
</div>
</form>
</dialog>
... continued in next post ...