This commit is contained in:
“chrisshank” 2024-12-05 14:48:53 -08:00
parent 29a7bef95b
commit 3607ce237a
8 changed files with 325 additions and 321 deletions

View File

@ -1,219 +1,217 @@
// Ported from https://github.com/bitu467/record-player // Ported from https://github.com/bitu467/record-player
import { css } from '../../src/common/tags';
const styles = new CSSStyleSheet(); const styles = css`
styles.replaceSync(` ::slotted(*) {
::slotted(*) { display: none;
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);
} }
70% { :host {
transform: rotateX(20deg); display: block;
rotate: 14deg;
} }
100% { .player {
rotate: 14deg; background-color: #d52831;
} width: 330px;
} height: 190px;
position: absolute;
@keyframes move-arm { transform: translate(-50%, -50%);
from { left: 50%;
rotate: 14deg; top: 50%;
border-radius: 10px;
box-shadow: 0 8px 0 0 #be2728;
margin-top: -4px;
} }
to { .record {
rotate: 42deg; width: 175px;
} height: 175px;
} background-color: #181312;
position: absolute;
@keyframes reset-arm { border-radius: 50%;
0% { top: 10px;
rotate: 42deg; left: 20px;
display: flex;
justify-content: center;
align-items: center;
animation: spin 3s linear infinite;
animation-play-state: paused;
} }
20% { .record::before,
transform: rotateX(20deg); .record::after {
rotate: 42deg; content: '';
position: absolute;
border: 5px solid transparent;
border-top-color: #2c2424;
border-bottom-color: #2c2424;
border-radius: 50%;
} }
80% { .record::before {
transform: rotateX(20deg); width: 135px;
} height: 135px;
}
@keyframes spin {
from {
rotate: 0deg;
} }
to { .record:after {
rotate: 360deg; 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 { export class RecordPlayer extends HTMLElement {
static tagName = 'record-player'; static tagName = 'record-player';

View File

@ -4,6 +4,10 @@ export const vert = String.raw;
export const frag = String.raw; export const frag = String.raw;
export const css = String.raw;
export const html = 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;
}

View File

@ -3,8 +3,7 @@ import { FolkRope } from './folk-rope.ts';
import * as parser from '@babel/parser'; import * as parser from '@babel/parser';
import type { Node } from '@babel/types'; import type { Node } from '@babel/types';
const styles = new CSSStyleSheet(); const styles = css`
styles.replaceSync(css`
:host { :host {
display: block; display: block;
position: absolute; position: absolute;
@ -27,7 +26,7 @@ styles.replaceSync(css`
translate: -50% -50%; translate: -50% -50%;
border-radius: 5px; border-radius: 5px;
} }
`); `;
export class FolkEventPropagator extends FolkRope { export class FolkEventPropagator extends FolkRope {
static override tagName = 'folk-event-propagator'; static override tagName = 'folk-event-propagator';

View File

@ -1,4 +1,5 @@
import { getStroke, StrokeOptions } from 'perfect-freehand'; import { getStroke, StrokeOptions } from 'perfect-freehand';
import { css } from './common/tags';
export type Point = [x: number, y: number, pressure: number]; 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 // 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 // https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer
const styles = new CSSStyleSheet(); const styles = css`
styles.replaceSync(` :host,
:host, svg { svg {
display: block; display: block;
height: 100%; height: 100%;
width: 100%; width: 100%;
@ -21,7 +22,7 @@ styles.replaceSync(`
inset: 0 0 0 0; inset: 0 0 0 0;
cursor: var(--tracing-cursor, crosshair); cursor: var(--tracing-cursor, crosshair);
} }
`); `;
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {

View File

@ -2,9 +2,10 @@ import { LatLng, LatLngExpression, LeafletEvent, map, Map, tileLayer } from 'lea
// @ts-ignore // @ts-ignore
// Vite specific import :( // Vite specific import :(
import css from 'leaflet/dist/leaflet.css?inline'; import leafletCSS from 'leaflet/dist/leaflet.css?inline';
const styles = new CSSStyleSheet(); import { css } from './common/tags';
styles.replaceSync(`${css} const styles = css`
${leafletCSS}
:host { :host {
display: block; display: block;
} }
@ -13,7 +14,7 @@ styles.replaceSync(`${css}
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
`); `;
export class RecenterEvent extends Event { export class RecenterEvent extends Event {
constructor() { constructor() {

View File

@ -73,8 +73,7 @@ export class TransformEvent extends Event {
export type Dimension = number | 'auto'; export type Dimension = number | 'auto';
const styles = new CSSStyleSheet(); const styles = css`
styles.replaceSync(css`
:host { :host {
display: block; display: block;
position: absolute; position: absolute;
@ -209,7 +208,7 @@ styles.replaceSync(css`
opacity: 0; opacity: 0;
cursor: default; cursor: default;
} }
`); `;
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@ -229,7 +228,7 @@ export class FolkShape extends HTMLElement {
#shadow = this.attachShadow({ mode: 'open' }); #shadow = this.attachShadow({ mode: 'open' });
#internals = this.attachInternals(); #internals = this.attachInternals();
#dynamicStyles = new CSSStyleSheet(); #dynamicStyles = css``;
#type = (this.getAttribute('type') || 'rectangle') as Shape; #type = (this.getAttribute('type') || 'rectangle') as Shape;
get type(): Shape { get type(): Shape {

View File

@ -1,115 +1,118 @@
const styles = new CSSStyleSheet(); import { css } from './common/tags';
// hardcoded column and row numbers // hardcoded column and row numbers
styles.replaceSync(` const styles = css`
:host { :host {
--column-number: 10; --column-number: 10;
--row-number: 10; --row-number: 10;
--cell-height: 1.75rem; --cell-height: 1.75rem;
--cell-width: 100px; --cell-width: 100px;
--border-color: #e1e1e1; --border-color: #e1e1e1;
border: solid 1px var(--border-color); border: solid 1px var(--border-color);
box-sizing: border-box; box-sizing: border-box;
display: grid; display: grid;
font-family: monospace; font-family: monospace;
grid-template-columns: 50px repeat(var(--column-number), var(--cell-width)); grid-template-columns: 50px repeat(var(--column-number), var(--cell-width));
grid-template-rows: repeat(calc(var(--row-number) + 1), var(--cell-height)); grid-template-rows: repeat(calc(var(--row-number) + 1), var(--cell-height));
position: relative; position: relative;
overflow: scroll; overflow: scroll;
scroll-snap-type: both mandatory; scroll-snap-type: both mandatory;
scroll-padding-top: var(--cell-height); scroll-padding-top: var(--cell-height);
scroll-padding-left: 50px; 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;
} }
}
s-header { textarea {
background-color: #f8f9fa; background-color: rgba(255, 255, 255, 0.75);
display: flex; grid-column: var(--text-column, 0);
padding: 0.125rem 0.5rem; grid-row: var(--text-row, 0);
align-items: center; z-index: 11;
justify-content: center; }
&[empty] { s-columns {
box-shadow: 3px 3px 3px 0px rgba(173, 168, 168, 0.4); box-shadow: 0px 3px 5px 0px rgba(173, 168, 168, 0.6);
grid-area: 1; display: grid;
grid-column: 2 / -1;
grid-row: 1;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
position: sticky; position: sticky;
top: 0; 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; left: 0;
z-index: 3; z-index: 2;
s-header {
font-size: 0.75rem;
}
} }
&:state(selected) { s-header {
background-color: #d3e2fd; background-color: #f8f9fa;
font-weight: bold; display: flex;
} padding: 0.125rem 0.5rem;
} align-items: center;
justify-content: center;
s-body { &[empty] {
display: grid; box-shadow: 3px 3px 3px 0px rgba(173, 168, 168, 0.4);
grid-column: 2 / -1; grid-area: 1;
grid-row: 2 / -1; position: sticky;
grid-template-columns: subgrid; top: 0;
grid-template-rows: subgrid; left: 0;
z-index: 3;
}
&:state(selected) {
background-color: #d3e2fd;
font-weight: bold;
}
} }
s-columns, s-rows, s-body { s-body {
background-color: var(--border-color); display: grid;
gap: 1px; grid-column: 2 / -1;
} grid-row: 2 / -1;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}
::slotted(folk-cell) { s-columns,
box-sizing: border-box; s-rows,
align-items: center; s-body {
background-color: rgb(255, 255, 255); background-color: var(--border-color);
display: flex; gap: 1px;
padding: 0.25rem; }
justify-content: start;
scroll-snap-align: start;
overflow: hidden;
}
::slotted(folk-cell[type='number']) { ::slotted(folk-cell) {
justify-content: end; 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) { ::slotted(folk-cell[type='number']) {
outline: 2px solid #1b73e8; justify-content: end;
z-index: 4; }
}
`); ::slotted(folk-cell:focus) {
outline: 2px solid #1b73e8;
z-index: 4;
}
`;
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

View File

@ -1,8 +1,7 @@
import { FolkEventPropagator } from './folk-event-propagator.ts'; import { FolkEventPropagator } from './folk-event-propagator.ts';
import { css } from './common/tags.ts'; import { css } from './common/tags.ts';
const styles = new CSSStyleSheet(); const styles = css`
styles.replaceSync(css`
:host { :host {
position: fixed; position: fixed;
bottom: 16px; bottom: 16px;
@ -27,7 +26,7 @@ styles.replaceSync(css`
button.active { button.active {
background: #eee; background: #eee;
} }
`); `;
export class FolkToolbar extends HTMLElement { export class FolkToolbar extends HTMLElement {
static tagName = 'folk-toolbar'; static tagName = 'folk-toolbar';