Updates...

This commit is contained in:
2022-09-17 22:54:24 +03:00
parent 12fc946c9b
commit 0f3b3d527d
21 changed files with 1246 additions and 910 deletions

View File

@@ -39,6 +39,5 @@
"*://*.twitch.tv/*" "*://*.twitch.tv/*"
] ]
} }
], ]
"permissions": ["webNavigation"]
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,168 +0,0 @@
import {CustomHTMLElementConstructor} from "./types";
export class CustomHTMLElement<T = HTMLElement> {
element: HTMLElement;
constructor(element: string, data: CustomHTMLElementConstructor) {
this.element = document.createElement(element);
if (data.id) {
this.setId(data.id);
} else {
this.setId(element + '-generated-id-' + Math.floor(Math.random() * 10000000));
}
if (data.class) {
if (typeof data.class === "string") {
this.addClass(data.class);
} else {
for (const className of data.class) {
this.addClass(className);
}
}
}
if (data.attributes) {
for (const key in data.attributes) {
this.addAttribute(key, data.attributes[key]);
}
}
if (data.css) this.setStyle(data.css);
if (data.body) typeof data.body === "string" ? this.setBody(data.body) : this.appendChild(data.body);
if (data.customBody) this.appendCustomChild(data.customBody);
}
setId(id: string): CustomHTMLElement<T> {
this.element.id = id;
return this;
}
addClass(classes: string): CustomHTMLElement<T> {
this.element.classList.add(classes);
return this;
}
addAttribute(name: string, value: string): CustomHTMLElement<T> {
this.element.setAttribute(name, value);
return this;
}
setStyle(attributes: Partial<CSSStyleDeclaration>): CustomHTMLElement<T> {
for(let key in attributes) {
this.element.style[key] = attributes[key] || '';
}
return this;
}
setBody(body: string): CustomHTMLElement<T> {
this.element.innerHTML = body;
return this;
}
appendBody(body: string): CustomHTMLElement<T> {
this.element.innerHTML += body;
return this;
}
appendChild(child: HTMLElement): CustomHTMLElement<T> {
this.element.appendChild(child);
return this;
}
appendCustomChild(child: CustomHTMLElement): CustomHTMLElement<T> {
this.element.appendChild(child.getElement());
return this;
}
getElement(): T {
return this.element as T;
}
setClickListener(listener: Function): CustomHTMLElement<T> {
this.element.addEventListener('click', () => listener());
return this;
}
setChangeListener(listener: Function): CustomHTMLElement<T> {
this.element.addEventListener('change', () => listener());
return this;
}
setMouseMoveListener(listener: Function): CustomHTMLElement<T> {
this.element.addEventListener('mousemove', () => listener());
return this;
}
setMouseDownListener(listener: Function): CustomHTMLElement<T> {
this.element.addEventListener('mousedown', () => listener());
return this;
}
setMouseUpListener(listener: Function): CustomHTMLElement<T> {
this.element.addEventListener('mouseup', () => listener());
return this;
}
remove(): void {
this.element.remove();
}
show(): CustomHTMLElement<T> {
this.setStyle({
display: 'unset',
});
return this;
}
hide(): CustomHTMLElement<T> {
this.setStyle({
display: 'none',
});
return this;
}
}
export class CustomDivElement extends CustomHTMLElement<HTMLDivElement> {
constructor(className: string = '', content: string = '') {
super('div', {class: className, body: content});
}
}
export class CustomInputElement extends CustomHTMLElement<HTMLInputElement> {
constructor(className: string = '') {
super('input', {class: className});
}
}
export class CustomPElement extends CustomHTMLElement<HTMLParagraphElement> {
constructor(className: string = '', content: string = '') {
super('p', {class: className, body: content});
}
}
export class CustomButtonElement extends CustomHTMLElement<HTMLButtonElement> {
constructor(className: string = '', content: string = '') {
super('button', {class: className, body: content});
}
}
export class CustomAElement extends CustomHTMLElement<HTMLAnchorElement> {
constructor(className: string = '', content: string = '') {
super('a', {class: className, body: content});
}
}
export class CustomSpanElement extends CustomHTMLElement<HTMLSpanElement> {
constructor(className: string = '', content: string = '') {
super('span', {class: className, body: content});
}
}
export class CustomImgElement extends CustomHTMLElement<HTMLSpanElement> {
constructor(className: string = '', content: string = '') {
super('img', {class: className, body: content});
}
}

View File

