mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
feat(themeCreator): add svelte theme creator
This commit is contained in:
@@ -67,6 +67,7 @@
|
|||||||
"@types/sortablejs": "^1.15.8",
|
"@types/sortablejs": "^1.15.8",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"@types/webextension-polyfill": "^0.10.7",
|
"@types/webextension-polyfill": "^0.10.7",
|
||||||
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
@@ -75,6 +76,7 @@
|
|||||||
"kolorist": "^1.8.0",
|
"kolorist": "^1.8.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"million": "^3.1.11",
|
||||||
"motion": "^10.18.0",
|
"motion": "^10.18.0",
|
||||||
"postcss": "^8.4.45",
|
"postcss": "^8.4.45",
|
||||||
"publish-browser-extension": "^2.2.1",
|
"publish-browser-extension": "^2.2.1",
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ import injectedCSS from '@/css/injected.scss?inline'
|
|||||||
import documentLoadCSS from '@/css/documentload.scss?inline'
|
import documentLoadCSS from '@/css/documentload.scss?inline'
|
||||||
import renderSvelte from '@/svelte-interface/main'
|
import renderSvelte from '@/svelte-interface/main'
|
||||||
import Settings from '@/svelte-interface/pages/settings.svelte'
|
import Settings from '@/svelte-interface/pages/settings.svelte'
|
||||||
import { renderStore } from './seqta/ui/renderStore'
|
|
||||||
import { settingsPopup } from './svelte-interface/hooks/SettingsPopup'
|
import { settingsPopup } from './svelte-interface/hooks/SettingsPopup'
|
||||||
|
|
||||||
let SettingsClicked = false
|
let SettingsClicked = false
|
||||||
|
|||||||
+73
-30
@@ -1,9 +1,9 @@
|
|||||||
@charset "UTF-8";
|
@charset "UTF-8";
|
||||||
@import url('https://fonts.googleapis.com/css?family=Rubik:300,400,500,600');
|
@import url("https://fonts.googleapis.com/css?family=Rubik:300,400,500,600");
|
||||||
|
|
||||||
@import './injected/sidebar-animation.scss';
|
@import "./injected/sidebar-animation.scss";
|
||||||
@import './injected/theme.scss';
|
@import "./injected/theme.scss";
|
||||||
@import './injected/transparency.scss';
|
@import "./injected/transparency.scss";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
background: var(--better-main) !important;
|
background: var(--better-main) !important;
|
||||||
@@ -16,7 +16,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body,
|
body,
|
||||||
.legacy-root input, .legacy-root textarea, .legacy-root button, .legacy-root select, .legacy-root option, .legacy-root .input,
|
.legacy-root input,
|
||||||
|
.legacy-root textarea,
|
||||||
|
.legacy-root button,
|
||||||
|
.legacy-root select,
|
||||||
|
.legacy-root option,
|
||||||
|
.legacy-root .input,
|
||||||
html {
|
html {
|
||||||
font-family: Rubik, sans-serif !important;
|
font-family: Rubik, sans-serif !important;
|
||||||
}
|
}
|
||||||
@@ -35,7 +40,8 @@ html {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
}
|
}
|
||||||
#themeCreatorIframe {
|
|
||||||
|
#themeCreator {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -195,7 +201,8 @@ html {
|
|||||||
background: unset;
|
background: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.legacy-root button:active, .legacy-root a:active:not(.cke_combo_button) {
|
.legacy-root button:active,
|
||||||
|
.legacy-root a:active:not(.cke_combo_button) {
|
||||||
background-image: unset !important;
|
background-image: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +212,8 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dark .dashboard section {
|
.dark .dashboard section {
|
||||||
input, select {
|
input,
|
||||||
|
select {
|
||||||
background: rgba(255, 255, 255, 0.1);
|
background: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,7 +235,7 @@ html {
|
|||||||
input,
|
input,
|
||||||
select {
|
select {
|
||||||
border: transparent;
|
border: transparent;
|
||||||
background: rgba(0, 0, 0, .1);
|
background: rgba(0, 0, 0, 0.1);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +277,7 @@ html {
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
ul.magicDelete > li:hover {
|
ul.magicDelete > li:hover {
|
||||||
background: rgba(0, 0, 0, .1);
|
background: rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
.dashlet-notes > .editor {
|
.dashlet-notes > .editor {
|
||||||
background: unset;
|
background: unset;
|
||||||
@@ -292,7 +300,8 @@ ul.magicDelete > li.deleting {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#media-container video, #media-container img {
|
#media-container video,
|
||||||
|
#media-container img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
@@ -372,14 +381,16 @@ ul.magicDelete > li.deleting {
|
|||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
background: var(--item-colour, transparent);
|
background: var(--item-colour, transparent);
|
||||||
transition: width 100ms, transform 0.3s ease;
|
transition:
|
||||||
|
width 100ms,
|
||||||
|
transform 0.3s ease;
|
||||||
border-radius: 8px 0 0 8px;
|
border-radius: 8px 0 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,7 +492,7 @@ ol:has(.MessageList__avatar___2wxyb svg) {
|
|||||||
.quickbar .actions [title="Choose a colour"] > svg {
|
.quickbar .actions [title="Choose a colour"] > svg {
|
||||||
scale: 0.9;
|
scale: 0.9;
|
||||||
}
|
}
|
||||||
.quickbar[data-yiq='light'] .actions {
|
.quickbar[data-yiq="light"] .actions {
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
.singleSelect > li {
|
.singleSelect > li {
|
||||||
@@ -508,7 +519,7 @@ ol:has(.MessageList__avatar___2wxyb svg) {
|
|||||||
}
|
}
|
||||||
#main .timetablepage .quickbar {
|
#main .timetablepage .quickbar {
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: 0 4px 8px rgba(0,0,0,0.5);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
.quickbar .actions {
|
.quickbar .actions {
|
||||||
@@ -539,7 +550,7 @@ ol:has(.MessageList__avatar___2wxyb svg) {
|
|||||||
margin: 0 0 0 -12px;
|
margin: 0 0 0 -12px;
|
||||||
background-color: rgba(255, 255, 255, 0.2);
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
clip-path: polygon(50% 40%, 0 0, 100% 0);
|
clip-path: polygon(50% 40%, 0 0, 100% 0);
|
||||||
border: 12px solid rgba(255,255,255,0);
|
border: 12px solid rgba(255, 255, 255, 0);
|
||||||
border-top-color: transparent;
|
border-top-color: transparent;
|
||||||
}
|
}
|
||||||
#main > .timetablepage > .quickbar.above::before {
|
#main > .timetablepage > .quickbar.above::before {
|
||||||
@@ -1328,7 +1339,9 @@ div > ol:has(.uiFileHandlerWrapper) {
|
|||||||
height: 25px;
|
height: 25px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
.notifications__notifications___3mmLY > button > .notifications__bubble___1EkSQ {
|
.notifications__notifications___3mmLY
|
||||||
|
> button
|
||||||
|
> .notifications__bubble___1EkSQ {
|
||||||
background: var(--better-alert-highlight);
|
background: var(--better-alert-highlight);
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
@@ -1534,7 +1547,9 @@ iframe.userHTML {
|
|||||||
.Collapsible__Collapsible___3O8P3 > .Collapsible__header___-Afvq {
|
.Collapsible__Collapsible___3O8P3 > .Collapsible__header___-Afvq {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
.AssessmentList__AssessmentList___1GdCl > .AssessmentList__searchFilter___3N70o + .AssessmentList__items___3LcmQ {
|
.AssessmentList__AssessmentList___1GdCl
|
||||||
|
> .AssessmentList__searchFilter___3N70o
|
||||||
|
+ .AssessmentList__items___3LcmQ {
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
.Thermoscore__Thermoscore___2tWMi {
|
.Thermoscore__Thermoscore___2tWMi {
|
||||||
@@ -1630,10 +1645,13 @@ ul {
|
|||||||
> .SelectedAssessment__clearBtn___21D85 {
|
> .SelectedAssessment__clearBtn___21D85 {
|
||||||
background: var(--better-main);
|
background: var(--better-main);
|
||||||
}
|
}
|
||||||
.SelectedAssessment__SelectedAssessment___3Bu5D > .SelectedAssessment__meta___1gq_y {
|
.SelectedAssessment__SelectedAssessment___3Bu5D
|
||||||
|
> .SelectedAssessment__meta___1gq_y {
|
||||||
border-bottom: 1px solid var(--better-main);
|
border-bottom: 1px solid var(--better-main);
|
||||||
}
|
}
|
||||||
.TabSet__TabSet___Vo-SZ > ol.TabSet__tabs___1RRZk > li.TabSet__selected___1psfF {
|
.TabSet__TabSet___Vo-SZ
|
||||||
|
> ol.TabSet__tabs___1RRZk
|
||||||
|
> li.TabSet__selected___1psfF {
|
||||||
border-bottom-color: var(--better-main);
|
border-bottom-color: var(--better-main);
|
||||||
}
|
}
|
||||||
.TabSet__TabSet___Vo-SZ > ol.TabSet__tabs___1RRZk {
|
.TabSet__TabSet___Vo-SZ > ol.TabSet__tabs___1RRZk {
|
||||||
@@ -1758,7 +1776,15 @@ div.entry.class[style*="left: 46.5%"] {
|
|||||||
div.entry.class[style*="width: 46.5%"] {
|
div.entry.class[style*="width: 46.5%"] {
|
||||||
width: 50% !important;
|
width: 50% !important;
|
||||||
}
|
}
|
||||||
.timetablepage .dailycal > .content > .wrapper > .days > tbody > tr > td > .entriesWrapper {
|
.timetablepage
|
||||||
|
.dailycal
|
||||||
|
> .content
|
||||||
|
> .wrapper
|
||||||
|
> .days
|
||||||
|
> tbody
|
||||||
|
> tr
|
||||||
|
> td
|
||||||
|
> .entriesWrapper {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
}
|
}
|
||||||
@@ -1952,7 +1978,6 @@ div.bar.flat {
|
|||||||
.cke_toolbox > .cke_toolbar .cke_button_on {
|
.cke_toolbox > .cke_toolbar .cke_button_on {
|
||||||
background-color: #3d3d3e !important;
|
background-color: #3d3d3e !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.legacy-root input.singleSelect:focus {
|
.legacy-root input.singleSelect:focus {
|
||||||
background: var(--auto-background);
|
background: var(--auto-background);
|
||||||
@@ -1996,7 +2021,15 @@ body {
|
|||||||
.forumView .assessment {
|
.forumView .assessment {
|
||||||
background: var(--better-main);
|
background: var(--better-main);
|
||||||
}
|
}
|
||||||
.dailycal > .content > .wrapper > .days > tbody > tr > td > .entriesWrapper > .entry {
|
.dailycal
|
||||||
|
> .content
|
||||||
|
> .wrapper
|
||||||
|
> .days
|
||||||
|
> tbody
|
||||||
|
> tr
|
||||||
|
> td
|
||||||
|
> .entriesWrapper
|
||||||
|
> .entry {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
.Viewer__Viewer___32BH- {
|
.Viewer__Viewer___32BH- {
|
||||||
@@ -2035,7 +2068,9 @@ li.MessageList__unread___3imtO {
|
|||||||
border-radius: 1600px;
|
border-radius: 1600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MessageList__MessageList___3DxoC > ol > li.MessageList__selected___1SJNz.MessageList__unread___3imtO {
|
.MessageList__MessageList___3DxoC
|
||||||
|
> ol
|
||||||
|
> li.MessageList__selected___1SJNz.MessageList__unread___3imtO {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2055,7 +2090,9 @@ li.MessageList__unread___3imtO {
|
|||||||
transition: width 0.1s;
|
transition: width 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MessageList__MessageList___3DxoC > ol > li.MessageList__unread___3imtO::before {
|
.MessageList__MessageList___3DxoC
|
||||||
|
> ol
|
||||||
|
> li.MessageList__unread___3imtO::before {
|
||||||
width: 3px;
|
width: 3px;
|
||||||
}
|
}
|
||||||
.connectedNotificationsWrapper > div > button {
|
.connectedNotificationsWrapper > div > button {
|
||||||
@@ -2129,7 +2166,10 @@ li.MessageList__unread___3imtO {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark .MessageList__MessageList___3DxoC > ol > li.MessageList__selected___1SJNz {
|
.dark
|
||||||
|
.MessageList__MessageList___3DxoC
|
||||||
|
> ol
|
||||||
|
> li.MessageList__selected___1SJNz {
|
||||||
background: var(--background-secondary);
|
background: var(--background-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2620,7 +2660,9 @@ li.MessageList__unread___3imtO {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-shadow: inset 0px 6px 0 var(--item-colour, transparent), inset 0px 40px 50px -40px rgba(179, 179, 179, 0.9);
|
box-shadow:
|
||||||
|
inset 0px 6px 0 var(--item-colour, transparent),
|
||||||
|
inset 0px 40px 50px -40px rgba(179, 179, 179, 0.9);
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 15em;
|
height: 15em;
|
||||||
@@ -2629,7 +2671,9 @@ li.MessageList__unread___3imtO {
|
|||||||
font-family: Rubik, sans-serif;
|
font-family: Rubik, sans-serif;
|
||||||
}
|
}
|
||||||
.dark .day {
|
.dark .day {
|
||||||
box-shadow: inset 0px 6px 0 var(--item-colour, transparent), inset 0px 40px 50px -40px rgba(0,0,0,0.9);
|
box-shadow:
|
||||||
|
inset 0px 6px 0 var(--item-colour, transparent),
|
||||||
|
inset 0px 40px 50px -40px rgba(0, 0, 0, 0.9);
|
||||||
}
|
}
|
||||||
.clickable {
|
.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -2666,7 +2710,7 @@ li.MessageList__unread___3imtO {
|
|||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
.dark .upcoming-items {
|
.dark .upcoming-items {
|
||||||
box-shadow: inset 0px 40px 80px -40px rgba(0,0,0,0.6);
|
box-shadow: inset 0px 40px 80px -40px rgba(0, 0, 0, 0.6);
|
||||||
}
|
}
|
||||||
.upcoming-assessment-title {
|
.upcoming-assessment-title {
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
@@ -2946,7 +2990,6 @@ li.MessageList__unread___3imtO {
|
|||||||
width: 90%;
|
width: 90%;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.3);
|
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
}
|
}
|
||||||
.whatsnewTextContainer {
|
.whatsnewTextContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -1,73 +1,79 @@
|
|||||||
import browser from "webextension-polyfill";
|
import renderSvelte from "@/svelte-interface/main"
|
||||||
|
import themeCreator from "@/svelte-interface/pages/themeCreator.svelte"
|
||||||
|
import { unmount } from "svelte"
|
||||||
|
|
||||||
|
let themeCreatorSvelteApp: any = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the Theme Creator sidebar, it is an embedded page loaded similar to the extension popup
|
* Open the Theme Creator sidebar, it is an embedded page loaded similar to the extension popup
|
||||||
* @param themeID - The ID of the theme to load in the Theme Creator
|
* @param themeID - The ID of the theme to load in the Theme Creator
|
||||||
* @returns void
|
* @returns void
|
||||||
*/
|
*/
|
||||||
export function OpenThemeCreator( themeID: string = '' ) {
|
export function OpenThemeCreator(themeID: string = "") {
|
||||||
CloseThemeCreator();
|
CloseThemeCreator()
|
||||||
|
|
||||||
const width = '310px';
|
const width = "310px"
|
||||||
|
|
||||||
const themeCreatorIframe: HTMLIFrameElement = document.createElement('iframe');
|
const themeCreatorDiv: HTMLDivElement = document.createElement("div")
|
||||||
themeCreatorIframe.src = `${browser.runtime.getURL('interface/index.html')}${ themeID != '' ? `?themeID=${themeID}` : '' }#themeCreator`;
|
themeCreatorDiv.id = "themeCreator"
|
||||||
themeCreatorIframe.id = 'themeCreatorIframe';
|
themeCreatorDiv.style.width = width
|
||||||
themeCreatorIframe.setAttribute('allowTransparency', 'true');
|
|
||||||
themeCreatorIframe.setAttribute('excludeDarkCheck', 'true');
|
|
||||||
themeCreatorIframe.style.border = 'none';
|
|
||||||
themeCreatorIframe.style.width = width;
|
|
||||||
|
|
||||||
const mainContent = document.querySelector('#container') as HTMLDivElement;
|
const shadow = themeCreatorDiv.attachShadow({ mode: "open" })
|
||||||
if (mainContent) mainContent.style.width = `calc(100% - ${width})`;
|
themeCreatorSvelteApp = renderSvelte(themeCreator, shadow, {
|
||||||
|
themeID: themeID,
|
||||||
|
})
|
||||||
|
|
||||||
|
const mainContent = document.querySelector("#container") as HTMLDivElement
|
||||||
|
if (mainContent) mainContent.style.width = `calc(100% - ${width})`
|
||||||
|
|
||||||
// close button
|
// close button
|
||||||
const closeButton = document.createElement('button');
|
const closeButton = document.createElement("button")
|
||||||
closeButton.classList.add('themeCloseButton');
|
closeButton.classList.add("themeCloseButton")
|
||||||
closeButton.textContent = '×';
|
closeButton.textContent = "×"
|
||||||
closeButton.addEventListener('click', CloseThemeCreator);
|
closeButton.addEventListener("click", CloseThemeCreator)
|
||||||
document.body.appendChild(closeButton);
|
document.body.appendChild(closeButton)
|
||||||
|
|
||||||
const resizeBar = document.createElement('div');
|
const resizeBar = document.createElement("div")
|
||||||
resizeBar.classList.add('resizeBar');
|
resizeBar.classList.add("resizeBar")
|
||||||
resizeBar.style.right = '307.5px';
|
resizeBar.style.right = "307.5px"
|
||||||
|
|
||||||
let isDragging = false;
|
let isDragging = false
|
||||||
let currentX: number;
|
let currentX: number
|
||||||
|
|
||||||
const mouseDownHandler = (e: MouseEvent) => {
|
const mouseDownHandler = (e: MouseEvent) => {
|
||||||
isDragging = true;
|
isDragging = true
|
||||||
currentX = e.clientX;
|
currentX = e.clientX
|
||||||
document.addEventListener('mousemove', mouseMoveHandler);
|
document.addEventListener("mousemove", mouseMoveHandler)
|
||||||
document.addEventListener('mouseup', mouseUpHandler);
|
document.addEventListener("mouseup", mouseUpHandler)
|
||||||
document.body.style.userSelect = 'none';
|
document.body.style.userSelect = "none"
|
||||||
themeCreatorIframe.style.pointerEvents = 'none'; // Disable pointer events on iframe during resize
|
themeCreatorDiv.style.pointerEvents = "none"
|
||||||
};
|
}
|
||||||
|
|
||||||
const mouseMoveHandler = (e: MouseEvent) => {
|
const mouseMoveHandler = (e: MouseEvent) => {
|
||||||
if (!isDragging) return;
|
if (!isDragging) return
|
||||||
const dx = e.clientX - currentX;
|
const windowWidth = window.innerWidth
|
||||||
currentX = e.clientX;
|
const newWidth = Math.min(Math.max(310, windowWidth - e.clientX), 600)
|
||||||
const newWidth = Math.min(Math.max(310, themeCreatorIframe.offsetWidth - dx), 600);
|
themeCreatorDiv.style.width = `${newWidth}px`
|
||||||
themeCreatorIframe.style.width = `${newWidth}px`;
|
mainContent.style.width = `calc(100% - ${newWidth}px)`
|
||||||
mainContent.style.width = `calc(100% - ${newWidth}px)`;
|
resizeBar.style.right = `${newWidth - 2.5}px`
|
||||||
resizeBar.style.right = `${newWidth - 2.5}px`;
|
|
||||||
};
|
currentX = e.clientX
|
||||||
|
}
|
||||||
|
|
||||||
const mouseUpHandler = () => {
|
const mouseUpHandler = () => {
|
||||||
isDragging = false;
|
isDragging = false
|
||||||
document.removeEventListener('mousemove', mouseMoveHandler);
|
document.removeEventListener("mousemove", mouseMoveHandler)
|
||||||
document.removeEventListener('mouseup', mouseUpHandler);
|
document.removeEventListener("mouseup", mouseUpHandler)
|
||||||
document.body.style.userSelect = '';
|
document.body.style.userSelect = ""
|
||||||
themeCreatorIframe.style.pointerEvents = 'auto';
|
themeCreatorDiv.style.pointerEvents = "auto"
|
||||||
};
|
}
|
||||||
|
|
||||||
resizeBar.addEventListener('mousedown', mouseDownHandler);
|
resizeBar.addEventListener("mousedown", mouseDownHandler)
|
||||||
resizeBar.addEventListener('mouseover', () => resizeBar.style.opacity = '1');
|
resizeBar.addEventListener("mouseover", () => (resizeBar.style.opacity = "1"))
|
||||||
resizeBar.addEventListener('mouseout', () => resizeBar.style.opacity = '0');
|
resizeBar.addEventListener("mouseout", () => (resizeBar.style.opacity = "0"))
|
||||||
|
|
||||||
document.body.appendChild(themeCreatorIframe);
|
document.body.appendChild(themeCreatorDiv)
|
||||||
document.body.appendChild(resizeBar);
|
document.body.appendChild(resizeBar)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,14 +81,17 @@ export function OpenThemeCreator( themeID: string = '' ) {
|
|||||||
* @returns void
|
* @returns void
|
||||||
*/
|
*/
|
||||||
export function CloseThemeCreator() {
|
export function CloseThemeCreator() {
|
||||||
const themeCreatorIframe = document.getElementById('themeCreatorIframe');
|
const themeCreator = document.getElementById("themeCreator")
|
||||||
const closeButton = document.querySelector('.themeCloseButton') as HTMLButtonElement;
|
const closeButton = document.querySelector(
|
||||||
const resizeBar = document.querySelector('.resizeBar') as HTMLDivElement;
|
".themeCloseButton",
|
||||||
|
) as HTMLButtonElement
|
||||||
|
const resizeBar = document.querySelector(".resizeBar") as HTMLDivElement
|
||||||
|
|
||||||
if (themeCreatorIframe) themeCreatorIframe.remove();
|
if (themeCreatorSvelteApp) unmount(themeCreatorSvelteApp)
|
||||||
if (closeButton) closeButton.remove();
|
if (themeCreator) themeCreator.remove()
|
||||||
if (resizeBar) resizeBar.remove();
|
if (closeButton) closeButton.remove()
|
||||||
|
if (resizeBar) resizeBar.remove()
|
||||||
|
|
||||||
const mainContent = document.querySelector('#container') as HTMLDivElement;
|
const mainContent = document.querySelector("#container") as HTMLDivElement
|
||||||
if (mainContent) mainContent.style.width = '100%';
|
if (mainContent) mainContent.style.width = "100%"
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>Code Editor Here</div>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
.dark {
|
div:has(> #rbgcp-wrapper) {
|
||||||
div:has(> #rbgcp-wrapper) {
|
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
#rbgcp-wrapper {
|
#rbgcp-wrapper {
|
||||||
div[style="padding-top: 11px; position: relative;"] div {
|
div[style="padding-top: 11px; position: relative;"] div {
|
||||||
color: white !important;
|
color: white !important;
|
||||||
@@ -31,11 +31,14 @@
|
|||||||
#rbgcp-radial-btn,
|
#rbgcp-radial-btn,
|
||||||
#rbgcp-linear-btn {
|
#rbgcp-linear-btn {
|
||||||
&[style*="background: white;"] {
|
&[style*="background: white;"] {
|
||||||
background-color: #28282B !important;
|
background-color: #28282b !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
path, g, polyline, circle {
|
path,
|
||||||
|
g,
|
||||||
|
polyline,
|
||||||
|
circle {
|
||||||
stroke: white !important;
|
stroke: white !important;
|
||||||
fill: transparent !important;
|
fill: transparent !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,17 @@
|
|||||||
import { animate, spring } from 'motion';
|
import { animate, spring } from 'motion';
|
||||||
import { delay } from '@/seqta/utils/delay.ts'
|
import { delay } from '@/seqta/utils/delay.ts'
|
||||||
|
|
||||||
const { hidePicker } = $props<{
|
const { hidePicker, standalone = false } = $props<{
|
||||||
hidePicker: () => void
|
hidePicker?: () => void,
|
||||||
|
standalone?: boolean
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let background: HTMLDivElement;
|
let background: HTMLDivElement;
|
||||||
let content: HTMLDivElement;
|
let content: HTMLDivElement;
|
||||||
|
|
||||||
const closePicker = async () => {
|
const closePicker = async () => {
|
||||||
|
if (standalone) return;
|
||||||
|
|
||||||
animate(
|
animate(
|
||||||
content,
|
content,
|
||||||
{ scale: [1, 0.4], opacity: [1, 0] },
|
{ scale: [1, 0.4], opacity: [1, 0] },
|
||||||
@@ -25,12 +28,13 @@
|
|||||||
{ easing: [0.4, 0, 0.2, 1] }
|
{ easing: [0.4, 0, 0.2, 1] }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await delay(400);
|
await delay(400);
|
||||||
hidePicker();
|
hidePicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
if (standalone) return;
|
||||||
|
|
||||||
animate(
|
animate(
|
||||||
background,
|
background,
|
||||||
{ opacity: [0, 1] },
|
{ opacity: [0, 1] },
|
||||||
@@ -43,11 +47,17 @@
|
|||||||
{ easing: spring({ stiffness: 400, damping: 30 }) }
|
{ easing: spring({ stiffness: 400, damping: 30 }) }
|
||||||
);
|
);
|
||||||
|
|
||||||
document.addEventListener('keydown', (e) => {
|
const handleEscapeKey = (e: KeyboardEvent) => {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
closePicker();
|
closePicker();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
document.addEventListener('keydown', handleEscapeKey);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('keydown', handleEscapeKey);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleBackgroundClick(event: MouseEvent) {
|
function handleBackgroundClick(event: MouseEvent) {
|
||||||
@@ -57,17 +67,23 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
{#if standalone}
|
||||||
<div
|
<div class="h-auto rounded-xl overflow-clip">
|
||||||
|
<ReactAdapter el={ColourPicker} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div
|
||||||
bind:this={background}
|
bind:this={background}
|
||||||
class="absolute top-0 left-0 z-50 flex items-center justify-center w-full h-full cursor-pointer bg-black/20"
|
class="absolute top-0 left-0 z-50 flex items-center justify-center w-full h-full cursor-pointer bg-black/20"
|
||||||
onclick={handleBackgroundClick}
|
onclick={handleBackgroundClick}
|
||||||
onkeydown={(e) => { e.key === 'Enter' && handleBackgroundClick }}
|
onkeydown={(e) => { e.key === 'Enter' && handleBackgroundClick }}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
bind:this={content}
|
bind:this={content}
|
||||||
class="h-auto p-4 bg-white border shadow-lg cursor-auto rounded-xl dark:bg-zinc-800 border-zinc-100 dark:border-zinc-700"
|
class="h-auto p-4 bg-white border shadow-lg cursor-auto rounded-xl dark:bg-zinc-800 border-zinc-100 dark:border-zinc-700"
|
||||||
>
|
>
|
||||||
<ReactAdapter el={ColourPicker} />
|
<ReactAdapter el={ColourPicker} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<script lang="ts"></script>
|
||||||
|
|
||||||
|
<div class='w-full h-0.5 my-4 bg-zinc-200 dark:bg-zinc-700'></div>
|
||||||
@@ -1,23 +1,24 @@
|
|||||||
import styles from './index.css?inline';
|
import styles from "./index.css?inline"
|
||||||
import { mount } from 'svelte';
|
import { mount } from "svelte"
|
||||||
import type { ComponentType } from 'svelte';
|
import type { ComponentType } from "svelte"
|
||||||
|
|
||||||
export default function renderSvelte(
|
export default function renderSvelte(
|
||||||
Component: ComponentType | any,
|
Component: ComponentType | any,
|
||||||
mountPoint: ShadowRoot | HTMLElement,
|
mountPoint: ShadowRoot | HTMLElement,
|
||||||
props: Record<string, any> = {}
|
props: Record<string, any> = {},
|
||||||
) {
|
) {
|
||||||
const app = mount(Component, {
|
const app = mount(Component, {
|
||||||
target: mountPoint,
|
target: mountPoint,
|
||||||
props: {
|
props: {
|
||||||
standalone: false,
|
standalone: false,
|
||||||
...props
|
...props,
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
const style = document.createElement("style");
|
const style = document.createElement("style")
|
||||||
style.setAttribute("type", "text/css");
|
style.setAttribute("type", "text/css")
|
||||||
style.innerHTML = styles;
|
style.innerHTML = styles
|
||||||
mountPoint.appendChild(style);
|
mountPoint.appendChild(style)
|
||||||
return app;
|
|
||||||
|
return app
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
import type { CustomTheme } from '@/types/CustomThemes'
|
||||||
|
|
||||||
|
import { settingsState } from '@/seqta/utils/listeners/SettingsState'
|
||||||
|
import { getTheme } from '@/seqta/ui/themes/getTheme'
|
||||||
|
|
||||||
|
import Divider from '@/svelte-interface/components/themeCreator/divider.svelte'
|
||||||
|
import Switch from '@/svelte-interface/components/Switch.svelte'
|
||||||
|
import Button from '@/svelte-interface/components/Button.svelte'
|
||||||
|
import Slider from '@/svelte-interface/components/Slider.svelte'
|
||||||
|
import ColourPicker from '../components/ColourPicker.svelte'
|
||||||
|
import CodeEditor from '../components/CodeEditor.svelte'
|
||||||
|
|
||||||
|
|
||||||
|
const { themeID } = $props<{ themeID: string }>()
|
||||||
|
let theme = $state<CustomTheme>({
|
||||||
|
id: uuidv4(),
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
defaultColour: 'blue',
|
||||||
|
CanChangeColour: true,
|
||||||
|
allowBackgrounds: true,
|
||||||
|
CustomCSS: '',
|
||||||
|
CustomImages: [],
|
||||||
|
coverImage: null,
|
||||||
|
isEditable: true,
|
||||||
|
hideThemeName: false,
|
||||||
|
forceDark: false
|
||||||
|
})
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
console.log(themeID)
|
||||||
|
|
||||||
|
if (themeID) {
|
||||||
|
const tempTheme = await getTheme(themeID)
|
||||||
|
if (tempTheme) theme = tempTheme
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
type SettingType = 'switch' | 'button' | 'slider' | 'colourPicker' | 'select' | 'codeEditor';
|
||||||
|
|
||||||
|
type SwitchProps = { state: boolean; onChange: (value: boolean) => void };
|
||||||
|
type ButtonProps = { onClick: () => void; text: string };
|
||||||
|
type SliderProps = { state: number; onChange: (value: number) => void; min?: number; max?: number };
|
||||||
|
type ColourPickerProps = { color: string; onChange: (color: string) => void };
|
||||||
|
type SelectProps = { options: Array<{ value: string; label: string }>; value: string; onChange: (value: string) => void };
|
||||||
|
type CodeEditorProps = { value: string; onChange: (value: string) => void };
|
||||||
|
|
||||||
|
type ComponentProps = SwitchProps | ButtonProps | SliderProps | ColourPickerProps | SelectProps | CodeEditorProps;
|
||||||
|
|
||||||
|
type SettingItem = {
|
||||||
|
type: SettingType;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
direction?: 'horizontal' | 'vertical';
|
||||||
|
props: ComponentProps;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#snippet settingItem(item: SettingItem)}
|
||||||
|
<div class="flex justify-between {item.direction === 'vertical' ? 'flex-col items-start gap-2' : 'items-center'} py-3">
|
||||||
|
<div class="pr-4">
|
||||||
|
<h2 class="text-sm font-bold">{item.title}</h2>
|
||||||
|
<p class="text-xs">{item.description}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{#if item.type === 'switch'}
|
||||||
|
<Switch {...(item.props as SwitchProps)} />
|
||||||
|
{:else if item.type === 'button'}
|
||||||
|
<Button {...(item.props as ButtonProps)} />
|
||||||
|
{:else if item.type === 'slider'}
|
||||||
|
<Slider {...(item.props as SliderProps)} />
|
||||||
|
{:else if item.type === 'colourPicker'}
|
||||||
|
<ColourPicker standalone={true} {...(item.props)} />
|
||||||
|
{:else if item.type === 'codeEditor'}
|
||||||
|
<CodeEditor {...(item.props as CodeEditorProps)} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
<div class='h-screen overflow-y-scroll {$settingsState.DarkMode && "dark"} '>
|
||||||
|
<div class='w-full min-h-screen bg-zinc-100 dark:bg-zinc-800 flex flex-col p-2 dark:text-white'>
|
||||||
|
<h1 class='text-xl font-semibold'>Theme Creator</h1>
|
||||||
|
<a href='https://betterseqta.gitbook.io/betterseqta-docs' target='_blank' class='text-sm font-light text-zinc-500 dark:text-zinc-400'>
|
||||||
|
<span class='no-underline font-IconFamily pr-0.5'>{'\ueb44'}</span>
|
||||||
|
<span class='underline'>
|
||||||
|
Need help? Check out the docs!
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class='pb-2 text-sm'>Theme Name</div>
|
||||||
|
<input
|
||||||
|
id='themeName'
|
||||||
|
type='text'
|
||||||
|
placeholder='What is your theme called?'
|
||||||
|
bind:value={theme.name}
|
||||||
|
class='w-full p-2 mb-4 transition-all duration-300 rounded-lg focus:outline-none ring-0 focus:ring-1 ring-zinc-100 dark:ring-zinc-700 dark:bg-zinc-900 dark:text-white' />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class='pb-2 text-sm'>Description <span class='italic font-light opacity-80'>(optional)</span></div>
|
||||||
|
<textarea
|
||||||
|
id='themeDescription'
|
||||||
|
placeholder="Don't worry, this one's optional!"
|
||||||
|
bind:value={theme.description}
|
||||||
|
class='w-full p-2 rounded-lg focus:outline-none ring-0 focus:ring-1 ring-zinc-100 dark:ring-zinc-700 dark:bg-zinc-900 dark:text-white'></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
{#each [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
title: 'Hide Theme Name',
|
||||||
|
description: 'Useful when your cover image contains text',
|
||||||
|
props: {
|
||||||
|
state: theme.hideThemeName,
|
||||||
|
onChange: (value) => theme.hideThemeName = value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
title: 'Force Theme',
|
||||||
|
description: 'Force users to use either dark or light mode',
|
||||||
|
props: {
|
||||||
|
state: theme.forceDark !== undefined,
|
||||||
|
onChange: (value) => theme.forceDark = value ? false : undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'colourPicker',
|
||||||
|
title: 'Default Theme Colour',
|
||||||
|
description: 'Set the default color for your theme',
|
||||||
|
direction: 'vertical',
|
||||||
|
props: {
|
||||||
|
color: theme.defaultColour,
|
||||||
|
onChange: (color) => theme.defaultColour = color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'codeEditor',
|
||||||
|
title: 'Custom CSS',
|
||||||
|
description: 'Add custom CSS to your theme',
|
||||||
|
props: {
|
||||||
|
value: theme.CustomCSS,
|
||||||
|
onChange: (value) => theme.CustomCSS = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
] as SettingItem[] as setting}
|
||||||
|
{@render settingItem(setting)}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { SettingsState } from './AppProps';
|
|
||||||
export interface SettingsList {
|
export interface SettingsList {
|
||||||
title: string;
|
title: string;
|
||||||
id: number;
|
id: number;
|
||||||
@@ -6,9 +5,3 @@ export interface SettingsList {
|
|||||||
Component: any; /* TODO: Give this a type */
|
Component: any; /* TODO: Give this a type */
|
||||||
props?: any;
|
props?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface SettingsProps {
|
|
||||||
settingsState: SettingsState;
|
|
||||||
setSettingsState: React.Dispatch<React.SetStateAction<SettingsState>>;
|
|
||||||
}
|
|
||||||
|
|||||||
+3
-3
@@ -4,8 +4,8 @@ import { join, resolve } from 'path';
|
|||||||
import { base64Loader } from './lib/base64loader';
|
import { base64Loader } from './lib/base64loader';
|
||||||
import type { BuildTarget } from './lib/types';
|
import type { BuildTarget } from './lib/types';
|
||||||
|
|
||||||
import react from '@vitejs/plugin-react-swc';
|
import react from '@vitejs/plugin-react';
|
||||||
//import million from "million/compiler";
|
import million from "million/compiler";
|
||||||
//import MillionLint from '@million/lint';
|
//import MillionLint from '@million/lint';
|
||||||
|
|
||||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||||
@@ -31,7 +31,7 @@ export default defineConfig({
|
|||||||
svelte({
|
svelte({
|
||||||
emitCss: false
|
emitCss: false
|
||||||
}),
|
}),
|
||||||
//million.vite({ auto: true }),
|
million.vite({ auto: true }),
|
||||||
//MillionLint.vite(), /* enable for testing and debugging performance */
|
//MillionLint.vite(), /* enable for testing and debugging performance */
|
||||||
crx({
|
crx({
|
||||||
manifest: targets.find(t => t.browser === mode.toLowerCase())?.manifest ?? chrome.manifest,
|
manifest: targets.find(t => t.browser === mode.toLowerCase())?.manifest ?? chrome.manifest,
|
||||||
|
|||||||
Reference in New Issue
Block a user