Fix styling issues
This commit is contained in:
parent
b31c306b0a
commit
f01457dfba
10 changed files with 141 additions and 107 deletions
|
@ -7,6 +7,7 @@ import './script/pages/app-home';
|
|||
import './script/components/active-timer';
|
||||
import './script/components/counter';
|
||||
import './script/components/header';
|
||||
import './script/components/icons/icon-add';
|
||||
import './script/components/icons/icon-back';
|
||||
import './script/components/icons/icon-forward';
|
||||
import './script/components/icons/icon-navigation';
|
||||
|
|
|
@ -12,9 +12,6 @@ export class AppHeader extends LitElement {
|
|||
static get styles() {
|
||||
return css`
|
||||
* {
|
||||
--neutral-fill-stealth-rest: rgba(255, 255, 255, 0);
|
||||
--neutral-fill-stealth-hover: rgba(255, 255, 255, 0.2);
|
||||
--neutral-fill-stealth-active: rgba(255, 255, 255, 0.4);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
|
20
src/script/components/icons/icon-add.ts
Normal file
20
src/script/components/icons/icon-add.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
|
||||
// manually in-lining the svg until vite supports it
|
||||
@customElement('icon-add')
|
||||
export class AddIcon extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
svg {
|
||||
display: block;
|
||||
color: var(--foreground-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
render() {
|
||||
return html`
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 2.5a.5.5 0 00-1 0V9H2.5a.5.5 0 000 1H9v6.5a.5.5 0 001 0V10h6.5a.5.5 0 000-1H10V2.5z"/></svg>
|
||||
`;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
// @ts-ignore
|
||||
import Navigation from '@fluentui/svg-icons/icons/navigation_20_regular.svg';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { LitElement, css, html } from 'lit';
|
||||
import { property, customElement, query } from 'lit/decorators.js';
|
||||
// @ts-ignore
|
||||
import Add from '@fluentui/svg-icons/icons/add_20_regular.svg';
|
||||
import { IntervalTimer } from '../timer';
|
||||
import { SelectTimerEvent } from '../select-timer-event';
|
||||
|
||||
|
@ -70,54 +68,16 @@ export class AppSidebar extends LitElement {
|
|||
display: block;
|
||||
}
|
||||
|
||||
pwa-install {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
font-family: var(--body-font);
|
||||
font-size: var(--type-ramp-base-font-size);
|
||||
line-height: var(--type-ramp-base-line-height);
|
||||
font-weight: initial;
|
||||
font-variation-settings: var(--type-ramp-base-font-variations);
|
||||
height: calc((var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px);
|
||||
min-width: calc((var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px);
|
||||
color: var(--neutral-foreground-rest);
|
||||
border-radius: calc(var(--control-corner-radius) * 1px);
|
||||
fill: currentcolor;
|
||||
cursor: pointer;
|
||||
fluent-option {
|
||||
--design-unit: 6;
|
||||
}
|
||||
|
||||
pwa-install::part(openButton) {
|
||||
background: var(--neutral-fill-stealth-rest);
|
||||
border: calc(var(--stroke-width) * 1px) solid transparent;
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
padding: 0 calc((10 + (var(--design-unit) * 2 * var(--density))) * 1px);
|
||||
white-space: nowrap;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
border-radius: inherit;
|
||||
fill: inherit;
|
||||
cursor: inherit;
|
||||
font-family: inherit;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
pwa-install::part(openButton):hover {
|
||||
background: var(--neutral-fill-stealth-hover);
|
||||
}
|
||||
|
||||
fluent-button, pwa-install {
|
||||
box-sizing: border-box;
|
||||
height: 42px;
|
||||
fluent-button {
|
||||
--design-unit: 6;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
fluent-button, button, pwa-install::part(openButton) {
|
||||
fluent-button::part(control) {
|
||||
justify-content: start;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -129,18 +89,6 @@ export class AppSidebar extends LitElement {
|
|||
|
||||
constructor() {
|
||||
super();
|
||||
window.addEventListener('beforeinstallprompt', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
updated() {
|
||||
// Stupid hack to get the button to be left-aligned
|
||||
const button: HTMLButtonElement | null | undefined = this.fButton?.shadowRoot?.querySelector('button');
|
||||
if (button) {
|
||||
button.setAttribute('style', 'justify-content: start;');
|
||||
}
|
||||
}
|
||||
|
||||
private toggleVisibility() {
|
||||
|
@ -175,13 +123,15 @@ export class AppSidebar extends LitElement {
|
|||
<fluent-option
|
||||
@click=${() => this.selectTimer(timer.id!)}
|
||||
selected=${timer.id === this.selectedTimer}
|
||||
value=${timer.name}>${timer.name}</fluent-option>
|
||||
value=${timer.name}>
|
||||
${timer.name}<br />${timer.description || ''}
|
||||
</fluent-option>
|
||||
`;
|
||||
})}
|
||||
</fluent-listbox>
|
||||
<fluent-divider></fluent-divider>
|
||||
<fluent-button appearance="stealth" @click="${this.newTimer}">
|
||||
<img slot="start" src="${Add}" aria-hidden="true" />
|
||||
<icon-add slot="start"></icon-add>
|
||||
New Timer
|
||||
</fluent-button>
|
||||
</div>
|
||||
|
|
|
@ -17,8 +17,10 @@ export class TimerFormDialog extends LitElement {
|
|||
display: flex;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
max-height: var(--dialog-height);
|
||||
max-width: var(--dialog-width);
|
||||
height: var(--dialog-height);
|
||||
width: var(--dialog-width);
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
|
@ -32,9 +34,16 @@ export class TimerFormDialog extends LitElement {
|
|||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
fluent-button {
|
||||
margin: 1em 0;
|
||||
::part(control) {
|
||||
--dialog-height: 764px;
|
||||
box-sizing: border-box;
|
||||
max-height: 100vh;
|
||||
max-width: 100vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -88,10 +97,7 @@ export class TimerFormDialog extends LitElement {
|
|||
}
|
||||
|
||||
private async save() {
|
||||
let id: string | undefined = this.timerId?.value;
|
||||
if (!id) {
|
||||
id = undefined;
|
||||
}
|
||||
const id: string = this.timerId?.value || '';
|
||||
const name = this.timerName?.value;
|
||||
if (!name) {
|
||||
// TODO: Show errors in form
|
||||
|
@ -99,7 +105,7 @@ export class TimerFormDialog extends LitElement {
|
|||
return;
|
||||
}
|
||||
const timer = new IntervalTimer(name);
|
||||
timer.id = this.timer?.id;
|
||||
timer.id = Number.parseInt(id);
|
||||
timer.description = this.timerDescription?.value;
|
||||
timer.warmUp = parseDuration(this.timerWarmUp?.value);
|
||||
timer.lowIntensity = parseDuration(this.timerLowIntensity?.value);
|
||||
|
@ -115,14 +121,44 @@ export class TimerFormDialog extends LitElement {
|
|||
this.toggleVisibility();
|
||||
}
|
||||
|
||||
private async delete() {
|
||||
const id = Number.parseInt(this.timerId?.value || '');
|
||||
await this.timerService?.delete(id);
|
||||
this.toggleVisibility();
|
||||
}
|
||||
|
||||
private deleteButton() {
|
||||
if (this.timer?.id) {
|
||||
return html`
|
||||
<fluent-button
|
||||
appearance="outline"
|
||||
tabindex="0"
|
||||
@click=${this.delete}
|
||||
style="margin-top: 1em;">Delete</fluent-button>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
private durationString(duration: number | undefined) {
|
||||
if (!duration) {
|
||||
return '';
|
||||
} else {
|
||||
return durationString(duration);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let body;
|
||||
if (this.saving) {
|
||||
|
||||
return html`
|
||||
<div class="dialog">
|
||||
<p>Saving...</p>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
const title = this.timer?.id ? 'Edit Timer' : 'New Timer';
|
||||
body = html`
|
||||
<div class="dialog">
|
||||
<div class="dialog ${this.timer?.id ? 'tall' : ''}">
|
||||
<h2>${title}</h2>
|
||||
<form @submit=${this.save}>
|
||||
<input
|
||||
|
@ -145,31 +181,31 @@ export class TimerFormDialog extends LitElement {
|
|||
appearance="outline"
|
||||
placeholder="05:00"
|
||||
pattern="${this.durationPattern}"
|
||||
.value=${durationString(this.timer?.warmUp)}>Warm Up</fluent-text-field>
|
||||
.value=${this.durationString(this.timer?.warmUp)}>Warm Up</fluent-text-field>
|
||||
<fluent-text-field
|
||||
id="timer-low"
|
||||
appearance="outline"
|
||||
placeholder="00:30"
|
||||
pattern="${this.durationPattern}"
|
||||
.value=${durationString(this.timer?.lowIntensity)}>Low Intensity</fluent-text-field>
|
||||
.value=${this.durationString(this.timer?.lowIntensity)}>Low Intensity</fluent-text-field>
|
||||
<fluent-text-field
|
||||
id="timer-hi"
|
||||
appearance="outline"
|
||||
placeholder="01:00"
|
||||
pattern="${this.durationPattern}"
|
||||
.value=${durationString(this.timer?.highIntensity)}>High Intensity</fluent-text-field>
|
||||
.value=${this.durationString(this.timer?.highIntensity)}>High Intensity</fluent-text-field>
|
||||
<fluent-text-field
|
||||
id="timer-rest"
|
||||
appearance="outline"
|
||||
placeholder="01:00"
|
||||
pattern="${this.durationPattern}"
|
||||
.value=${durationString(this.timer?.rest)}>Rest</fluent-text-field>
|
||||
.value=${this.durationString(this.timer?.rest)}>Rest</fluent-text-field>
|
||||
<fluent-text-field
|
||||
id="timer-cool"
|
||||
appearance="outline"
|
||||
placeholder="05:00"
|
||||
pattern="${this.durationPattern}"
|
||||
.value=${durationString(this.timer?.coolDown)}>Cooldown</fluent-text-field>
|
||||
.value=${this.durationString(this.timer?.coolDown)}>Cooldown</fluent-text-field>
|
||||
<fluent-text-field
|
||||
id="timer-sets"
|
||||
appearance="outline"
|
||||
|
@ -180,14 +216,19 @@ export class TimerFormDialog extends LitElement {
|
|||
appearance="outline"
|
||||
placeholder="2"
|
||||
.value=${this.timer?.rounds}>Rounds</fluent-text-field>
|
||||
<fluent-button
|
||||
appearance="accent"
|
||||
tabindex="0"
|
||||
@click=${this.save}
|
||||
style="margin: 1em 0;">Save</fluent-button>
|
||||
<fluent-button appearance="outline" tabindex="0" @click=${this.toggleVisibility}>Cancel</fluent-button>
|
||||
${this.deleteButton()}
|
||||
</form>
|
||||
<fluent-button appearance="accent" tabindex="0" @click=${this.save}>Save</fluent-button>
|
||||
<fluent-button appearance="outline" tabindex="0" @click=${this.toggleVisibility}>Cancel</fluent-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<fluent-dialog ?hidden=${!this.visible} trap-focus modal>
|
||||
<fluent-dialog ?hidden=${!this.visible} trap-focus modal class=${this.timer?.id ? 'tall' : ''}>
|
||||
${body}
|
||||
</fluent-dialog>
|
||||
`;
|
||||
|
|
|
@ -23,6 +23,11 @@ export class AppHome extends LitElement {
|
|||
active-timer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -38,16 +43,6 @@ export class AppHome extends LitElement {
|
|||
});
|
||||
}
|
||||
|
||||
share() {
|
||||
if ((navigator as any).share) {
|
||||
(navigator as any).share({
|
||||
title: 'PWABuilder pwa-starter',
|
||||
text: 'Check out the PWABuilder pwa-starter!',
|
||||
url: 'https://github.com/pwa-builder/pwa-starter',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async closeEditor() {
|
||||
this.editTimer = undefined;
|
||||
this.timers = await this.timerService?.getAll() || [];
|
||||
|
@ -56,6 +51,14 @@ export class AppHome extends LitElement {
|
|||
}
|
||||
}
|
||||
|
||||
private editButton() {
|
||||
if (this.selectedTimer) {
|
||||
return html`
|
||||
<fluent-button appearance="stealth" slot="actions" @click=${() => this.editTimer = this.selectedTimer}>Edit</fluent-button>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let body;
|
||||
const timer = this.timers.filter(t => t.id === this.selectedTimer)[0] || this.timers[0];
|
||||
|
@ -65,7 +68,14 @@ export class AppHome extends LitElement {
|
|||
`;
|
||||
} else {
|
||||
body = html`
|
||||
<p>Create a timer to begin</p>
|
||||
<p>
|
||||
Create a timer to begin<br />
|
||||
<fluent-button
|
||||
appearance="stealth"
|
||||
@click=${() => this.editTimer = -1}>
|
||||
New Timer
|
||||
</fluent-button>
|
||||
</p>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -77,7 +87,7 @@ export class AppHome extends LitElement {
|
|||
.selectedTimer=${this.selectedTimer}
|
||||
@newtimer=${() => this.editTimer = -1}
|
||||
@selecttimer=${(e: SelectTimerEvent) => this.selectedTimer = e.timerId}>
|
||||
<fluent-button appearance="stealth" slot="actions" @click=${() => this.editTimer = timer.id}>Edit</fluent-button>
|
||||
${this.editButton()}
|
||||
</app-header>
|
||||
${body}
|
||||
<timer-form-dialog
|
||||
|
|
|
@ -5,7 +5,7 @@ import { IDBPDatabase } from 'idb';
|
|||
export interface TimerService {
|
||||
getAll(): Promise<IntervalTimer[]>;
|
||||
save(timer: IntervalTimer): Promise<IntervalTimer>;
|
||||
delete(timer: IntervalTimer): Promise<void>;
|
||||
delete(timer: IntervalTimer | number): Promise<void>;
|
||||
}
|
||||
|
||||
const dbName = 'interval-timer';
|
||||
|
@ -24,6 +24,9 @@ class IDBTimerService implements TimerService {
|
|||
}
|
||||
|
||||
async save(timer: IntervalTimer): Promise<IntervalTimer> {
|
||||
if (!timer.id) {
|
||||
delete timer.id;
|
||||
}
|
||||
const key = await this.db.put(storeName, timer);
|
||||
return {
|
||||
...timer,
|
||||
|
|
|
@ -29,7 +29,7 @@ export function className(phase: Phase) {
|
|||
}
|
||||
|
||||
export function durationString(n: number | undefined): string {
|
||||
if (!n) return '00:00';
|
||||
if (typeof n !== 'number') return '';
|
||||
let remainder = n;
|
||||
let s = '';
|
||||
if (remainder > 60) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/*
|
||||
This file is used for all of your global styles and CSS variables.
|
||||
Check here https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties for more info on using CSS variables.
|
||||
|
@ -9,7 +8,8 @@
|
|||
--foreground-color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
font-family: var(--font-family);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
@ -20,12 +20,14 @@ html, body {
|
|||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
fluent-design-system-provider, app-index {
|
||||
fluent-design-system-provider,
|
||||
app-index {
|
||||
height: 100%;
|
||||
color: var(--foreground-color);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
html,
|
||||
body {
|
||||
background: #181818;
|
||||
|
@ -74,6 +76,7 @@ fluent-design-system-provider, app-index {
|
|||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
|
||||
html,
|
||||
body {
|
||||
background: white;
|
||||
|
@ -82,7 +85,7 @@ fluent-design-system-provider, app-index {
|
|||
|
||||
fluent-design-system-provider {
|
||||
--foreground-color: black;
|
||||
--fill-color: #edebe9;
|
||||
--fill-color: #f1f1f1;
|
||||
--background-color: white;
|
||||
|
||||
--accent-base-color: #F2C812;
|
||||
|
@ -92,14 +95,25 @@ fluent-design-system-provider, app-index {
|
|||
--accent-fill-active: #F4D033;
|
||||
--accent-fill-selected: #C7A50F;
|
||||
|
||||
--neutral-foreground-rest: #e5e5e5;
|
||||
--accent-foreground-rest: var(--foreground-color);
|
||||
--accent-stroke-control-rest: linear-gradient(#F5D447 90%, #D2AD0F 100%);
|
||||
--accent-stroke-control-hover: linear-gradient(#F5D447 90%, #D2AD0F 100%);
|
||||
--accent-stroke-control-active: #F5D447;
|
||||
--accent-stroke-control-focus: linear-gradient(#F5D447 90%, #D2AD0F 100%);
|
||||
--foreground-on-accent-rest: #000000;
|
||||
--foreground-on-accent-hover: #000000;
|
||||
--foreground-on-accent-active: #000000;
|
||||
--neutral-foreground-rest: #2B2B2B;
|
||||
--neutral-fill-input-rest: #e5e5e5;
|
||||
--neutral-fill-input-hover: white;
|
||||
--neutral-fill-stealth-rest: #e5e5e5;
|
||||
|
||||
--neutral-fill-stealth-rest: rgba(0, 0, 0, 0);
|
||||
--neutral-fill-stealth-hover: rgba(0, 0, 0, 0.2);
|
||||
--neutral-fill-stealth-active: rgba(0, 0, 0, 0.4);
|
||||
--neutral-fill-rest: #5d5d5d;
|
||||
|
||||
--neutral-fill-input-active: #e5e5e5;
|
||||
--timer-background-red: #FF0909;
|
||||
--timer-background-green: #1cb91c;
|
||||
--timer-background-yellow: #F2C812;
|
||||
--timer-background-blue: #0091ff;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue