fix: copy/paste button error/done state class name switch
add: flex properties: flex-direction, justify-content, align-items, gap
fix: border witdh/color/style data error
This commit is contained in:
defaultkavy 2024-04-02 08:28:00 +08:00
parent 22d3148fce
commit e4a80e06ff
7 changed files with 52 additions and 42 deletions

1
.vscode/tasks.json vendored
View File

@ -25,7 +25,6 @@
{ {
"label": "dev-startup", "label": "dev-startup",
"dependsOn": [ "dependsOn": [
"server",
"vite" "vite"
], ],
"problemMatcher": [] "problemMatcher": []

File diff suppressed because one or more lines are too long

View File

@ -29,7 +29,7 @@
<meta name="twitter:title" content="YouTube Chat Designer"> <meta name="twitter:title" content="YouTube Chat Designer">
<meta name="twitter:description" content="YouTube Chat CSS design tool for streamer."> <meta name="twitter:description" content="YouTube Chat CSS design tool for streamer.">
<!-- <meta name="twitter:image" content=""> --> <!-- <meta name="twitter:image" content=""> -->
<script type="module" crossorigin src="/assets/index-DTS3ifer.js"></script> <script type="module" crossorigin src="/assets/index-CqaSrBDb.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-nOkcB8kh.css"> <link rel="stylesheet" crossorigin href="/assets/index-nOkcB8kh.css">
</head> </head>
<body> <body>

File diff suppressed because one or more lines are too long

View File

@ -22,7 +22,7 @@ export const $chat = new YouTubeChat().css({backgroundColor: '#131313'})
.send({name: 'リョウ', message: 'If you want to save your settings, using Copy JSON and save it, you can paste the JSON to recovery your settings.', role: 'Moderator'}) .send({name: 'リョウ', message: 'If you want to save your settings, using Copy JSON and save it, you can paste the JSON to recovery your settings.', role: 'Moderator'})
.send({name: '虹夏', message: 'Try to send message for test your design.', role: 'Owner'}) .send({name: '虹夏', message: 'Try to send message for test your design.', role: 'Owner'})
init(); modelInit();
const $app = $('app').content([ const $app = $('app').content([
$('h1').content([ $('h1').content([
@ -78,9 +78,10 @@ const $app = $('app').content([
const json_string = await navigator.clipboard.readText(); const json_string = await navigator.clipboard.readText();
try { try {
const json = JSON.parse(json_string); const json = JSON.parse(json_string);
init(json); modelInit(json);
} catch (err) { } catch (err) {
$button.content('Error!').class('error'); $button.content('Error!').class('error').removeClass('done');
if (timer) clearTimeout(timer);
timer = setTimeout(() => { timer = setTimeout(() => {
$button.removeClass('error').content('Paste'); $button.removeClass('error').content('Paste');
timer = undefined; timer = undefined;
@ -88,7 +89,7 @@ const $app = $('app').content([
return; return;
} }
load(); load();
$button.content('Pasted!').class('done') $button.content('Pasted!').class('done').removeClass('error')
if (timer) clearTimeout(timer); if (timer) clearTimeout(timer);
timer = setTimeout(() => { timer = setTimeout(() => {
$button.removeClass('done').content('Paste'); $button.removeClass('done').content('Paste');
@ -177,15 +178,16 @@ $(document.body).content($app)
load(); load();
window.addEventListener('resize', () => checkWindowSize()) window.addEventListener('resize', () => checkWindowSize())
function init(data = defaultStyle) { function modelInit(data = defaultStyle) {
ROLE_MODEL_MAP.clear(); ROLE_MODEL_MAP.clear();
for (const role of ROLE_LIST) { for (const role of ROLE_LIST) {
const STYLE_MAP = new Map<string, StyleModel>() const STYLE_MAP = new Map<string, StyleModel>();
ROLE_MODEL_MAP.set(role, STYLE_MAP); ROLE_MODEL_MAP.set(role, STYLE_MAP);
for (const element of ELEMENT_LIST) { for (const element of ELEMENT_LIST) {
const model = new StyleModel(data[role][element]); const initialized_data = dataInit(data[role][element]);
STYLE_MAP.set(element, model) const model = new StyleModel(initialized_data);
$chat.updateStyle(element, model, [role]) STYLE_MAP.set(element, model);
$chat.updateStyle(element, model, [role]);
} }
} }
$view.deleteAllView().clear(); $view.deleteAllView().clear();
@ -200,7 +202,7 @@ function load() {
$view.switchView('Message'); $view.switchView('Message');
$<$Input>('::.role-checkbox')?.forEach($input => $input.checked(false)); $<$Input>('::.role-checkbox')?.forEach($input => $input.checked(false));
$<$Input>(':#normal')?.checked(true); $<$Input>(':#normal')?.checked(true);
refreshPanel(); PANEL_MAP.forEach(panel => panel.update().layout())
} }
function refreshPanel() { function refreshPanel() {
@ -266,4 +268,11 @@ function checkWindowSize() {
} else { } else {
if (!$app.inDOM()) $(document.body).content($app); if (!$app.inDOM()) $(document.body).content($app);
} }
} }
function dataInit(data: Partial<CSSStyleDeclaration>) {
switch (undefined) {
case data.gap: data.gap = '0px';
}
return data;
}

View File

@ -21,9 +21,9 @@ export class StyleModel {
} }
const border = (dir: 'top' | 'right' | 'left' | 'bottom') => { const border = (dir: 'top' | 'right' | 'left' | 'bottom') => {
return { return {
[`border${firstCap(dir)}Style`]: filterMultitype(panel.$<$Select>(`#border-${dir}-style`)?.value(), this.data[`boder${firstCap(dir)}Style`]), [`border${firstCap(dir)}Style`]: filterMultitype(panel.$<$Select>(`#border-${dir}-style`)?.value(), this.data[`border${firstCap(dir)}Style`]),
[`border${firstCap(dir)}Color`]: filterMultitype(panel.$<$Input>(`#border-${dir}-color`)?.value(), this.data[`boder${firstCap(dir)}Color`]), [`border${firstCap(dir)}Color`]: filterMultitype(panel.$<$Input>(`#border-${dir}-color`)?.value(), this.data[`border${firstCap(dir)}Color`]),
[`border${firstCap(dir)}Width`]: filterMultitype(panel.$<$Input>(`#border-${dir}-width`)?.value(), this.data[`boder${firstCap(dir)}Color`], true) [`border${firstCap(dir)}Width`]: filterMultitype(panel.$<$Input>(`#border-${dir}-width`)?.value(), this.data[`border${firstCap(dir)}Width`], true)
} }
} }
@ -62,29 +62,12 @@ export class StyleModel {
display: filterMultitype(panel.$<$Select>('#display')?.value(), this.data.display), display: filterMultitype(panel.$<$Select>('#display')?.value(), this.data.display),
height: filterMultitype(panel.$<$Input>('#height')?.value(), this.data.height, true), height: filterMultitype(panel.$<$Input>('#height')?.value(), this.data.height, true),
width: filterMultitype(panel.$<$Input>('#width')?.value(), this.data.width, true), width: filterMultitype(panel.$<$Input>('#width')?.value(), this.data.width, true),
flexDirection: filterMultitype(panel.$<$Input>('#flex-direction')?.value(), this.data.flexDirection),
justifyContent: filterMultitype(panel.$<$Input>('#justify-content')?.value(), this.data.justifyContent),
alignItems: filterMultitype(panel.$<$Input>('#align-items')?.value(), this.data.alignItems),
gap: filterMultitype(panel.$<$Input>('#gap')?.value(), this.data.gap, true),
} }
this.data = data; this.data = data;
return this; return this;
} }
cssObject() {
const json = {};
const convert = (passKey: string | null, data: Object) => {
for (let [key, value] of Object.entries(data)) {
key = passKey ? passKey + key.charAt(0).toUpperCase() + key.slice(1) : key;
if (value instanceof Object === false) {
if (typeof value === 'number' && key !== 'opacity') value = `${value}px`;
Object.assign(json, {[`${key}`]: value});
continue;
}
convert(key, value);
}
}
convert(null, this.data);
return json
}
css() {
}
} }

View File

@ -1,4 +1,4 @@
import { $Container } from "fluentx"; import { $Container, $State } from "fluentx";
import { ColorInput } from "../component/ColorInput"; import { ColorInput } from "../component/ColorInput";
import { RangeInput } from "../component/RangeInput"; import { RangeInput } from "../component/RangeInput";
import { SelectInput } from "../component/SelectInput"; import { SelectInput } from "../component/SelectInput";
@ -10,6 +10,7 @@ import { firstCap, propCap } from "./util";
export class StylePanel extends $Container { export class StylePanel extends $Container {
type: StyleType; type: StyleType;
name: string; name: string;
flex_hidden$ = $.state(false);
constructor(name: string, type: StyleType) { constructor(name: string, type: StyleType) {
super('div'); super('div');
this.staticClass('style-panel'); this.staticClass('style-panel');
@ -26,6 +27,7 @@ export class StylePanel extends $Container {
model.update(this) model.update(this)
$chat.updateStyle(this.name, model, [role]); $chat.updateStyle(this.name, model, [role]);
}); });
this.flex_hidden$.set(this.data?.display !== 'flex');
return this; return this;
} }
@ -44,6 +46,22 @@ export class StylePanel extends $Container {
]) ])
]), ]),
$('section').content([
$('h3').content('Flex'),
$('div').content([
new SelectInput('flex-direction').label('Direction').add([
['row', 'column', 'row-reverse', 'column-reverse',].map(value => $('option').content(value).value(value))
]).value(this.data.flexDirection),
new RangeInput('gap').value(this.data.gap).unit('px').min(0).max(100).label('Gap'),
new SelectInput('justify-content').label('Justify Content').add([
['start', 'center', 'end', 'stretch', 'space-around', 'space-evenly', 'space-between'].map(value => $('option').content(value).value(value))
]).value(this.data.justifyContent),
new SelectInput('align-items').label('Align Items').add([
['start', 'center', 'end', 'stretch', 'space-around', 'space-evenly', 'space-between'].map(value => $('option').content(value).value(value))
]).value(this.data.alignItems)
])
]).hide(this.flex_hidden$),
this.type === 'text' ? $('section').content([ this.type === 'text' ? $('section').content([
$('h3').content('Font'), $('h3').content('Font'),
$('div').content([ $('div').content([