From 3607ce237a9ec44a220e0979ab6ff9109f93f68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cchrisshank=E2=80=9D?= Date: Thu, 5 Dec 2024 14:48:53 -0800 Subject: [PATCH] css ttl --- demo/src/record-player.ts | 400 +++++++++++++++++------------------ src/common/tags.ts | 8 +- src/folk-event-propagator.ts | 5 +- src/folk-ink.ts | 11 +- src/folk-map.ts | 13 +- src/folk-shape.ts | 7 +- src/folk-spreadsheet.ts | 197 ++++++++--------- src/folk-toolbar.ts | 5 +- 8 files changed, 325 insertions(+), 321 deletions(-) diff --git a/demo/src/record-player.ts b/demo/src/record-player.ts index fe5091d..17a9356 100644 --- a/demo/src/record-player.ts +++ b/demo/src/record-player.ts @@ -1,219 +1,217 @@ // Ported from https://github.com/bitu467/record-player +import { css } from '../../src/common/tags'; -const styles = new CSSStyleSheet(); -styles.replaceSync(` -::slotted(*) { - display: none; -} - -:host { - display: block; -} - -.player { - background-color: #d52831; - width: 330px; - height: 190px; - position: absolute; - transform: translate(-50%, -50%); - left: 50%; - top: 50%; - border-radius: 10px; - box-shadow: 0 8px 0 0 #be2728; - margin-top: -4px; -} - -.record { - width: 175px; - height: 175px; - background-color: #181312; - position: absolute; - border-radius: 50%; - top: 10px; - left: 20px; - display: flex; - justify-content: center; - align-items: center; - animation: spin 3s linear infinite; - animation-play-state: paused; -} - -.record::before, -.record::after { - content: ''; - position: absolute; - border: 5px solid transparent; - border-top-color: #2c2424; - border-bottom-color: #2c2424; - border-radius: 50%; -} - -.record::before { - width: 135px; - height: 135px; -} - -.record:after { - width: 95px; - height: 95px; -} - -.label { - height: 15px; - width: 15px; - background-color: #181312; - border: 20px solid #ff8e00; - border-radius: 50%; -} - -.tone-arm { - height: 90px; - width: 6px; - background-color: #ffffff; - position: absolute; - top: 25px; - right: 95px; - transform-origin: top; - - --move-time: 3s; - animation-fill-mode: forwards; - animation-timing-function: linear; -} - -.control { - background-color: #181312; - width: 17px; - height: 17px; - border: 10px solid #2c2c2c; - border-radius: 50%; - position: absolute; - top: -16px; - left: -16px; -} - -.tone-arm::before { - content: ''; - position: absolute; - height: 40px; - width: 6px; - background-color: #ffffff; - transform: rotate(30deg); - bottom: -36px; - right: 10px; -} - -.tone-arm::after { - content: ''; - position: absolute; - height: 0px; - width: 10px; - border-top: 18px solid #b2aea6; - border-left: 2px solid transparent; - border-right: 2px solid transparent; - top: 108px; - right: 12.5px; - transform: rotate(30deg); -} - -.btn { - width: 28px; - height: 28px; - background-color: #ed5650; - border-radius: 50%; - position: absolute; - bottom: 20px; - right: 30px; - border: none; - border: 3.5px solid rgb(190, 39, 42); - outline: none; - cursor: pointer; -} - -.slider { - -webkit-appearance: none; - appearance: none; - transform: rotate(-90deg); - width: 90px; - height: 7px; - position: absolute; - left: 233px; - top: 60px; - background-color: #be272a; - outline: none; - border-radius: 3px; - border: 6px solid #ed5650; -} - -.slider::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 10px; - height: 12px; - background-color: #ffffff; - cursor: pointer; -} - -:host(:state(playing)) .tone-arm { - animation: - ready-arm var(--move-time), - move-arm var(--duration) var(--move-time), - reset-arm var(--move-time) calc(var(--duration) + var(--move-time)); -} - -:host(:state(playing)) .record { - animation-play-state: running; -} - -@keyframes ready-arm { - 20% { - transform: rotateX(20deg); +const styles = css` + ::slotted(*) { + display: none; } - 70% { - transform: rotateX(20deg); - rotate: 14deg; + :host { + display: block; } - 100% { - rotate: 14deg; - } -} - -@keyframes move-arm { - from { - rotate: 14deg; + .player { + background-color: #d52831; + width: 330px; + height: 190px; + position: absolute; + transform: translate(-50%, -50%); + left: 50%; + top: 50%; + border-radius: 10px; + box-shadow: 0 8px 0 0 #be2728; + margin-top: -4px; } - to { - rotate: 42deg; - } -} - -@keyframes reset-arm { - 0% { - rotate: 42deg; + .record { + width: 175px; + height: 175px; + background-color: #181312; + position: absolute; + border-radius: 50%; + top: 10px; + left: 20px; + display: flex; + justify-content: center; + align-items: center; + animation: spin 3s linear infinite; + animation-play-state: paused; } - 20% { - transform: rotateX(20deg); - rotate: 42deg; + .record::before, + .record::after { + content: ''; + position: absolute; + border: 5px solid transparent; + border-top-color: #2c2424; + border-bottom-color: #2c2424; + border-radius: 50%; } - 80% { - transform: rotateX(20deg); - } -} - -@keyframes spin { - from { - rotate: 0deg; + .record::before { + width: 135px; + height: 135px; } - to { - rotate: 360deg; + .record:after { + width: 95px; + height: 95px; } -} -`); + + .label { + height: 15px; + width: 15px; + background-color: #181312; + border: 20px solid #ff8e00; + border-radius: 50%; + } + + .tone-arm { + height: 90px; + width: 6px; + background-color: #ffffff; + position: absolute; + top: 25px; + right: 95px; + transform-origin: top; + + --move-time: 3s; + animation-fill-mode: forwards; + animation-timing-function: linear; + } + + .control { + background-color: #181312; + width: 17px; + height: 17px; + border: 10px solid #2c2c2c; + border-radius: 50%; + position: absolute; + top: -16px; + left: -16px; + } + + .tone-arm::before { + content: ''; + position: absolute; + height: 40px; + width: 6px; + background-color: #ffffff; + transform: rotate(30deg); + bottom: -36px; + right: 10px; + } + + .tone-arm::after { + content: ''; + position: absolute; + height: 0px; + width: 10px; + border-top: 18px solid #b2aea6; + border-left: 2px solid transparent; + border-right: 2px solid transparent; + top: 108px; + right: 12.5px; + transform: rotate(30deg); + } + + .btn { + width: 28px; + height: 28px; + background-color: #ed5650; + border-radius: 50%; + position: absolute; + bottom: 20px; + right: 30px; + border: none; + border: 3.5px solid rgb(190, 39, 42); + outline: none; + cursor: pointer; + } + + .slider { + -webkit-appearance: none; + appearance: none; + transform: rotate(-90deg); + width: 90px; + height: 7px; + position: absolute; + left: 233px; + top: 60px; + background-color: #be272a; + outline: none; + border-radius: 3px; + border: 6px solid #ed5650; + } + + .slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 10px; + height: 12px; + background-color: #ffffff; + cursor: pointer; + } + + :host(:state(playing)) .tone-arm { + animation: ready-arm var(--move-time), move-arm var(--duration) var(--move-time), + reset-arm var(--move-time) calc(var(--duration) + var(--move-time)); + } + + :host(:state(playing)) .record { + animation-play-state: running; + } + + @keyframes ready-arm { + 20% { + transform: rotateX(20deg); + } + + 70% { + transform: rotateX(20deg); + rotate: 14deg; + } + + 100% { + rotate: 14deg; + } + } + + @keyframes move-arm { + from { + rotate: 14deg; + } + + to { + rotate: 42deg; + } + } + + @keyframes reset-arm { + 0% { + rotate: 42deg; + } + + 20% { + transform: rotateX(20deg); + rotate: 42deg; + } + + 80% { + transform: rotateX(20deg); + } + } + + @keyframes spin { + from { + rotate: 0deg; + } + + to { + rotate: 360deg; + } + } +`; export class RecordPlayer extends HTMLElement { static tagName = 'record-player'; diff --git a/src/common/tags.ts b/src/common/tags.ts index 4ab79dc..744e4c4 100644 --- a/src/common/tags.ts +++ b/src/common/tags.ts @@ -4,6 +4,10 @@ export const vert = String.raw; export const frag = String.raw; -export const css = String.raw; - export const html = String.raw; + +export function css(strings: TemplateStringsArray, ...values: any[]) { + const styles = new CSSStyleSheet(); + styles.replaceSync(String.raw(strings, ...values)); + return styles; +} diff --git a/src/folk-event-propagator.ts b/src/folk-event-propagator.ts index bf55150..d1aa527 100644 --- a/src/folk-event-propagator.ts +++ b/src/folk-event-propagator.ts @@ -3,8 +3,7 @@ import { FolkRope } from './folk-rope.ts'; import * as parser from '@babel/parser'; import type { Node } from '@babel/types'; -const styles = new CSSStyleSheet(); -styles.replaceSync(css` +const styles = css` :host { display: block; position: absolute; @@ -27,7 +26,7 @@ styles.replaceSync(css` translate: -50% -50%; border-radius: 5px; } -`); +`; export class FolkEventPropagator extends FolkRope { static override tagName = 'folk-event-propagator'; diff --git a/src/folk-ink.ts b/src/folk-ink.ts index 87953d5..d2b9c20 100644 --- a/src/folk-ink.ts +++ b/src/folk-ink.ts @@ -1,4 +1,5 @@ import { getStroke, StrokeOptions } from 'perfect-freehand'; +import { css } from './common/tags'; export type Point = [x: number, y: number, pressure: number]; @@ -6,9 +7,9 @@ export type Stroke = number[][]; // TODO: look into any-pointer media queries to tell if the user has a mouse or touch screen // https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer -const styles = new CSSStyleSheet(); -styles.replaceSync(` - :host, svg { +const styles = css` + :host, + svg { display: block; height: 100%; width: 100%; @@ -16,12 +17,12 @@ styles.replaceSync(` pointer-events: none; } - :host(:state(drawing)) { + :host(:state(drawing)) { position: fixed; inset: 0 0 0 0; cursor: var(--tracing-cursor, crosshair); } -`); +`; declare global { interface HTMLElementTagNameMap { diff --git a/src/folk-map.ts b/src/folk-map.ts index b90a800..8632944 100644 --- a/src/folk-map.ts +++ b/src/folk-map.ts @@ -2,18 +2,19 @@ import { LatLng, LatLngExpression, LeafletEvent, map, Map, tileLayer } from 'lea // @ts-ignore // Vite specific import :( -import css from 'leaflet/dist/leaflet.css?inline'; -const styles = new CSSStyleSheet(); -styles.replaceSync(`${css} +import leafletCSS from 'leaflet/dist/leaflet.css?inline'; +import { css } from './common/tags'; +const styles = css` + ${leafletCSS} :host { display: block; } - + :host > div { height: 100%; width: 100%; - } -`); + } +`; export class RecenterEvent extends Event { constructor() { diff --git a/src/folk-shape.ts b/src/folk-shape.ts index 019dbc0..975b997 100644 --- a/src/folk-shape.ts +++ b/src/folk-shape.ts @@ -73,8 +73,7 @@ export class TransformEvent extends Event { export type Dimension = number | 'auto'; -const styles = new CSSStyleSheet(); -styles.replaceSync(css` +const styles = css` :host { display: block; position: absolute; @@ -209,7 +208,7 @@ styles.replaceSync(css` opacity: 0; cursor: default; } -`); +`; declare global { interface HTMLElementTagNameMap { @@ -229,7 +228,7 @@ export class FolkShape extends HTMLElement { #shadow = this.attachShadow({ mode: 'open' }); #internals = this.attachInternals(); - #dynamicStyles = new CSSStyleSheet(); + #dynamicStyles = css``; #type = (this.getAttribute('type') || 'rectangle') as Shape; get type(): Shape { diff --git a/src/folk-spreadsheet.ts b/src/folk-spreadsheet.ts index 0dde578..5717e26 100644 --- a/src/folk-spreadsheet.ts +++ b/src/folk-spreadsheet.ts @@ -1,115 +1,118 @@ -const styles = new CSSStyleSheet(); +import { css } from './common/tags'; + // hardcoded column and row numbers -styles.replaceSync(` -:host { - --column-number: 10; - --row-number: 10; - --cell-height: 1.75rem; - --cell-width: 100px; - --border-color: #e1e1e1; - border: solid 1px var(--border-color); - box-sizing: border-box; - display: grid; - font-family: monospace; - grid-template-columns: 50px repeat(var(--column-number), var(--cell-width)); - grid-template-rows: repeat(calc(var(--row-number) + 1), var(--cell-height)); - position: relative; - overflow: scroll; - scroll-snap-type: both mandatory; - scroll-padding-top: var(--cell-height); - scroll-padding-left: 50px; -} - -textarea { - background-color: rgba(255, 255, 255, 0.75); - grid-column: var(--text-column, 0); - grid-row: var(--text-row, 0); - z-index: 11; -} - -s-columns { - box-shadow: 0px 3px 5px 0px rgba(173, 168, 168, 0.6); - display: grid; - grid-column: 2 / -1; - grid-row: 1; - grid-template-columns: subgrid; - grid-template-rows: subgrid; - position: sticky; - top: 0; - z-index: 2; -} - -s-rows { - box-shadow: 3px 0px 5px 0px rgba(173, 168, 168, 0.4); - display: grid; - grid-column: 1; - grid-row: 2 / -1; - grid-template-columns: subgrid; - grid-template-rows: subgrid; - position: sticky; - left: 0; - z-index: 2; - - s-header { - font-size: 0.75rem; +const styles = css` + :host { + --column-number: 10; + --row-number: 10; + --cell-height: 1.75rem; + --cell-width: 100px; + --border-color: #e1e1e1; + border: solid 1px var(--border-color); + box-sizing: border-box; + display: grid; + font-family: monospace; + grid-template-columns: 50px repeat(var(--column-number), var(--cell-width)); + grid-template-rows: repeat(calc(var(--row-number) + 1), var(--cell-height)); + position: relative; + overflow: scroll; + scroll-snap-type: both mandatory; + scroll-padding-top: var(--cell-height); + scroll-padding-left: 50px; } -} -s-header { - background-color: #f8f9fa; - display: flex; - padding: 0.125rem 0.5rem; - align-items: center; - justify-content: center; + textarea { + background-color: rgba(255, 255, 255, 0.75); + grid-column: var(--text-column, 0); + grid-row: var(--text-row, 0); + z-index: 11; + } - &[empty] { - box-shadow: 3px 3px 3px 0px rgba(173, 168, 168, 0.4); - grid-area: 1; + s-columns { + box-shadow: 0px 3px 5px 0px rgba(173, 168, 168, 0.6); + display: grid; + grid-column: 2 / -1; + grid-row: 1; + grid-template-columns: subgrid; + grid-template-rows: subgrid; position: sticky; top: 0; + z-index: 2; + } + + s-rows { + box-shadow: 3px 0px 5px 0px rgba(173, 168, 168, 0.4); + display: grid; + grid-column: 1; + grid-row: 2 / -1; + grid-template-columns: subgrid; + grid-template-rows: subgrid; + position: sticky; left: 0; - z-index: 3; + z-index: 2; + + s-header { + font-size: 0.75rem; + } } - &:state(selected) { - background-color: #d3e2fd; - font-weight: bold; + s-header { + background-color: #f8f9fa; + display: flex; + padding: 0.125rem 0.5rem; + align-items: center; + justify-content: center; + + &[empty] { + box-shadow: 3px 3px 3px 0px rgba(173, 168, 168, 0.4); + grid-area: 1; + position: sticky; + top: 0; + left: 0; + z-index: 3; + } + + &:state(selected) { + background-color: #d3e2fd; + font-weight: bold; + } } -} -s-body { - display: grid; - grid-column: 2 / -1; - grid-row: 2 / -1; - grid-template-columns: subgrid; - grid-template-rows: subgrid; + s-body { + display: grid; + grid-column: 2 / -1; + grid-row: 2 / -1; + grid-template-columns: subgrid; + grid-template-rows: subgrid; } - -s-columns, s-rows, s-body { - background-color: var(--border-color); - gap: 1px; -} -::slotted(folk-cell) { - box-sizing: border-box; - align-items: center; - background-color: rgb(255, 255, 255); - display: flex; - padding: 0.25rem; - justify-content: start; - scroll-snap-align: start; - overflow: hidden; -} + s-columns, + s-rows, + s-body { + background-color: var(--border-color); + gap: 1px; + } -::slotted(folk-cell[type='number']) { - justify-content: end; -} + ::slotted(folk-cell) { + box-sizing: border-box; + align-items: center; + background-color: rgb(255, 255, 255); + display: flex; + padding: 0.25rem; + justify-content: start; + scroll-snap-align: start; + overflow: hidden; + } -::slotted(folk-cell:focus) { - outline: 2px solid #1b73e8; - z-index: 4; -} -`); + ::slotted(folk-cell[type='number']) { + justify-content: end; + } + + ::slotted(folk-cell:focus) { + outline: 2px solid #1b73e8; + z-index: 4; + } +`; const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; diff --git a/src/folk-toolbar.ts b/src/folk-toolbar.ts index 4a68064..7db0a92 100644 --- a/src/folk-toolbar.ts +++ b/src/folk-toolbar.ts @@ -1,8 +1,7 @@ import { FolkEventPropagator } from './folk-event-propagator.ts'; import { css } from './common/tags.ts'; -const styles = new CSSStyleSheet(); -styles.replaceSync(css` +const styles = css` :host { position: fixed; bottom: 16px; @@ -27,7 +26,7 @@ styles.replaceSync(css` button.active { background: #eee; } -`); +`; export class FolkToolbar extends HTMLElement { static tagName = 'folk-toolbar';