ssb: Add a manual theme color picker.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 18m1s

This commit is contained in:
2025-10-22 19:39:20 -04:00
parent 49b1834bc6
commit 5647196924
16 changed files with 165 additions and 79 deletions

View File

@@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "🦀", "emoji": "🦀",
"previous": "&J8epgiTHHI/2GtNoS+FW3UpyTrIEL4ltovW1JpmwSW4=.sha256" "previous": "&ceivZzkWd2Bvvdzdvdv68bZm2Y9oC0J352C78ZmMMU4=.sha256"
} }

View File

@@ -1,6 +1,6 @@
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {html, render} from './lit-all.min.js'; import {html, render} from './lit-all.min.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
let g_emojis; let g_emojis;
@@ -140,6 +140,9 @@ export async function picker(callback, anchor, author, recent) {
<style> <style>
${styles} ${styles}
</style> </style>
<style>
${generate_theme()}
</style>
<div <div
class="w3-modal" class="w3-modal"
style="display: block; box-sizing: border-box; z-index: 10" style="display: block; box-sizing: border-box; z-index: 10"

View File

@@ -18,5 +18,8 @@ import * as tf_styles from './tf-styles.js';
window.addEventListener('load', function () { window.addEventListener('load', function () {
let style = document.createElement('style'); let style = document.createElement('style');
style.innerText = tf_styles.styles; style.innerText = tf_styles.styles;
Promise.resolve(tf_styles.generate_theme()).then(function (x) {
style.innerText += x;
});
document.body.appendChild(style); document.body.appendChild(style);
}); });

View File

@@ -1,6 +1,6 @@
import {LitElement, html, css, guard, until} from './lit-all.min.js'; import {LitElement, html, css, guard, until} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfElement extends LitElement { class TfElement extends LitElement {
static get properties() { static get properties() {
@@ -763,6 +763,17 @@ class TfElement extends LitElement {
} }
} }
async pick_color() {
let input = document.createElement('input');
input.type = 'color';
input.value = (await tfrpc.rpc.localStorageGet('color')) ?? '#ff0000';
input.addEventListener('change', async function () {
await tfrpc.rpc.localStorageSet('color', input.value);
window.location.reload();
});
input.click();
}
render() { render() {
let self = this; let self = this;
@@ -819,6 +830,12 @@ class TfElement extends LitElement {
</button> </button>
` `
)} )}
<button
class="w3-bar-item w3-button w3-right"
@click=${this.pick_color}
>
🎨<span class="w3-hide-small">Color</span>
</button>
</div> </div>
`; `;
let contents = this.guest let contents = this.guest
@@ -854,6 +871,9 @@ class TfElement extends LitElement {
` `
: undefined; : undefined;
return html` return html`
<style>
${generate_theme()}
</style>
<div <div
style="width: 100vw; min-height: 100vh; height: 100vh; display: flex; flex-direction: column" style="width: 100vw; min-height: 100vh; height: 100vh; display: flex; flex-direction: column"
class="w3-theme-dark" class="w3-theme-dark"

View File

@@ -1,7 +1,7 @@
import {LitElement, html, unsafeHTML, live} from './lit-all.min.js'; import {LitElement, html, unsafeHTML, live} from './lit-all.min.js';
import * as tfutils from './tf-utils.js'; import * as tfutils from './tf-utils.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
import Tribute from './tribute.esm.js'; import Tribute from './tribute.esm.js';
class TfComposeElement extends LitElement { class TfComposeElement extends LitElement {
@@ -603,6 +603,9 @@ class TfComposeElement extends LitElement {
🔐 Encrypt 🔐 Encrypt
</button>`; </button>`;
let result = html` let result = html`
<style>
${generate_theme()}
</style>
<style> <style>
.w3-input:empty::before { .w3-input:empty::before {
content: attr(placeholder); content: attr(placeholder);

View File

@@ -4,12 +4,14 @@ import {
html, html,
repeat, repeat,
render, render,
unsafeCSS,
unsafeHTML, unsafeHTML,
until,
} from './lit-all.min.js'; } from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import * as tfutils from './tf-utils.js'; import * as tfutils from './tf-utils.js';
import * as emojis from './emojis.js'; import * as emojis from './emojis.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfMessageElement extends LitElement { class TfMessageElement extends LitElement {
static get properties() { static get properties() {
@@ -701,7 +703,7 @@ class TfMessageElement extends LitElement {
: undefined; : undefined;
} }
render() { _render() {
let content = this.message?.content; let content = this.message?.content;
if (this.message?.decrypted?.type == 'post') { if (this.message?.decrypted?.type == 'post') {
content = this.message.decrypted; content = this.message.decrypted;
@@ -1095,6 +1097,15 @@ class TfMessageElement extends LitElement {
return this.render_small_frame(this.render_raw()); return this.render_small_frame(this.render_raw());
} }
} }
render() {
return html`
<style>
${generate_theme()}
</style>
${this._render()}
`;
}
} }
customElements.define('tf-message', TfMessageElement); customElements.define('tf-message', TfMessageElement);

View File

@@ -1,6 +1,6 @@
import {LitElement, html, unsafeHTML, repeat, until} from './lit-all.min.js'; import {LitElement, html, unsafeHTML, repeat, until} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfNewsElement extends LitElement { class TfNewsElement extends LitElement {
static get properties() { static get properties() {
@@ -231,6 +231,9 @@ class TfNewsElement extends LitElement {
} }
} }
return html` return html`
<style>
${generate_theme()}
</style>
<div> <div>
${repeat( ${repeat(
final_messages, final_messages,

View File

@@ -1,7 +1,7 @@
import {LitElement, html, until, unsafeHTML} from './lit-all.min.js'; import {LitElement, html, until, unsafeHTML} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import * as tfutils from './tf-utils.js'; import * as tfutils from './tf-utils.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfProfileElement extends LitElement { class TfProfileElement extends LitElement {
static get properties() { static get properties() {
@@ -316,7 +316,9 @@ class TfProfileElement extends LitElement {
} }
image = this.editing?.image ?? image; image = this.editing?.image ?? image;
let description = this.editing?.description ?? profile.description; let description = this.editing?.description ?? profile.description;
return html`<div class="w3-card-4 w3-container w3-theme-d3" style="box-sizing: border-box"> return html`
<style>${generate_theme()}</style>
<div class="w3-card-4 w3-container w3-theme-d3" style="box-sizing: border-box">
<header class="w3-container"> <header class="w3-container">
<p><tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)} in ${this.sequence} messages)</p> <p><tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)} in ${this.sequence} messages)</p>
</header> </header>

View File

@@ -1,5 +1,5 @@
import {LitElement, html, unsafeHTML} from './lit-all.min.js'; import {LitElement, html, unsafeHTML} from './lit-all.min.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfReactionsModalElement extends LitElement { class TfReactionsModalElement extends LitElement {
static get properties() { static get properties() {
@@ -24,50 +24,57 @@ class TfReactionsModalElement extends LitElement {
render() { render() {
let self = this; let self = this;
return this.votes?.length return this.votes?.length
? html` <div ? html` <style>
class="w3-modal w3-animate-opacity" ${generate_theme()}
style="display: block; box-sizing: border-box; z-index: 10" </style>
@click=${this.clear}
>
<div <div
class="w3-modal-content w3-card-4 w3-theme-d1" class="w3-modal w3-animate-opacity"
onclick="event.stopPropagation()" style="display: block; box-sizing: border-box; z-index: 10"
@click=${this.clear}
> >
<div class="w3-container w3-padding"> <div
<header class="w3-container"> class="w3-modal-content w3-card-4 w3-theme-d1"
<h2>Reactions</h2> onclick="event.stopPropagation()"
<span class="w3-button w3-display-topright" @click=${this.clear} >
>&times;</span <div class="w3-container w3-padding">
> <header class="w3-container">
</header> <h2>Reactions</h2>
<ul class="w3-theme-dark w3-container w3-ul"> <span
${this.votes class="w3-button w3-display-topright"
.sort((x, y) => y.timestamp - x.timestamp) @click=${this.clear}
.map( >&times;</span
(x) => html` >
<li style="display: flex; flex-direction: row; gap: 4px"> </header>
<span style="flex-basis: 3em" <ul class="w3-theme-dark w3-container w3-ul">
>${x?.content?.vote?.expression}</span ${this.votes
.sort((x, y) => y.timestamp - x.timestamp)
.map(
(x) => html`
<li
style="display: flex; flex-direction: row; gap: 4px"
> >
<tf-user <span style="flex-basis: 3em"
style="flex: 1 1" >${x?.content?.vote?.expression}</span
id=${x.author} >
.users=${this.users} <tf-user
></tf-user> style="flex: 1 1"
<span id=${x.author}
style="flex-shrink: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis" .users=${this.users}
>${new Date(x?.timestamp).toLocaleString()}</span ></tf-user>
> <span
</li> style="flex-shrink: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis"
` >${new Date(x?.timestamp).toLocaleString()}</span
)} >
</ul> </li>
<footer class="w3-container w3-padding"> `
<button class="w3-button" @click=${this.clear}>Close</button> )}
</footer> </ul>
<footer class="w3-container w3-padding">
<button class="w3-button" @click=${this.clear}>Close</button>
</footer>
</div>
</div> </div>
</div> </div>`
</div>`
: undefined; : undefined;
} }
} }

View File

@@ -1,4 +1,5 @@
import {css, unsafeCSS} from './lit-all.min.js'; import {css, unsafeCSS, until} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
const tf = css` const tf = css`
img { img {
@@ -408,16 +409,8 @@ function is_dark(hex, value) {
return (r * 299 + g * 587 + b * 114) / 1000 < value; return (r * 299 + g * 587 + b * 114) / 1000 < value;
} }
function generated() { export function generate(color) {
let now = new Date(); let [r, g, b] = hex_to_rgb(color);
let k_color = rgb_to_hex([
(now.getDay() * 128) / 6,
(now.getHours() * 128) / 23,
(now.getSeconds() * 128) / 59,
]);
//let k_color = '#034f84';
//let k_color = rgb_to_hex([Math.random() * 256, Math.random() * 256, Math.random() * 256]);
let [r, g, b] = hex_to_rgb(k_color);
let [h, s, l] = rgb_to_hsl(r, g, b); let [h, s, l] = rgb_to_hsl(r, g, b);
let theme1 = { let theme1 = {
@@ -461,4 +454,28 @@ function generated() {
return unsafeCSS(result); return unsafeCSS(result);
} }
export let styles = [tf, w3, generated()]; let g_theme;
export function generate_theme() {
return g_theme
? g_theme
: until(
tfrpc.rpc.localStorageGet('color').then(function (value) {
g_theme = generate(value ?? '#034f84');
return g_theme;
}),
generated_now()
);
}
function generated_now() {
let now = new Date();
return generate(
rgb_to_hex([
(now.getDay() * 128) / 6,
(now.getHours() * 128) / 23,
(now.getSeconds() * 128) / 59,
])
);
}
export let styles = [tf, w3];

View File

@@ -1,6 +1,6 @@
import {LitElement, html} from './lit-all.min.js'; import {LitElement, html} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfTabConnectionsElement extends LitElement { class TfTabConnectionsElement extends LitElement {
static get properties() { static get properties() {
@@ -251,6 +251,9 @@ class TfTabConnectionsElement extends LitElement {
render() { render() {
let self = this; let self = this;
return html` return html`
<style>
${generate_theme()}
</style>
<div class="w3-container" style="box-sizing: border-box"> <div class="w3-container" style="box-sizing: border-box">
<h2>New Connection</h2> <h2>New Connection</h2>
<textarea class="w3-input w3-theme-d1" id="code"></textarea> <textarea class="w3-input w3-theme-d1" id="code"></textarea>

View File

@@ -1,6 +1,6 @@
import {LitElement, cache, html, unsafeHTML, until} from './lit-all.min.js'; import {LitElement, cache, html, unsafeHTML, until} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfTabNewsFeedElement extends LitElement { class TfTabNewsFeedElement extends LitElement {
static get properties() { static get properties() {
@@ -538,6 +538,9 @@ class TfTabNewsFeedElement extends LitElement {
`; `;
} }
return cache(html` return cache(html`
<style>
${generate_theme()}
</style>
${this.unread_allowed() ${this.unread_allowed()
? html`<button ? html`<button
class="w3-button w3-theme-d1" class="w3-button w3-theme-d1"

View File

@@ -7,7 +7,7 @@ import {
until, until,
} from './lit-all.min.js'; } from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfTabNewsElement extends LitElement { class TfTabNewsElement extends LitElement {
static get properties() { static get properties() {
@@ -395,6 +395,9 @@ class TfTabNewsElement extends LitElement {
</div>`; </div>`;
} }
return cache(html` return cache(html`
<style>
${generate_theme()}
</style>
${this.render_sidebar()} ${this.render_sidebar()}
<div <div
style="margin-left: 2in; padding: 0px; top: 0; height: 100vh; max-height: 100%; overflow: auto; contain: layout" style="margin-left: 2in; padding: 0px; top: 0; height: 100vh; max-height: 100%; overflow: auto; contain: layout"

View File

@@ -1,6 +1,6 @@
import {LitElement, html, unsafeHTML} from './lit-all.min.js'; import {LitElement, html, unsafeHTML} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfTabSearchElement extends LitElement { class TfTabSearchElement extends LitElement {
static get properties() { static get properties() {
@@ -146,6 +146,7 @@ class TfTabSearchElement extends LitElement {
} }
let self = this; let self = this;
return html` return html`
<style>${generate_theme()}</style>
<div class="w3-padding"> <div class="w3-padding">
<div style="display: flex; flex-direction: row; gap: 4px"> <div style="display: flex; flex-direction: row; gap: 4px">
<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input> <input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input>

View File

@@ -1,5 +1,5 @@
import {LitElement, html, unsafeHTML} from './lit-all.min.js'; import {LitElement, html, unsafeHTML} from './lit-all.min.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfTagElement extends LitElement { class TfTagElement extends LitElement {
static get properties() { static get properties() {
@@ -17,11 +17,15 @@ class TfTagElement extends LitElement {
render() { render() {
let number = this.count ? html` (${this.count})` : undefined; let number = this.count ? html` (${this.count})` : undefined;
return html`<a return html`
href=${'#' + encodeURIComponent(this.tag)} <style>
class="w3-tag w3-theme-d1 w3-round-4 w3-button" ${generate_theme()}</style
>${this.tag}${number}</a ><a
> `; href=${'#' + encodeURIComponent(this.tag)}
class="w3-tag w3-theme-d1 w3-round-4 w3-button"
>${this.tag}${number}</a
>
`;
} }
} }

View File

@@ -1,6 +1,6 @@
import {LitElement, html} from './lit-all.min.js'; import {LitElement, html} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js'; import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js'; import {styles, generate_theme} from './tf-styles.js';
class TfUserElement extends LitElement { class TfUserElement extends LitElement {
static get properties() { static get properties() {
@@ -58,12 +58,15 @@ class TfUserElement extends LitElement {
/>`; />`;
} }
} }
return html` <div return html` <style>
style=${'display: inline-block; vertical-align: middle; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis' + ${generate_theme()}
(this.nolink ? '' : '; font-weight: bold')} </style>
> <div
${image} ${name} style=${'display: inline-block; vertical-align: middle; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis' +
</div>`; (this.nolink ? '' : '; font-weight: bold')}
>
${image} ${name}
</div>`;
} }
} }