@@ -11,10 +11,11 @@ export default class HTMLBuilder {
if (data.attributes) this.setAttributes(data.attributes); if (data.attributes) this.setAttributes(data.attributes);
if (data.style) this.setStyles(data.style); if (data.style) this.setStyles(data.style);
if (data.mouseClickEvent) this.setMouseClickListener(data.mouseClickEvent); if (data.mouseClickEvent) this.setMouseClickListener(data.mouseClickEvent);
if (data.mouseMoveEvent) this.setMouseClickListener(data.mouseMoveEvent); if (data.mouseMoveEvent) this.setMouseMoveListener(data.mouseMoveEvent);
if (data.mouseDownEvent) this.setMouseClickListener(data.mouseDownEvent); if (data.mouseDownEvent) this.setMouseDownListener(data.mouseDownEvent);
if (data.mouseUpEvent) this.setMouseClickListener(data.mouseUpEvent); if (data.mouseUpEvent) this.setMouseUpListener(data.mouseUpEvent);
if (data.keyUpEvent) this.setKeyUpListener(data.keyUpEvent); if (data.keyUpEvent) this.setKeyUpListener(data.keyUpEvent);
if (data.changeListener) this.setChangeListener(data.changeListener);
if (data.content) this.setContent(data.content); if (data.content) this.setContent(data.content);
} }
@@ -61,20 +62,24 @@ export default class HTMLBuilder {
this.element.addEventListener('click', () => cb()); this.element.addEventListener('click', () => cb());
} }
setContent(content: (HTMLBuilderBlock|string)[]) { setContent(content: (HTMLBuilderBlock|string|HTMLElement)[]) {
for (let block of content) { for (let block of content) {
this.addContent(block); this.addContent(block);
} }
} }
addContent(content: HTMLBuilderBlock|string) { addContent(content: HTMLBuilderBlock|string|HTMLElement) {
if (typeof content === 'string') { if (typeof content === 'string') {
this.element.innerHTML += content; this.element.innerHTML += content;
} else {
if (content instanceof HTMLElement) {
this.element.appendChild(content);
} else { } else {
const el = new HTMLBuilder(content); const el = new HTMLBuilder(content);
this.element.appendChild(el.element) this.element.appendChild(el.element)
} }
} }
}
setMouseMoveListener(cb: Function) { setMouseMoveListener(cb: Function) {
this.element.addEventListener('mousemove', () => cb()); this.element.addEventListener('mousemove', () => cb());
@@ -92,6 +97,10 @@ export default class HTMLBuilder {
this.element.addEventListener('keyup', () => cb(this.element.innerHTML)); this.element.addEventListener('keyup', () => cb(this.element.innerHTML));
} }
setChangeListener(cb: Function) {
this.element.addEventListener('change', (e) => cb(e));
}
getElement() { getElement() {
return this.element; return this.element;
} }

View File

@@ -0,0 +1,30 @@
export default class TwitchButton {
element: HTMLButtonElement;
constructor(content: string, type: 'default' | 'outline' = 'default', classes: string|string[] = '') {
this.element = document.createElement('button');
this.element.textContent = content;
this.element.classList.add('twitch-notes_button');
if(type === 'outline') {
this.element.classList.add('twitch-notes_button__outline');
}
if (classes) {
if (typeof classes === 'string') {
this.element.classList.add(classes);
} else {
for (let className of classes) {
this.element.classList.add(className);
}
}
}
}
onClick(cb: Function) {
this.element.addEventListener('click', () => cb());
}
}

View File

@@ -0,0 +1,31 @@
export default class TwitchCloseButton {
element: HTMLButtonElement;
constructor(classes: string|string[] = '') {
this.element = document.createElement('button');
this.element.innerHTML = `<svg width="100%" height="100%" viewBox="0 0 20 20" x="0px" y="0px" class="twitch-notes_x-button">
<g>
<path d="M8.5 10L4 5.5 5.5 4 10 8.5 14.5 4 16 5.5 11.5 10l4.5 4.5-1.5 1.5-4.5-4.5L5.5 16 4 14.5 8.5 10z"></path>
</g>
</svg>`;
this.element.classList.add('twitch-notes_close-button');
if (classes) {
if (typeof classes === 'string') {
this.element.classList.add(classes);
} else {
for (let className of classes) {
this.element.classList.add(className);
}
}
}
}
onClick(cb: Function) {
this.element.addEventListener('click', () => cb());
}
}

View File

@@ -0,0 +1,113 @@
import TwitchCloseButton from "./TwitchCloseButton";
import NoteStorage from "../NoteStorage";
// import openImportNotesWindow from "../openImprtNotesWindow";
import openClearDataWindow from "../openClearDataWindow";
import TwitchButton from "./TwitchButton";
import TwitchNotesWindow from "./TwitchNotesWindow";
import importNotesResult from "../importNotesResult";
import TwitchNotesImportResolve from "./TwitchNotesImportResolve";
export default class TwitchNotesImport {
private static instance?: TwitchNotesImport;
private element?: HTMLDivElement;
private userList?: HTMLDivElement;
private static resolveCallback?: Function;
constructor() {
this.element = document.createElement('div');
}
private create() {
if (!this.element) {
this.element = document.createElement('div');
}
this.element.innerHTML = '';
this.element.classList.add('twitch-notes-blurred-background');
const closeButton = new TwitchCloseButton();
closeButton.onClick(() => {
this.close();
});
const container = document.createElement('div');
container.classList.add('twitch-notes-center-floating-container');
const header = document.createElement('div');
header.classList.add('twitch-notes-container-header');
const title = document.createElement('div');
title.classList.add('twitch-notes-container-header-title');
title.textContent = 'Import Notes';
header.appendChild(title);
container.appendChild(header);
header.insertAdjacentElement("beforeend", closeButton.element);
const content = document.createElement('div');
content.classList.add('twitch-notes-container-content');
content.style.display = 'block';
content.style.padding = '1rem';
container.appendChild(content);
content.innerHTML = `
<strong>WARNING!</strong> <em>This action might override existing data!</em><br />
<br />
Select exported twitch notes file<br />
`;
const blurredBackground = this.element;
const input = document.createElement('input');
input.classList.add('twitch-notes-file-input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'json');
input.addEventListener('change', () => {
if (!input.files) return;
// @ts-ignore
let file = input.files.item(0);
if (!file) return;
let reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function (evt) {
if (!evt?.target?.result) return;
NoteStorage.inputData = JSON.parse(evt.target.result.toString());
if (NoteStorage.inputData) {
input.style.display = 'none';
importNotesResult(container, blurredBackground, TwitchNotesImport.resolveCallback);
}
}
reader.onerror = function () {
console.error("error reading file");
}
});
content.appendChild(input);
this.element.appendChild(container);
document.body.appendChild(this.element);
}
private close() {
if (this.element) this.element.remove();
this.element = undefined;
}
public static update() {
TwitchNotesImport.instance?.create();
}
public static open(cb: Function) {
TwitchNotesImport.resolveCallback = cb;
TwitchNotesImport.instance = new TwitchNotesImport();
TwitchNotesImport.instance.create();
}
public static close() {
TwitchNotesImport.instance?.element?.remove();
TwitchNotesImport.instance = undefined;
}
}

View File

@@ -0,0 +1,76 @@
import TwitchCloseButton from "./TwitchCloseButton";
import NoteStorage from "../NoteStorage";
// import openImportNotesWindow from "../openImprtNotesWindow";
import openClearDataWindow from "../openClearDataWindow";
import TwitchButton from "./TwitchButton";
import TwitchNotesWindow from "./TwitchNotesWindow";
import importNotesResult from "../importNotesResult";
import importNotesConflictResolve from "../importNotesConflictResolve";
import HTMLBuilder from "../HTMLBuilder";
export default class TwitchNotesImportResolve {
private static instance?: TwitchNotesImportResolve;
private element?: HTMLDivElement;
constructor() {
this.element = document.createElement('div');
}
private create(
user: string,
parentContainer: HTMLElement,
blurredBackground: HTMLElement
) {
if (!this.element) {
this.element = document.createElement('div');
}
this.element.innerHTML = '';
this.element.classList.add('twitch-notes-blurred-background');
const closeButton = new TwitchCloseButton();
closeButton.onClick(() => {
this.close();
});
const container = document.createElement('div');
container.classList.add('twitch-notes-center-floating-container');
const header = document.createElement('div');
header.classList.add('twitch-notes-container-header');
const title = document.createElement('div');
title.classList.add('twitch-notes-container-header-title');
title.textContent = 'Resolve note ('+user+') conflict';
header.appendChild(title);
container.appendChild(header);
header.insertAdjacentElement("beforeend", closeButton.element);
const content = document.createElement('div');
content.classList.add('twitch-notes-container-content');
content.style.display = 'block';
content.style.padding = '1rem';
container.appendChild(content);
content.appendChild(importNotesConflictResolve(user, this.element, parentContainer, blurredBackground));
this.element.appendChild(container);
document.body.appendChild(this.element);
}
private close() {
if (this.element) this.element.remove();
this.element = undefined;
}
public static open(user: string,
container: HTMLElement,
blurredBackground: HTMLElement) {
TwitchNotesImportResolve.instance = new TwitchNotesImportResolve();
TwitchNotesImportResolve.instance.create(user, container, blurredBackground);
}
}

View File

@@ -0,0 +1,259 @@
import TwitchCloseButton from "./TwitchCloseButton";
import NoteStorage from "../NoteStorage";
// import openImportNotesWindow from "../openImprtNotesWindow";
import openClearDataWindow from "../openClearDataWindow";
import TwitchButton from "./TwitchButton";
import TwitchNotesImport from "./TwitchNotesImport";
export default class TwitchNotesWindow {
private static instance?: TwitchNotesWindow;
private element?: HTMLDivElement;
private userList?: HTMLDivElement;
constructor() {
this.element = document.createElement('div');
}
private buildContent(content: HTMLDivElement) {
content.innerHTML = '';
const userButtons: HTMLDivElement[] = [];
this.userList = document.createElement('div');
this.userList.classList.add('twitch-notes-container-content-user-list');
const addNoteButton = document.createElement('div');
addNoteButton.classList.add('twitch-notes-container-content-user-list-item');
addNoteButton.textContent = '+ Add New Note';
addNoteButton.addEventListener('click', () => {
this.newNote(noteContainer, userButtons);
});
this.userList.appendChild(addNoteButton);
const searchField = document.createElement('input');
searchField.classList.add('twitch-notes-container-content-user-list-item');
searchField.classList.add('twitch-notes-container-content-user-list-item-search');
searchField.placeholder = 'Search...'
searchField.addEventListener('keyup', () => {
for(let row of userButtons) {
if (searchField.value === '') {
row.style.display = 'block';
continue;
}
if(row.textContent?.includes(searchField.value)) {
row.style.display = 'block';
} else {
row.style.display = 'none';
}
}
});
this.userList.appendChild(searchField);
for (const user of NoteStorage.getSavedUserList()) {
const userButton = document.createElement('div');
userButton.classList.add('twitch-notes-container-content-user-list-item');
userButton.textContent = user;
userButtons.push(userButton);
this.userList.appendChild(userButton);
userButton.addEventListener('click', () => {
this.openNote(noteContainer, user, userButtons, userButton);
});
}
const noteContainer = document.createElement('div');
noteContainer.classList.add('twitch-notes-container-content-note-container');
if (NoteStorage.getSavedUserList().length) {
userButtons[0].click();
} else {
noteContainer.textContent = '';
const noNotes = document.createElement('div');
noNotes.classList.add('twitch-notes-container-content-note-container-note');
noNotes.innerHTML = 'You have not notes yet...';
noteContainer.appendChild(noNotes);
}
content.appendChild(this.userList);
content.appendChild(noteContainer);
}
private newNote(noteContainer: HTMLDivElement, userButtons: HTMLDivElement[]) {
noteContainer.innerHTML = '';
for (let btn of userButtons) {
btn.style.background = 'transparent';
}
const noteTitle = document.createElement('input');
noteTitle.classList.add('twitch-notes-container-header-title');
noteTitle.classList.add('twitch-notes-container-content-user-list-item-search');
noteTitle.style.marginTop = '1rem';
noteTitle.placeholder = 'Note title or username';
noteContainer.appendChild(noteTitle);
const note = document.createElement('div');
note.classList.add('twitch-notes-container-content-note-container-note');
note.setAttribute('contentEditable', 'true');
note.innerHTML = '';
noteContainer.appendChild(note);
const controls = document.createElement('div');
controls.classList.add('twitch-notes-container-content-note-container-controls');
noteContainer.appendChild(controls);
const save = new TwitchButton('Save');
controls.appendChild(save.element);
const savedNote = document.createElement('span');
savedNote.classList.add('twitch-notes-container-content-note-container-controls-saved')
savedNote.textContent = 'Note Saved!';
savedNote.style.opacity = '0';
controls.appendChild(savedNote);
save.onClick(() => {
const user = noteTitle.value.trim().toLowerCase();
const userButton = document.createElement('div');
userButton.classList.add('twitch-notes-container-content-user-list-item');
userButton.textContent = user;
userButtons.push(userButton);
this.userList?.appendChild(userButton);
userButton.addEventListener('click', () => {
this.openNote(noteContainer, user, userButtons, userButton);
});
userButtons.push(userButton);
NoteStorage.saveNote(user, note.innerHTML);
this.openNote(noteContainer, user, userButtons, userButton);
});
}
private openNote(noteContainer: HTMLDivElement, user: string, userButtons: HTMLDivElement[], userButton: HTMLDivElement) {
noteContainer.innerHTML = '';
for (let btn of userButtons) {
btn.style.background = 'transparent';
}
userButton.style.background = 'var(--color-twitch-purple-5)'
const noteTitle = document.createElement('div');
noteTitle.classList.add('twitch-notes-container-header-title');
noteTitle.textContent = user;
noteTitle.style.marginTop = '1rem';
noteContainer.appendChild(noteTitle);
const note = document.createElement('div');
note.classList.add('twitch-notes-container-content-note-container-note');
note.setAttribute('contentEditable', 'true');
note.innerHTML = NoteStorage.getNote(user);
noteContainer.appendChild(note);
const controls = document.createElement('div');
controls.classList.add('twitch-notes-container-content-note-container-controls');
noteContainer.appendChild(controls);
const save = new TwitchButton('Save');
controls.appendChild(save.element);
const savedNote = document.createElement('span');
savedNote.classList.add('twitch-notes-container-content-note-container-controls-saved')
savedNote.textContent = 'Note Saved!';
savedNote.style.opacity = '0';
controls.appendChild(savedNote);
save.onClick(() => {
NoteStorage.saveNote(user, note.innerHTML);
savedNote.style.opacity = '1';
});
}
private create() {
if (!this.element) {
this.element = document.createElement('div');
}
this.element.innerHTML = '';
this.element.classList.add('twitch-notes-blurred-background');
const closeButton = new TwitchCloseButton();
closeButton.onClick(() => {
this.close();
});
const container = document.createElement('div');
container.classList.add('twitch-notes-center-floating-container');
const header = document.createElement('div');
header.classList.add('twitch-notes-container-header');
const title = document.createElement('div');
title.classList.add('twitch-notes-container-header-title');
title.textContent = 'Twitch Notes';
header.appendChild(title);
container.appendChild(header);
header.insertAdjacentElement("beforeend", closeButton.element);
const content = document.createElement('div');
content.classList.add('twitch-notes-container-content')
container.appendChild(content);
this.buildContent(content);
const footer = document.createElement('div');
footer.classList.add('twitch-notes-container-footer');
container.appendChild(footer);
const exportNotes = document.createElement('span');
exportNotes.classList.add('twitch-notes-link');
exportNotes.textContent = 'Export Notes';
exportNotes.addEventListener('click', () => {
NoteStorage.exportNotes();
})
footer.appendChild(exportNotes);
const importNotes = document.createElement('span');
importNotes.classList.add('twitch-notes-link');
importNotes.textContent = 'Import Notes';
importNotes.addEventListener('click', () => {
TwitchNotesImport.open(() => {
TwitchNotesWindow.update();
});
});
footer.appendChild(importNotes);
const clearNotes = document.createElement('span');
clearNotes.classList.add('twitch-notes-link');
clearNotes.textContent = 'Clear Notes';
clearNotes.addEventListener('click', () => {
openClearDataWindow();
});
footer.appendChild(clearNotes);
this.element.appendChild(container);
document.body.appendChild(this.element);
}
private close() {
if (this.element) this.element.remove();
this.element = undefined;
}
public static update() {
TwitchNotesWindow.instance?.create();
}
public static toggle() {
if (!TwitchNotesWindow.instance) {
TwitchNotesWindow.instance = new TwitchNotesWindow();
TwitchNotesWindow.instance.create();
return;
}
if (TwitchNotesWindow.instance.element) {
TwitchNotesWindow.instance.close();
} else {
TwitchNotesWindow.instance.create();
}
}
}

View File

@@ -18,7 +18,7 @@ export default class Mouse {
} }
static handleMouseUp() { static handleMouseUp() {
NoteContainers.activeContainer = ''; NoteContainers.activeContainer = null;
Mouse.isMouseDown = false; Mouse.isMouseDown = false;
} }

View File

@@ -1,17 +1,17 @@
import HTMLBuilder from "./HTMLBuilder"; import HTMLBuilder from "./HTMLBuilder";
const containers: {[key: string]: HTMLBuilder} = {}; export default class NoteContainers {
static activeContainer: string | null = null;
static containers: { [key: string]: HTMLBuilder } = {};
export default { static addContainer(username: string, container: HTMLBuilder) {
activeContainer: '', if (NoteContainers.containers[username]) return;
containers, NoteContainers.containers[username] = container;
addContainer(username: string, container: HTMLBuilder) { };
if (this.containers[username]) return;
this.containers[username] = container; static removeContainer(username: string) {
}, if (!NoteContainers.containers[username]) return;
removeContainer(username: string) { NoteContainers.containers[username].remove();
if (!this.containers[username]) return; delete NoteContainers.containers[username];
this.containers[username].remove(); };
delete this.containers[username];
}
} }

View File

@@ -2,15 +2,14 @@ import { ELEMENT_ButtonContainer } from "./const";
import toggleSettingsList from "./toggleSettingsList"; import toggleSettingsList from "./toggleSettingsList";
import openTwitchNote from "./openTwitchNote"; import openTwitchNote from "./openTwitchNote";
import HTMLBuilder from "./HTMLBuilder"; import HTMLBuilder from "./HTMLBuilder";
import TwitchButton from "./HTMLElements/TwitchButton";
import TwitchNotesWindow from "./HTMLElements/TwitchNotesWindow";
export default class TwitchNote { export default class TwitchNote {
observer: MutationObserver | null = null; observer?: MutationObserver;
chatContainerNode?: Element; chatContainerNode?: Element;
constructor() {
}
init(chatContainerNode: Element) { init(chatContainerNode: Element) {
this.chatContainerNode = chatContainerNode; this.chatContainerNode = chatContainerNode;
this.startObserver(chatContainerNode); this.startObserver(chatContainerNode);
@@ -55,41 +54,16 @@ export default class TwitchNote {
return; return;
} }
const btn = new HTMLBuilder({ const button = new TwitchButton('Notes', 'outline');
element: 'div', button.onClick(TwitchNotesWindow.toggle);
style: {
marginLeft: "0.5rem !important"
},
content: [
{
element: 'div',
style: {
display: "inline-flex !important"
},
content: [
{
element: 'button',
class: [
'twitch-notes-settings-button',
'twitch-notes-settings-button__outline'
],
content: [
'Notes'
],
mouseClickEvent: () => toggleSettingsList(),
}
]
}
]
});
if (buttonContainer.lastChild) { if (buttonContainer.lastChild) {
buttonContainer.lastChild.insertBefore( buttonContainer.lastChild.insertBefore(
btn.getElement(), button.element,
buttonContainer.lastChild.lastChild buttonContainer.lastChild.lastChild
); );
} else { } else {
buttonContainer.appendChild(btn.getElement()); buttonContainer.appendChild(button.element);
} }
} }

View File

@@ -1,42 +1,51 @@
import {CustomButtonElement, CustomDivElement, CustomHTMLElement, CustomPElement} from "./CustomHTMLElement";
import NoteStorage from "./NoteStorage"; import NoteStorage from "./NoteStorage";
import importNotesResult from "./importNotesResult"; import importNotesResult from "./importNotesResult";
import HTMLBuilder from "./HTMLBuilder";
export default function importNotesConflictResolve( export default function importNotesConflictResolve(
user: string, user: string,
resultsContainer: CustomHTMLElement, resultsContainer: HTMLElement,
container: CustomHTMLElement, container: HTMLElement,
blurredBackground: CustomHTMLElement blurredBackground: HTMLElement
) { ) {
const diffBlurredBackground = new CustomDivElement('twitch-notes-blurred-background');
const diffContainer = new CustomDivElement('twitch-notes-center-floating-container', '<strong>Select which note to keep for <em>' + user + '</em></strong><br /><em>You can modify notes to merge them and keep updated one</em><br /><br />');
const inputContainer = new CustomDivElement();
inputContainer.setStyle({
display: 'flex',
flexDirection: 'row',
flexWrap: 'no-wrap',
width: '100%',
});
const valueStyle = { const valueStyle = {
minWidth: '320px', minWidth: '320px',
padding: '6px', padding: '6px',
border: '1px solid #FFFFFF19', border: '1px solid #FFFFFF19',
outline: 'none', outline: 'none',
}; };
const valueAttr: [string, string] = ['contentEditable', 'true']; const valueAttr = {contentEditable: 'true'};
const localValueContainer = new CustomDivElement(); const diffBlurredBackground = new HTMLBuilder({
const pLocal = new CustomPElement('', '<strong>Locally saved note</strong>'); element: 'div',
localValueContainer.appendCustomChild(pLocal); content: [
'<strong>Select which note to keep for <em>' + user + '</em></strong><br /><em>You can modify notes to merge them and keep updated one</em><br /><br />',
const localValue = new CustomDivElement(); {
localValue.setStyle(valueStyle); element: 'div',
localValue.addAttribute(...valueAttr); class: 'twitch-notes-grid-col-2',
localValue.setId('local-value-container'); style: {
const localValueSave = new CustomButtonElement('twitch-notes-settings-button', 'Save this'); width: '100%',
localValueSave.setClickListener(() => { },
content: [
{
element: 'div',
content: [{
element: 'p',
content: [
'<strong>Locally saved note</strong>',
{
element: 'div',
style: valueStyle,
attributes: valueAttr,
id: 'local-value-container',
content: [NoteStorage.getNote(user)]
},
'<br />',
{
element: 'button',
class: 'twitch-notes_button',
content: ['Save this'],
mouseClickEvent: () => {
const val = document.getElementById('local-value-container')?.innerHTML || ''; const val = document.getElementById('local-value-container')?.innerHTML || '';
NoteStorage.inputData.notes = NoteStorage.inputData.notes.map(n => n.user === user ? { NoteStorage.inputData.notes = NoteStorage.inputData.notes.map(n => n.user === user ? {
user: n.user, user: n.user,
@@ -46,20 +55,30 @@ export default function importNotesConflictResolve(
diffBlurredBackground.remove(); diffBlurredBackground.remove();
resultsContainer.remove(); resultsContainer.remove();
importNotesResult(container, blurredBackground); importNotesResult(container, blurredBackground);
}); }
localValueContainer.appendCustomChild(localValue); }
localValueContainer.appendBody('<br />'); ]
localValueContainer.appendCustomChild(localValueSave); }]
},
const importedValueContainer = new CustomDivElement(); {
const iLocal = new CustomPElement('', '<strong>Imported note</strong>'); element: 'div',
importedValueContainer.appendCustomChild(iLocal); content: [{
const importedValue = new CustomDivElement('', NoteStorage.inputData.notes.filter(n => n.user === user)[0].note || ''); element: 'p',
importedValue.setId('import-value-container'); content: [
importedValue.setStyle(valueStyle); '<strong>Locally saved note</strong>',
importedValue.addAttribute(...valueAttr); {
const importedValueSave = new CustomButtonElement('twitch-notes-settings-button', 'Save this'); element: 'div',
importedValueSave.setClickListener(() => { style: valueStyle,
attributes: valueAttr,
id: 'import-value-container',
content: [NoteStorage.inputData.notes.filter(n => n.user === user)[0].note || '']
},
'<br />',
{
element: 'button',
class: 'twitch-notes_button',
content: ['Save this'],
mouseClickEvent: () => {
const val = document.getElementById('import-value-container')?.innerHTML || ''; const val = document.getElementById('import-value-container')?.innerHTML || '';
NoteStorage.inputData.notes = NoteStorage.inputData.notes.map(n => n.user === user ? { NoteStorage.inputData.notes = NoteStorage.inputData.notes.map(n => n.user === user ? {
user: n.user, user: n.user,
@@ -69,17 +88,14 @@ export default function importNotesConflictResolve(
diffBlurredBackground.remove(); diffBlurredBackground.remove();
resultsContainer.remove(); resultsContainer.remove();
importNotesResult(container, blurredBackground); importNotesResult(container, blurredBackground);
}
}
]
}]
}
]
}
]
}); });
return diffBlurredBackground.getElement();
importedValueContainer.appendCustomChild(importedValue);
importedValueContainer.appendBody('<br />');
importedValueContainer.appendCustomChild(importedValueSave);
inputContainer.appendCustomChild(localValueContainer);
inputContainer.appendCustomChild(importedValueContainer);
diffContainer.appendCustomChild(inputContainer);
diffBlurredBackground.appendCustomChild(diffContainer);
document.body.appendChild(diffBlurredBackground.getElement());
} }

View File

@@ -1,8 +1,10 @@
import {CustomAElement, CustomButtonElement, CustomDivElement, CustomHTMLElement} from "./CustomHTMLElement";
import NoteStorage from "./NoteStorage"; import NoteStorage from "./NoteStorage";
import importNotesConflictResolve from "./importNotesConflictResolve"; import importNotesConflictResolve from "./importNotesConflictResolve";
import HTMLBuilder from "./HTMLBuilder";
import TwitchButton from "./HTMLElements/TwitchButton";
import TwitchNotesImportResolve from "./HTMLElements/TwitchNotesImportResolve";
export default function importNotesResult(container: CustomHTMLElement, blurredBackground: CustomHTMLElement) { export default function importNotesResult(container: HTMLElement, blurredBackground: HTMLElement, cb?: Function) {
const willBeAdded = []; const willBeAdded = [];
let willBeOverwritten = []; let willBeOverwritten = [];
const noChanges = []; const noChanges = [];
@@ -19,71 +21,85 @@ export default function importNotesResult(container: CustomHTMLElement, blurredB
} }
} }
const resultsContainer = new CustomDivElement(); const resultsContainer = new HTMLBuilder({
element: 'div',
style: {
padding: '1rem'
}
});
if (willBeOverwritten.length) { if (willBeOverwritten.length) {
const overwrittenContainer = new CustomDivElement('', '<strong>Note conflicts found for:</strong><br />'); const overwrittenContainer = new HTMLBuilder({
overwrittenContainer.setStyle({marginTop: '1rem'}); element: 'div',
content: ['<strong>Note conflicts found for:</strong><br />'],
style: {
marginTop: '1rem',
}
});
for (let item of willBeOverwritten) { for (let item of willBeOverwritten) {
const row = new CustomDivElement('', item + ' ');
const isResolved = NoteStorage.inputData.notes.find(note => note.user === item)?.resolved; const isResolved = NoteStorage.inputData.notes.find(note => note.user === item)?.resolved;
row.setStyle({ overwrittenContainer.addContent({
color: isResolved ? 'green' : 'red', element: 'div',
}); content: [item + ' ', {
const resolve = new CustomAElement('', isResolved ? '[update]' : '[resolve]'); element: 'a',
resolve.setStyle({ content: [isResolved ? '[update]' : '[resolve]'],
cursor: 'pointer' style: {
}); cursor: 'pointer',
},
resolve.setClickListener(() => { mouseClickEvent: () => {
importNotesConflictResolve(item, resultsContainer, container, blurredBackground); TwitchNotesImportResolve.open(item, container, blurredBackground);
}) // importNotesConflictResolve(item, resultsContainer, container, blurredBackground);
row.appendCustomChild(resolve);
overwrittenContainer.appendCustomChild(row);
} }
resultsContainer.appendCustomChild(overwrittenContainer); }],
style: {
color: isResolved ? 'green' : 'red',
}
});
}
resultsContainer.addContent(overwrittenContainer.getElement());
} }
if (willBeAdded.length) { if (willBeAdded.length) {
const addedContainer = new CustomDivElement('', '<strong>Note will be added for:</strong><br />' + willBeAdded.join('<br />')); resultsContainer.addContent({
addedContainer.setStyle({ element: 'div',
content: ['<strong>Note will be added for:</strong><br />' + willBeAdded.join('<br />')],
style: {
marginTop: '1rem', marginTop: '1rem',
color: 'white' color: 'white'
}
}); });
resultsContainer.appendCustomChild(addedContainer);
} }
if (noChanges.length) { if (noChanges.length) {
const noChangesContainer = new CustomDivElement('', '<strong>No changes for:</strong><br />' + noChanges.join('<br />')); resultsContainer.addContent({
noChangesContainer.setStyle({ element: 'div',
content: ['<strong>No changes for:</strong><br />' + noChanges.join('<br />')],
style: {
marginTop: '1rem', marginTop: '1rem',
color: 'gray' color: 'gray'
}
}); });
resultsContainer.appendCustomChild(noChangesContainer);
} }
const spacer = new CustomDivElement(); resultsContainer.addContent({element: 'div', style: {height: '24px'}});
spacer.setStyle({height: '24px'});
resultsContainer.appendCustomChild(spacer);
willBeOverwritten = willBeOverwritten.filter(x => !NoteStorage.inputData.notes.find(n => n.user === x)?.resolved); willBeOverwritten = willBeOverwritten.filter(x => !NoteStorage.inputData.notes.find(n => n.user === x)?.resolved);
const saveButton = new CustomButtonElement('twitch-notes-settings-button', 'Complete import'); const saveButton = new TwitchButton('Complete import');
saveButton.setStyle({}) if (willBeOverwritten.length > 0) saveButton.element.style.background = 'gray';
if (willBeOverwritten.length > 0) saveButton.setStyle({background: 'gray'}); if (willBeOverwritten.length > 0) saveButton.element.setAttribute('disabled', 'true');
if (willBeOverwritten.length > 0) saveButton.addAttribute('disabled', 'true');
resultsContainer.appendCustomChild(saveButton) resultsContainer.addContent(saveButton.element)
if (willBeOverwritten.length > 0) { if (willBeOverwritten.length > 0) {
const note = new CustomDivElement('', '<em>Import cannot be completed while there are unresolved conflicts</em>'); resultsContainer.addContent({
note.setStyle({ element: 'div',
color: 'gray', content: ['<em>Import cannot be completed while there are unresolved conflicts</em>'],
style: {color: 'gray'}
}); });
resultsContainer.appendCustomChild(note);
} else { } else {
saveButton.setClickListener(() => { saveButton.element.addEventListener('click', () => {
for (let note of NoteStorage.inputData.notes) { for (let note of NoteStorage.inputData.notes) {
NoteStorage.saveNote(note.user, note.note); NoteStorage.saveNote(note.user, note.note);
} }
@@ -93,8 +109,10 @@ export default function importNotesResult(container: CustomHTMLElement, blurredB
notes: [], notes: [],
settings: {}, settings: {},
}; };
cb ? cb() : () => {};
}); });
} }
container.appendCustomChild(resultsContainer); container.innerHTML = '';
container.appendChild(resultsContainer.getElement());
} }

View File

@@ -1,75 +1,90 @@
import {CustomButtonElement, CustomDivElement, CustomSpanElement} from "./CustomHTMLElement";
import NoteStorage from "./NoteStorage"; import NoteStorage from "./NoteStorage";
import {getCloseButtonSVG} from "./HTMLTemplates"; import {getCloseButtonSVG} from "./HTMLTemplates";
import HTMLBuilder from "./HTMLBuilder";
export default function openAllNoteListWindow() { export default function openAllNoteListWindow() {
let activeNote: string = ''; let activeNote: string = '';
const blurredBackground = new CustomDivElement('twitch-notes-blurred-background'); const blurredBackground = new HTMLBuilder({element: "div", class: 'twitch-notes-blurred-background'});
const noteSaved = new CustomSpanElement('', 'Note saved!'); const noteSaved = new HTMLBuilder({
noteSaved.setStyle({ element: 'span',
content: ['Note saved!'],
style: {
color: 'green', color: 'green',
marginLeft: '2rem', marginLeft: '2rem',
display: 'none'
}
}); });
noteSaved.hide();
const container = new CustomDivElement('twitch-notes-center-floating-container'); const content = new HTMLBuilder({
container.setStyle({ element: 'div',
style: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'no-wrap',
width: '100%',
height: '320px'
}
});
const closeButton = new HTMLBuilder({
element: 'button',
class: 'twitch-notes-settings-close-button',
content: [getCloseButtonSVG()],
style: {
position: 'absolute',
top: '1rem',
right: '1rem',
},
mouseClickEvent: () => {
blurredBackground.remove();
}
});
const container = new HTMLBuilder({
element: 'div',
class: 'twitch-notes-center-floating-container',
style: {
padding: '0', padding: '0',
paddingTop: '1rem', paddingTop: '1rem',
width: '100%', width: '100%',
maxWidth: '800px', maxWidth: '800px',
height: 'calc(320px + 5rem)', height: 'calc(320px + 5rem)',
maxHeight: '90vh', maxHeight: '90vh',
}); },
content: [
const closeButton = new CustomButtonElement('twitch-notes-settings-close-button', getCloseButtonSVG()); {
closeButton.setStyle({ element: 'div',
position: 'absolute', class: 'twitch-notes-title',
top: '1rem', content: ['Notes:'],
right: '1rem', style: {
});
const title = new CustomDivElement('twitch-note-title', 'Notes:');
title.setStyle({
borderBottom: '1px solid #FFFFFF19', borderBottom: '1px solid #FFFFFF19',
paddingBottom: '1rem', paddingBottom: '1rem',
}); }
container.appendCustomChild(title); },
content.getElement(),
const content = new CustomDivElement(); closeButton.getElement()
content.setStyle({ ]
display: 'flex',
flexDirection: 'row',
flexWrap: 'no-wrap',
width: '100%',
height: '320px'
});
container.appendCustomChild(content);
closeButton.setClickListener(() => {
blurredBackground.remove();
});
container.appendCustomChild(closeButton);
const userList = new CustomDivElement();
userList.setStyle({
borderRight: '1px solid #FFFFFF19',
height: '320px',
minWidth: '240px',
overflowY: 'auto',
overflowX: 'hidden',
}); });
const noteContainer = new CustomDivElement(); const userList = new HTMLBuilder({
noteContainer.setStyle({ element: 'div',
class: 'twitch-notes-user-list'
});
const noteContainer = new HTMLBuilder({
element: 'div',
style: {
height: '320px', height: '320px',
padding: '1rem', padding: '1rem',
width: '100%', width: '100%',
opacity: '0', opacity: '0',
}
}); });
const note = new CustomDivElement(); const note = new HTMLBuilder({
note.setStyle({ element: 'div',
style: {
marginBottom: '3rem', marginBottom: '3rem',
border: '1px solid #FFFFFF19', border: '1px solid #FFFFFF19',
height: 'calc(320px - 7rem)', height: 'calc(320px - 7rem)',
@@ -78,49 +93,57 @@ export default function openAllNoteListWindow() {
outline: 'none', outline: 'none',
overflowY: 'auto', overflowY: 'auto',
overflowX: 'hidden', overflowX: 'hidden',
},
attributes: {
contentEditable: 'true'
}
}); });
note.addAttribute('contentEditable', 'true');
const saveNote = new CustomButtonElement('twitch-notes-settings-button','Save Note'); const saveNote = new HTMLBuilder({
saveNote.setStyle({ element: 'button',
class: 'twitch-notes-settings-button',
content: ['Save Note'],
style: {
position: 'absolute', position: 'absolute',
bottom: '1rem', bottom: '1rem',
left: '1rem' left: '1rem'
}); },
mouseClickEvent: () => {
saveNote.setClickListener(() => { if (!activeNote) {
if(!activeNote) {
return; return;
} }
NoteStorage.saveNote(activeNote, note.getElement().innerHTML); NoteStorage.saveNote(activeNote, note.getElement().innerHTML);
noteSaved.setStyle({ noteSaved.getElement().style.display = 'inline-block';
display: 'inline-block', }
});
}); });
for(let user of NoteStorage.getSavedUserList()) { for (let user of NoteStorage.getSavedUserList()) {
const userLine = new CustomDivElement('twitch-notes-user-list-user', user); const userLine = new HTMLBuilder({
userLine.setClickListener(() => { element: 'div',
class: 'twitch-notes-user-list-user',
content: [user],
mouseClickEvent: () => {
const list = document.getElementsByClassName('twitch-notes-user-list-user'); const list = document.getElementsByClassName('twitch-notes-user-list-user');
for(let i = 0; i < list.length; i++) { for (let i = 0; i < list.length; i++) {
list.item(i)?.removeAttribute('data-active'); list.item(i)?.removeAttribute('data-active');
} }
noteSaved.hide(); noteSaved.getElement().style.display = 'none';
userLine.addAttribute('data-active', 'true'); userLine.addAttribute('data-active', 'true');
noteContainer.setStyle({opacity: '1'}); noteContainer.getElement().style.opacity = '1';
note.getElement().innerHTML = NoteStorage.getNote(user); note.getElement().innerHTML = NoteStorage.getNote(user);
activeNote = user; activeNote = user;
}
}); });
userList.appendCustomChild(userLine); userList.addContent(userLine.getElement());
} }
noteContainer.appendCustomChild(note); noteContainer.addContent(note.getElement());
noteContainer.appendCustomChild(saveNote); noteContainer.addContent(saveNote.getElement());
noteContainer.appendCustomChild(noteSaved); noteContainer.addContent(noteSaved.getElement());
content.appendCustomChild(userList); content.addContent(userList.getElement());
content.appendCustomChild(noteContainer); content.addContent(noteContainer.getElement());
blurredBackground.appendCustomChild(container); blurredBackground.addContent(container.getElement());
document.body.appendChild(blurredBackground.getElement()); document.body.appendChild(blurredBackground.getElement());
} }

View File

@@ -1,28 +1,48 @@
import {CustomButtonElement, CustomDivElement} from "./CustomHTMLElement";
import NoteStorage from "./NoteStorage"; import NoteStorage from "./NoteStorage";
import HTMLBuilder from "./HTMLBuilder";
import TwitchNotesWindow from "./HTMLElements/TwitchNotesWindow";
export default function openClearDataWindow() { export default function openClearDataWindow() {
const blurredBackground = new CustomDivElement( 'twitch-notes-blurred-background'); const blurredBackground = new HTMLBuilder({
const container = new CustomDivElement('twitch-notes-center-floating-container', '<strong>This action will delete all saved notes!</strong><br /><br /><em>Consider exporting notes before performing this action in case you will need to use notes again</em>'); element: 'div',
const spacer = new CustomDivElement(); class: 'twitch-notes-blurred-background',
spacer.setStyle({ content: [{
height: '24px' element: 'div',
}); class: 'twitch-notes-center-floating-container',
const deleteAction = new CustomButtonElement('twitch-notes-settings-button', 'DELETE ALL NOTES'); style: {
deleteAction.setStyle({ padding: '1rem',
},
content: [
'<strong>This action will delete all saved notes!</strong><br /><br /><em>Consider exporting notes before performing this action in case you will need to use notes again</em>',
{
element: 'div',
style: {
height: '24px',
}
},
{
element: 'button',
class: 'twitch-notes_button',
content: ['DELETE ALL NOTES'],
style: {
background: 'red' background: 'red'
}); },
deleteAction.setClickListener(() => { mouseClickEvent: () => {
NoteStorage.clearData(); NoteStorage.clearData();
blurredBackground.remove(); blurredBackground.remove();
}); TwitchNotesWindow.update();
const cancelAction = new CustomButtonElement('twitch-notes-settings-button', 'Cancel'); }
cancelAction.setClickListener(() => { },
{
element: 'button',
class: 'twitch-notes_button',
content: ['Cancel'],
mouseClickEvent: () => {
blurredBackground.remove(); blurredBackground.remove();
}
}
]
}]
}); });
container.appendCustomChild(spacer);
container.appendCustomChild(deleteAction);
container.appendCustomChild(cancelAction);
blurredBackground.appendCustomChild(container);
document.body.appendChild(blurredBackground.getElement()); document.body.appendChild(blurredBackground.getElement());
} }

View File

@@ -1,52 +1,73 @@
import {CustomButtonElement, CustomDivElement, CustomInputElement} from "./CustomHTMLElement";
import NoteStorage from "./NoteStorage"; import NoteStorage from "./NoteStorage";
import {getCloseButtonSVG} from "./HTMLTemplates"; import {getCloseButtonSVG} from "./HTMLTemplates";
import importNotesResult from "./importNotesResult"; import importNotesResult from "./importNotesResult";
import HTMLBuilder from "./HTMLBuilder";
export default function openImportNotesWindow() { // export default function openImportNotesWindow() {
const blurredBackground = new CustomDivElement('twitch-notes-blurred-background'); // const blurredBackground = new HTMLBuilder({
const container = new CustomDivElement('twitch-notes-center-floating-container', '<strong>WARNING!</strong> <em>This action might override existing data!</em><br /><br />'); // element: 'div',
const inputBlock = new CustomDivElement('','Select exported twitch notes file<br /><br />'); // class: 'twitch-notes-blurred-background'
const input = new CustomInputElement('twitch-notes-file-input'); // });
input.addAttribute('type', 'file').addAttribute('accept', 'json'); // const container = new HTMLBuilder({
const settingsCloseButton = new CustomButtonElement('twitch-notes-settings-close-button', getCloseButtonSVG()); // element: 'div',
settingsCloseButton.setStyle({ // class: 'twitch-notes-center-floating-container',
position: 'absolute', // style: {
top: '1rem', // padding: '1rem',
right: '1rem', // },
}); // content: [
// '<strong>WARNING!</strong> <em>This action might override existing data!</em><br /><br />',
inputBlock.appendCustomChild(input); // {
// element: 'button',
settingsCloseButton.setClickListener(() => { // class: 'twitch-notes-settings-close-button',
blurredBackground.remove(); // content: [getCloseButtonSVG()],
}) // style: {
// position: 'absolute',
input.setChangeListener(() => { // top: '1rem',
if (!input?.getElement()?.files) return; // right: '1rem',
// @ts-ignore // },
let file = input.getElement().files.item(0); // mouseClickEvent:() => {
if (!file) { // blurredBackground.remove();
return; // }
} // }
let reader = new FileReader(); // ]
reader.readAsText(file, "UTF-8"); // });
reader.onload = function (evt) { // const input = new HTMLBuilder({
if (!evt?.target?.result) return; // element: 'input',
// class: 'twitch-notes-file-input',
NoteStorage.inputData = JSON.parse(evt.target.result.toString()); // attributes: {
if (NoteStorage.inputData) { // type: 'file',
inputBlock.setStyle({display: 'none'}); // accept: 'json'
importNotesResult(container, blurredBackground); // }
} // });
} // const inputBlock = new HTMLBuilder({
reader.onerror = function () { // element: 'div',
console.error("error reading file"); // content: ['Select exported twitch notes file<br /><br />', input.getElement()]
} // });
}); //
// input.setChangeListener(() => {
container.appendCustomChild(settingsCloseButton); // if (!(input?.getElement() as HTMLInputElement)?.files) return;
container.appendCustomChild(inputBlock); // // @ts-ignore
blurredBackground.appendCustomChild(container); // let file = input.getElement().files.item(0);
document.body.appendChild(blurredBackground.getElement()); // if (!file) {
} // return;
// }
// let reader = new FileReader();
// reader.readAsText(file, "UTF-8");
// reader.onload = function (evt) {
// if (!evt?.target?.result) return;
//
// NoteStorage.inputData = JSON.parse(evt.target.result.toString());
// if (NoteStorage.inputData) {
// inputBlock.setStyles({display: 'none'});
// importNotesResult(container, blurredBackground);
// }
// }
// reader.onerror = function () {
// console.error("error reading file");
// }
// });
//
// container.addContent(inputBlock.getElement());
// blurredBackground.addContent(container.getElement());
// document.body.appendChild(blurredBackground.getElement());
// }

View File

@@ -10,7 +10,7 @@ export default function openTwitchNote(username: string) {
let noteContent = NoteStorage.getNote(username); let noteContent = NoteStorage.getNote(username);
const container: HTMLBuilderBlock = { const container: HTMLBuilderBlock = {
element: 'div', element: 'div',
class: 'twitch-note-container', class: 'twitch-notes-floating-container',
style: { style: {
left: Mouse.mousePosition.x + 'px', left: Mouse.mousePosition.x + 'px',
top: Mouse.mousePosition.y + 10 + 'px' top: Mouse.mousePosition.y + 10 + 'px'
@@ -18,7 +18,7 @@ export default function openTwitchNote(username: string) {
content: [ content: [
{ {
element: 'div', element: 'div',
class: 'twitch-note-header', class: 'twitch-notes-header',
mouseDownEvent: () => { mouseDownEvent: () => {
NoteContainers.activeContainer = username; NoteContainers.activeContainer = username;
Mouse.isMouseDown = true; Mouse.isMouseDown = true;
@@ -26,20 +26,20 @@ export default function openTwitchNote(username: string) {
content: [ content: [
{ {
element: 'span', element: 'span',
class: 'twitch-note-close-button', class: 'twitch-notes-close-button',
content: [getCloseButtonSVG()], content: [getCloseButtonSVG()],
mouseClickEvent: () => NoteContainers.removeContainer(username), mouseClickEvent: () => NoteContainers.removeContainer(username),
}, },
{ {
element: 'span', element: 'span',
class: 'twitch-note-title', class: 'twitch-notes-title',
content: [username], content: [username],
} }
] ]
}, },
{ {
element: 'div', element: 'div',
class: 'twitch-note-content', class: 'twitch-notes-content',
content: [NoteStorage.getNote(username)], content: [NoteStorage.getNote(username)],
attributes: { attributes: {
contentEditable: 'true' contentEditable: 'true'
@@ -50,7 +50,7 @@ export default function openTwitchNote(username: string) {
}, },
{ {
element: 'div', element: 'div',
class: 'twitch-note-save-button', class: 'twitch-notes-save-button',
content: ['SAVE'], content: ['SAVE'],
mouseClickEvent: () => { mouseClickEvent: () => {
NoteStorage.saveNote(username, noteContent); NoteStorage.saveNote(username, noteContent);

View File

@@ -1,79 +1,6 @@
.twitch-note-container { .twitch-notes {
position: fixed;
z-index: 1000000;
min-width: 420px;
max-width: 95vw;
min-height: 240px;
max-height: 50vh;
background: var(--color-background-base);
border: var(--border-width-default) solid var(--color-border-base) !important;
}
.twitch-note-header { &_button {
width: 100%;
height: 32px;
line-height: 32px;
border-bottom: var(--border-width-default) solid var(--color-border-base) !important;
position: relative;
cursor: move;
}
.twitch-note-title {
color: var(--color-text-alt) !important;
font-size: var(--font-size-6) !important;
font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
padding-left: calc((32px - var(--font-size-6)) / 2);
}
.twitch-note-close-button {
position: absolute;
right: 5px;
top: 5px;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
aspect-ratio: 1;
color: var(--color-text-alt) !important;
font-size: var(--font-size-6) !important;
font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
cursor: pointer;
}
.twitch-note-content {
position: absolute;
top: 32px;
left: 0;
right: 0;
bottom: 32px;
background: transparent;
color: var(--color-text-base) !important;
font-family: var(--font-base);
vertical-align: baseline;
outline: none;
overflow: auto;
padding: calc((32px - var(--font-size-6)) / 2);
}
.twitch-note-save-button {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 32px;
border-top: var(--border-width-default) solid var(--color-border-base) !important;
cursor: pointer;
color: var(--color-text-alt) !important;
font-size: var(--font-size-6) !important;
font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
text-align: center;
line-height: 32px;
}
.twitch-notes-settings-button {
z-index: var(--z-index-default) !important; z-index: var(--z-index-default) !important;
position: relative !important; position: relative !important;
background-color: var(--color-background-button-primary-default); background-color: var(--color-background-button-primary-default);
@@ -99,77 +26,10 @@
background: transparent; background: transparent;
border: 2px solid var(--color-text-button-primary); border: 2px solid var(--color-text-button-primary);
} }
}
.twitch-notes-settings-container { }
border: 0;
font: inherit;
padding: 0;
vertical-align: baseline;
position: fixed;
z-index: var(--z-index-balloon);
inset: auto 0 0 auto;
margin: 0 69px 48px 0;
}
.twitch-notes-settings-balloon { &_close-button {
display: inline-block;
max-width: 90vw;
min-width: 0;
white-space: nowrap;
border-radius: 0.6rem !important;
background-color: var(--color-background-base) !important;
box-shadow: var(--shadow-elevation-2) !important;
color: inherit !important;
}
.twitch-notes-settings-popover {
white-space: normal;
width: 32rem;
}
.twitch-notes-settings-header {
display: flex !important;
-webkit-box-align: center !important;
align-items: center !important;
position: relative !important;
padding-left: 1rem !important;
padding-right: 1rem !important;
background-color: var(--color-background-base) !important;
min-height: 4rem;
}
.twitch-notes-settings-header-left-element {
left: 0 !important;
margin-right: 0.5rem !important;
width: 3rem;
}
.twitch-notes-settings-header-center-element {
-webkit-box-align: center !important;
align-items: center !important;
display: flex !important;
text-align: center !important;
-webkit-box-flex: 1 !important;
flex-grow: 1 !important;
-webkit-box-pack: center !important;
justify-content: center !important;
}
.twitch-notes-settings-header-center-element-content {
line-height: 1.5;
color: var(--color-text-alt) !important;
font-size: var(--font-size-5) !important;
font-weight: var(--font-weight-semibold) !important;
}
.twitch-notes-settings-header-right-element {
right: 0 !important;
margin-left: 0.5rem !important;
}
.twitch-notes-settings-close-button {
cursor: default; cursor: default;
text-transform: none; text-transform: none;
text-indent: 0; text-indent: 0;
@@ -188,7 +48,7 @@
overflow: hidden; overflow: hidden;
text-decoration: none; text-decoration: none;
white-space: nowrap; white-space: nowrap;
position: relative; position: absolute;
display: inline-flex; display: inline-flex;
-webkit-box-align: center; -webkit-box-align: center;
align-items: center; align-items: center;
@@ -200,103 +60,244 @@
width: calc(var(--button-size-default) - 1rem); width: calc(var(--button-size-default) - 1rem);
background-color: var(--color-background-button-text-default); background-color: var(--color-background-button-text-default);
color: var(--color-fill-button-icon); color: var(--color-fill-button-icon);
} top: 1rem;
right: 1rem;
.twitch-notes-settings-scrollable-area { .twitch-notes_x-button {
display: flex; position: absolute;
overflow: hidden; left: 0;
z-index: 0; width: calc(var(--button-size-default) - 1rem);
height: 100%; height: calc(var(--button-size-default) - 1rem);
position: relative; top: 0;
max-height: 478px; fill: currentcolor;
} }
}
.twitch-notes-settings-content { &-floating-container {
box-sizing: content-box; position: fixed;
min-width: 100%; z-index: 1000000;
overflow-x: hidden; width: 320px;
overflow-y: auto; height: 240px;
max-height: inherit !important; background: var(--color-background-base);
margin: 1rem; border: var(--border-width-default) solid var(--color-border-base) !important;
padding-bottom: 0 !important; }
}
.twitch-notes-settings-option-line { &-container {
position: relative !important; position: fixed;
width: calc(100% - 2rem) !important; z-index: 1000000;
} min-width: 500px;
max-width: 95vw;
min-height: 240px;
max-height: 50vh;
background: var(--color-background-base);
border: var(--border-width-default) solid var(--color-border-base) !important;
.twitch-notes-settings-option-line-button { &-header {
border-radius: var(--border-radius-medium);
display: block;
width: 100%; width: 100%;
color: inherit; height: calc(var(--button-size-default) + 1rem);
} line-height: calc(var(--button-size-default) + 1rem);
border-bottom: var(--border-width-default) solid var(--color-border-base) !important;
position: relative;
.twitch-notes-settings-option-line-button:hover { &-title {
color: var(--color-text-alt) !important;
font-size: var(--font-size-6) !important;
font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
margin-left: calc((32px - var(--font-size-6)) / 2);
width: calc(100% - 2rem);
}
}
&-content {
display: grid;
grid-template-columns: 240px 1fr;
&-user-list {
border-right: 1px solid #FFFFFF19;
height: 100%;
min-width: 240px;
overflow-y: auto;
overflow-x: hidden;
&-item {
padding: 1rem;
border-bottom: var(--border-width-default) solid var(--color-border-base) !important;
cursor: pointer; cursor: pointer;
text-decoration: none; width: 100%;
color: inherit; color: var(--color-text-alt) !important;
background-color: var(--color-background-interactable-hover); font-size: var(--font-size-6) !important;
} font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
.twitch-notes-settings-option-line-button-container { &-search {
display: flex !important; background: transparent;
-webkit-box-align: center !important; outline: none;
align-items: center !important; color: var(--color-fill-button-icon);
position: relative !important; }
padding: 0.5rem !important; }
} }
.twitch-notes-settings-option-line-button-container-content { &-note-container {
-webkit-box-flex: 1 !important;
flex-grow: 1 !important;
}
.twitch-note-settings-separator { &-note {
border-top: 1px solid var(--color-border-base); min-width: 420px;
margin-top: 1rem !important; min-height: 320px;
margin-left: 0.5rem !important; display: block;
margin-right: 0.5rem !important; margin: 1rem;
padding-bottom: 1rem !important; border: var(--border-width-default) solid var(--color-border-base) !important;
} padding: 1rem;
}
.twitch-notes-x-button { &-controls {
padding: 1rem;
display: flex;
align-content: center;
&-saved {
color: green;
padding-left: 1rem;
line-height: var(--button-size-default);
}
}
}
}
&-footer {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
width: 100%;
border-top: var(--border-width-default) solid var(--color-border-base) !important;
padding: 1rem;
text-align: center;
}
}
&-header {
width: 100%;
height: 32px;
line-height: 32px;
border-bottom: var(--border-width-default) solid var(--color-border-base) !important;
position: relative;
cursor: move;
}
&--container-header-title {
color: var(--color-text-alt) !important;
font-size: var(--font-size-6) !important;
font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
padding-left: calc((32px - var(--font-size-6)) / 2);
}
&-title {
color: var(--color-text-alt) !important;
font-size: var(--font-size-6) !important;
font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
padding-left: calc((32px - var(--font-size-6)) / 2);
}
&-close-button {
position: absolute;
right: 5px;
top: 5px;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
aspect-ratio: 1;
color: var(--color-text-alt) !important;
font-size: var(--font-size-6) !important;
font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
cursor: pointer;
}
&-content {
position: absolute;
top: 32px;
left: 0;
right: 0;
bottom: 32px;
background: transparent;
color: var(--color-text-base) !important;
font-family: var(--font-base);
vertical-align: baseline;
outline: none;
overflow: auto;
padding: calc((32px - var(--font-size-6)) / 2);
}
&-save-button {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 32px;
border-top: var(--border-width-default) solid var(--color-border-base) !important;
cursor: pointer;
color: var(--color-text-alt) !important;
font-size: var(--font-size-6) !important;
font-weight: var(--font-weight-semibold) !important;
text-transform: uppercase !important;
text-align: center;
line-height: 32px;
}
&-x-button {
position: absolute; position: absolute;
left: 0; left: 0;
width: 100%; width: 100%;
min-height: 100%; min-height: 100%;
top: 0; top: 0;
fill: currentcolor; fill: currentcolor;
} }
.twitch-notes-blurred-background { &-blurred-background {
position: fixed; position: fixed;
inset: 0 0 0 0; inset: 0 0 0 0;
z-index: 2000000; z-index: 2000000;
background: rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(2px); backdrop-filter: blur(2px);
} }
.twitch-notes-center-floating-container { &-center-floating-container {
background: var(--color-background-base); background: var(--color-background-base);
border: var(--border-width-default) solid var(--color-border-base) !important; border: var(--border-width-default) solid var(--color-border-base) !important;
padding: 4rem 2rem 2rem;
position: fixed; position: fixed;
top: 50vh; top: 50vh;
left: 50vw; left: 50vw;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
min-height: 320px;
min-width: 300px;
max-height: 90vh; max-height: 90vh;
max-width: 90vw; max-width: 90vw;
overflow: auto; overflow: auto;
} }
.twitch-notes-user-list-user { &-link {
padding: 1rem; display: inline-block;
border-bottom: var(--border-width-default) solid var(--color-border-base) !important; -webkit-line-clamp: 2;
-webkit-box-orient: vertical;
color: var(--color-text-link) !important;
line-height: var(--line-height-heading) !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: normal !important;
font-weight: var(--font-weight-semibold) !important;
&:hover {
text-decoration: underline;
cursor: pointer; cursor: pointer;
} }
}
.twitch-notes-user-list-user[data-active] { &-grid-col-2 {
background: #772ce833; display: grid;
grid-template-columns: 1fr 1fr;
width: 100%;
}
} }

View File

@@ -1,94 +1,18 @@
import NoteStorage from "./NoteStorage"; import NoteStorage from "./NoteStorage";
import { getCloseButtonSVG } from "./HTMLTemplates";
import openAllNoteListWindow from "./openAllNoteListWindow"; import openAllNoteListWindow from "./openAllNoteListWindow";
import openClearDataWindow from "./openClearDataWindow"; import openClearDataWindow from "./openClearDataWindow";
import openImportNotesWindow from "./openImprtNotesWindow"; // import openImportNotesWindow from "./openImprtNotesWindow";
import createChatSettingsLine from "./chatSettingsLine"; import createChatSettingsLine from "./chatSettingsLine";
import { HTMLBuilderBlock } from "./types"; import {HTMLBuilderBlock} from "./types";
import HTMLBuilder from "./HTMLBuilder"; import HTMLBuilder from "./HTMLBuilder";
import TwitchCloseButton from "./HTMLElements/TwitchCloseButton";
export default function toggleSettingsList() { export default function toggleSettingsList() {
const settingsWindow = document.querySelector('.twitch-notes-settings-container') as HTMLElement; const settingsWindow = document.querySelector('.twitch-notes-settings-container') as HTMLElement;
if (!settingsWindow) { if (settingsWindow) {
const settingsContainer: HTMLBuilderBlock = {
element: 'div',
class: 'twitch-notes-settings-container',
content: [{
element: 'div',
class: 'twitch-notes-settings-balloon',
content: [{
element: 'div',
class: 'twitch-notes-settings-popover',
content: [
{
element: 'div',
class: 'twitch-notes-settings-header',
content: [
{
element: 'div',
class: 'twitch-notes-settings-header-left-element',
},
{
element: 'div',
class: 'twitch-notes-settings-header-center-element',
content: [{
element: 'p',
class: 'twitch-notes-settings-header-center-element-content',
content: ['Twitch Notes Settings']
}]
},
{
element: 'div',
class: 'twitch-notes-settings-header-right-element',
content: [{
element: 'button',
class: 'twitch-notes-settings-close-button',
content: [getCloseButtonSVG()],
mouseClickEvent: () => toggleSettingsList(),
}]
}
]
},
{
element: 'div',
class: 'twitch-notes-settings-scrollable-area',
content: [{
element: 'div',
class: 'twitch-notes-settings-content',
content: [
createChatSettingsLine('Export Notes', () => {
NoteStorage.exportNotes();
toggleSettingsList();
}),
createChatSettingsLine('Import Notes',() => {
openImportNotesWindow();
toggleSettingsList();
}),
createChatSettingsLine('Clear Data',() => {
openClearDataWindow();
toggleSettingsList();
}),
{
element: 'div',
class: 'twitch-note-settings-separator',
},
createChatSettingsLine('View All Notes',() => {
openAllNoteListWindow();
toggleSettingsList();
}),
]
}]
}
]
}]
}]
};
const settingsContainerElement = new HTMLBuilder(settingsContainer);
document.body.appendChild(settingsContainerElement.getElement());
return;
} else {
settingsWindow.remove(); settingsWindow.remove();
return;
} }
} }

View File

@@ -1,24 +1,14 @@
import {CustomHTMLElement} from "./CustomHTMLElement";
export type CustomHTMLElementConstructor = {
class?: string | string[],
id?: string,
css?: Partial<CSSStyleDeclaration>,
attributes?: {[key: string]: string},
body?: string | HTMLElement,
customBody?: CustomHTMLElement,
}
export type HTMLBuilderBlock = { export type HTMLBuilderBlock = {
element: 'div' | 'span' | 'button' | 'a' | 'p' | 'strong' | 'em' | 'input' | 'img', element: 'div' | 'span' | 'button' | 'a' | 'p' | 'strong' | 'em' | 'input' | 'img',
id?: string, id?: string,
class?: string | string[], class?: string | string[],
style?: Partial<CSSStyleDeclaration>, style?: Partial<CSSStyleDeclaration>,
attributes?: {[key: string]: string}, attributes?: {[key: string]: string},
content?: (HTMLBuilderBlock | string)[], content?: (HTMLBuilderBlock | string | HTMLElement)[],
mouseClickEvent?: Function, mouseClickEvent?: Function,
mouseMoveEvent?: Function, mouseMoveEvent?: Function,
mouseDownEvent?: Function, mouseDownEvent?: Function,
mouseUpEvent?: Function, mouseUpEvent?: Function,
keyUpEvent?: Function, keyUpEvent?: Function,
changeListener?: Function,
} }