Skip to content

Commit

Permalink
feat: add scaffolding for UI components, and initial component (#62)
Browse files Browse the repository at this point in the history
* feat: initial commit of UI, basic base CSS, and sd-field

* fix: spacing of body and field

* refactor: switch to fix width

* refactor: switch to actual CSS files

* test: fix tests with ESM / CSS import

* fix: missing CSS variables for coloring

* refactor: rename field class to align with existing HTML elements

* chore: fix linting, and include js, cjs, and mjs files

---------

Co-authored-by: Richard Herman <[email protected]>
  • Loading branch information
GeekyEggo and GeekyEggo authored Oct 17, 2024
1 parent 7618186 commit 3030a3d
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 2 deletions.
18 changes: 17 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import tsEslint from "typescript-eslint";

export default [
{
ignores: [".github/", "dist/", "node_modules/", "types/", "*.mjs"],
ignores: [
".github/",
"dist/",
"node_modules/",
"types/",
],
},

/**
Expand Down Expand Up @@ -121,6 +126,17 @@ export default [
},
},

/**
* JavaScript.
*/
{
files: ["**/*.{js,cjs,mjs}"],
rules: {
"@typescript-eslint/explicit-function-return-type": "off",
"jsdoc/no-types": "off",
},
},

/**
* Tests and mocks.
*/
Expand Down
9 changes: 9 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const config = {
verbose: true,
roots: ["src"],
transform: {
// TypeScript.
"^.+\\.ts$": [
"@swc/jest",
{
Expand All @@ -27,7 +28,15 @@ const config = {
},
},
],
// Transform ESM.
"^.+\\.(js|jsx)$": "@swc/jest",
// Ignore CSS files.
"^.+\\.css$": "<rootDir>/tests/__setup__/empty-transform.cjs",
},
transformIgnorePatterns: [
// Selective ESM transformation enables working with Lit.
"node_modules/(?!(lit-html|lit-element|lit|@lit)/)",
],
};

export default config;
70 changes: 70 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,13 @@
"jest-websocket-mock": "^2.5.0",
"prettier": "^3.0.3",
"rollup": "^4.0.2",
"rollup-plugin-import-css": "^3.5.5",
"typescript": "^5.2.2",
"typescript-eslint": "^8.8.0"
},
"dependencies": {
"@elgato/schemas": "^0.3.1",
"lit": "^3.2.1",
"ws": "^8.17.1"
}
}
5 changes: 5 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import nodeResolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";
import { dirname, join, parse, resolve } from "node:path";
import url from "node:url";
import css from "rollup-plugin-import-css";

const isWatching = !!process.env.ROLLUP_WATCH;
const banner = `/**!
Expand Down Expand Up @@ -51,6 +52,10 @@ export default streamDeck;
});
},
},
css({
inject: true,
modules: false,
}),
],
};
}
Expand Down
65 changes: 65 additions & 0 deletions src/ui/components/field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { LitElement, css, html, type HTMLTemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";

/**
* Field that identifies an input, or group of inputs.
*/
@customElement("sd-field")
export class SDFieldElement extends LitElement {
/**
* @inheritdoc
*/
public static styles = [
css`
.sd-field {
align-items: baseline;
column-gap: 10px;
display: grid;
grid-template-columns: 93px 262px;
}
`,
];

/**
* Label to show for the field.
*/
@property()
accessor label: string | undefined = undefined;

/**
* @inheritdoc
*/
public render(): HTMLTemplateResult {
return html`
<div class="sd-field">
<div class="sd-field-label">
<label @click=${this.#focusFirstElement}>${this.label ? this.label + ":" : undefined}</label>
</div>
<div class="sd-field-input">
<slot></slot>
</div>
</div>
`;
}

/**
* Focuses the first element, that can have focus, within the field.
*/
#focusFirstElement(): void {
for (const el of this.querySelectorAll("*")) {
if ("focus" in el && typeof el.focus === "function") {
el.focus();
return;
}
}
}
}

declare global {
interface HTMLElementTagNameMap {
/**
* Field that identifies an input, or group of inputs.
*/
"sd-field": SDFieldElement;
}
}
1 change: 1 addition & 0 deletions src/ui/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./field";
1 change: 1 addition & 0 deletions src/ui/css/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "*.css";
37 changes: 37 additions & 0 deletions src/ui/css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
:root {
--sd-background-color: #2d2d2d;
--sd-color-content-primary: #d8d8d8;
--sd-color-content-secondary: #969696;
--sd-font-size: 12px;
--sd-line-height: calc(var(--sd-font-size) * 1.333);
--sd-scrollbar-track-color: #262626;
--sd-scrollbar-thumb-color: #666666;
}

body {
background-color: var(--sd-background-color);
color: var(--sd-color-content-primary);
font-size: var(--sd-font-size);
font-family:
System,
"Segoe UI",
Arial,
Roboto,
Helvetica sans-serif;
line-height: var(--sd-line-height);
margin: 8px 8px 8px 0px;
text-rendering: optimizeLegibility;
}

::-webkit-scrollbar {
width: 4px;
}

::-webkit-scrollbar-track {
background-color: var(--sd-scrollbar-track-color);
}

::-webkit-scrollbar-thumb {
background-color: var(--sd-scrollbar-thumb-color);
border-radius: 2px;
}
2 changes: 2 additions & 0 deletions src/ui/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { type ActionInfo, type RegistrationInfo } from "../api";
import type { IDisposable } from "../common/disposable";
import type { JsonObject } from "../common/json";
import "./components";
import { connection } from "./connection";
import "./css/main.css";
import { i18n } from "./i18n";
import { logger } from "./logging";
import { plugin } from "./plugin";
Expand Down
2 changes: 1 addition & 1 deletion src/ui/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"dom",
"es2022"
],
"module": "es2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"skipLibCheck": true,
"strict": true,
Expand Down
12 changes: 12 additions & 0 deletions tests/__setup__/empty-transform.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* An empty Jest transform, allowing for specific files to be omitted, for example CSS files.
*/
module.exports = {
/**
* Processes the file, transforming it to a readable state... of no code.
* @returns An empty set of code, without a map, that mimics a transformed file.
*/
process: () => {
return { code: "" };
},
};

0 comments on commit 3030a3d

Please sign in to comment.