Open in-page settings inside floating windows
This commit is contained in:
parent
b6dec385dc
commit
b62f6feaea
@ -15,6 +15,11 @@ import alignmentIndicatorSvg from '!!raw-loader!@ui/res/img/alignment-indicators
|
|||||||
import lockBarIndicatorSvg from '!!raw-loader!@ui/res/img/lock-bar-indicators.svg';
|
import lockBarIndicatorSvg from '!!raw-loader!@ui/res/img/lock-bar-indicators.svg';
|
||||||
import VideoAlignmentType from '../../../common/enums/VideoAlignmentType.enum';
|
import VideoAlignmentType from '../../../common/enums/VideoAlignmentType.enum';
|
||||||
import { setVideoAlignmentIndicatorState } from '../../../ui/utils/video-alignment-indicator-handling';
|
import { setVideoAlignmentIndicatorState } from '../../../ui/utils/video-alignment-indicator-handling';
|
||||||
|
import { UwuiWindow } from './UwuiWindow';
|
||||||
|
|
||||||
|
import { createApp } from 'vue';
|
||||||
|
import SettingsWindowContent from '@components/SettingsWindowContent.vue';
|
||||||
|
// import jsonEditorCSS from 'vanilla-jsoneditor/themes/jse-theme-dark.css?inline'
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.info("Loading: UI");
|
console.info("Loading: UI");
|
||||||
@ -293,10 +298,16 @@ class UI {
|
|||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'todo: open settings'
|
label: 'Extension settings',
|
||||||
|
action: () => this.createSettingsWindow(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'todo: first-time "customize/hide menu" option'
|
label: 'Cropping issues?',
|
||||||
|
action: () => this.createSettingsWindow('ui-settings'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Report a problem',
|
||||||
|
action: () => this.createSettingsWindow('about'),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -393,6 +404,28 @@ class UI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createSettingsWindow(path?: string) {
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
|
||||||
|
iframe.src = chrome.runtime.getURL(`ui/pages/settings/index.html#ui${path ? `/${path}` : ''}`);
|
||||||
|
iframe.setAttribute('allowtransparency', 'true');
|
||||||
|
Object.assign(iframe.style, {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
border: 'none',
|
||||||
|
background: 'transparent', // important
|
||||||
|
});
|
||||||
|
|
||||||
|
new UwuiWindow({
|
||||||
|
title: 'Ultrawidify settings (iframe)',
|
||||||
|
width: 1200,
|
||||||
|
height: 800,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
content: iframe,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setUiVisibility(visible) {
|
setUiVisibility(visible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
336
src/ext/lib/uwui/UwuiWindow.ts
Normal file
336
src/ext/lib/uwui/UwuiWindow.ts
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
import extensionCss from '@src/main.css?inline';
|
||||||
|
|
||||||
|
|
||||||
|
type WindowContent = string | HTMLElement;
|
||||||
|
type WindowBackgroundMode = 'transparent' | 'blur' | 'solid';
|
||||||
|
|
||||||
|
interface WindowOptions {
|
||||||
|
title?: string;
|
||||||
|
content: WindowContent;
|
||||||
|
background?: WindowBackgroundMode;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
x?: number;
|
||||||
|
y?: number;
|
||||||
|
extraStyles?: string[];
|
||||||
|
onFocus?: () => void;
|
||||||
|
onClose?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UwuiWindow {
|
||||||
|
private static baseZ = 1000000;
|
||||||
|
private static instances: UwuiWindow[] = [];
|
||||||
|
|
||||||
|
private host: HTMLDivElement;
|
||||||
|
private shadow: ShadowRoot;
|
||||||
|
private windowEl: HTMLDivElement;
|
||||||
|
private titleBar: HTMLDivElement;
|
||||||
|
|
||||||
|
private dragging = false;
|
||||||
|
private resizing = false;
|
||||||
|
private dragOffsetX = 0;
|
||||||
|
private dragOffsetY = 0;
|
||||||
|
|
||||||
|
private background: WindowBackgroundMode = 'blur';
|
||||||
|
private extraStyles?: string[];
|
||||||
|
|
||||||
|
private onFocus?: () => void;
|
||||||
|
private onClose?: () => void;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(options: WindowOptions) {
|
||||||
|
this.onFocus = options.onFocus;
|
||||||
|
this.onClose = options.onClose;
|
||||||
|
|
||||||
|
this.host = document.createElement('div');
|
||||||
|
this.host.style.position = 'fixed';
|
||||||
|
this.host.style.inset = '0';
|
||||||
|
this.host.style.pointerEvents = 'none';
|
||||||
|
|
||||||
|
this.background = options.background ?? 'blur';
|
||||||
|
this.extraStyles = options.extraStyles;
|
||||||
|
|
||||||
|
document.body.appendChild(this.host);
|
||||||
|
|
||||||
|
this.shadow = this.host.attachShadow({ mode: 'closed' });
|
||||||
|
this.shadow.innerHTML = this.template(options);
|
||||||
|
|
||||||
|
|
||||||
|
this.windowEl = this.shadow.querySelector('.uw-window')!;
|
||||||
|
this.titleBar = this.shadow.querySelector('.uw-titlebar')!;
|
||||||
|
|
||||||
|
this.setGeometry(
|
||||||
|
options.x ?? 100,
|
||||||
|
options.y ?? 100,
|
||||||
|
options.width ?? 320,
|
||||||
|
options.height ?? 220
|
||||||
|
);
|
||||||
|
|
||||||
|
this.injectContent(options.content);
|
||||||
|
this.bindEvents();
|
||||||
|
|
||||||
|
UwuiWindow.instances.unshift(this);
|
||||||
|
UwuiWindow.recomputeZIndices();
|
||||||
|
|
||||||
|
this.applyBackground();
|
||||||
|
|
||||||
|
this.bindBackgroundMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets window stacking order
|
||||||
|
* @param order stacking order (0 = topmost)
|
||||||
|
*/
|
||||||
|
setOrder(order: number) {
|
||||||
|
const list = UwuiWindow.instances;
|
||||||
|
|
||||||
|
// Remove this window from current position
|
||||||
|
const currentIndex = list.indexOf(this);
|
||||||
|
if (currentIndex !== -1) {
|
||||||
|
list.splice(currentIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp target index
|
||||||
|
const clamped = Math.max(0, Math.min(order, list.length));
|
||||||
|
|
||||||
|
// Insert at new position
|
||||||
|
list.splice(clamped, 0, this);
|
||||||
|
|
||||||
|
// Re-assign z-indexes
|
||||||
|
UwuiWindow.recomputeZIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.onClose?.();
|
||||||
|
|
||||||
|
const list = UwuiWindow.instances;
|
||||||
|
const index = list.indexOf(this);
|
||||||
|
if (index !== -1) {
|
||||||
|
list.splice(index, 1);
|
||||||
|
UwuiWindow.recomputeZIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.host.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static recomputeZIndices() {
|
||||||
|
const base = UwuiWindow.baseZ;
|
||||||
|
|
||||||
|
UwuiWindow.instances.forEach((win, index) => {
|
||||||
|
// index 0 = topmost → highest z-index
|
||||||
|
win.host.style.zIndex = String(base + (UwuiWindow.instances.length - index));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bringToFront = () => {
|
||||||
|
this.setOrder(0);
|
||||||
|
this.onFocus?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
//#region setup
|
||||||
|
private template(options: WindowOptions): string {
|
||||||
|
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
${this.generateStyles()}
|
||||||
|
|
||||||
|
${this.extraStyles?.join('\n')}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="uw-window">
|
||||||
|
<div class="uw-titlebar">
|
||||||
|
<span class="uw-title">${options.title ?? ''}</span>
|
||||||
|
|
||||||
|
<div class="uw-actions">
|
||||||
|
<div class="uw-bg-toggle">
|
||||||
|
<!-- YOUR SVG ICON GOES HERE -->
|
||||||
|
<button type="button" class="uw-bg-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>layers-outline</title><path d="M12,18.54L19.37,12.8L21,14.07L12,21.07L3,14.07L4.62,12.81L12,18.54M12,16L3,9L12,2L21,9L12,16M12,4.53L6.26,9L12,13.47L17.74,9L12,4.53Z" /></svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="uw-bg-menu">
|
||||||
|
<button data-bg="transparent">Transparent</button>
|
||||||
|
<button data-bg="blur">Blur</button>
|
||||||
|
<button data-bg="solid">Solid</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" class="uw-close">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>close</title><path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" /></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uw-content"></div>
|
||||||
|
<div class="uw-resize-handle"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateStyles() {
|
||||||
|
let css = extensionCss
|
||||||
|
.trim()
|
||||||
|
.replace(/'html, body \{/g, ':host {')
|
||||||
|
.replace(/'body \{/g, ':host {')
|
||||||
|
;
|
||||||
|
|
||||||
|
// this is bad but I can't be bothered to do it the proper way
|
||||||
|
const cssArr: string[] = css.split('@font-face');
|
||||||
|
const cssRemainder = cssArr[cssArr.length - 1].split('}').slice(1).join('}');
|
||||||
|
|
||||||
|
css = `
|
||||||
|
${cssArr[0]}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Heebo';
|
||||||
|
src: url(__FONT_HEEBO__) format('truetype-variations');
|
||||||
|
font-weight: 100 900;
|
||||||
|
font-stretch: 75% 125%;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Code Pro';
|
||||||
|
src: url(__FONT_SCP__) format('truetype-variations');
|
||||||
|
font-weight: 200 900;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Code Pro';
|
||||||
|
src: url(__FONT_SCPI__) format('truetype-variations');
|
||||||
|
font-weight: 200 900;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
${cssRemainder};
|
||||||
|
`;
|
||||||
|
|
||||||
|
return css
|
||||||
|
.replace('__FONT_HEEBO__', chrome.runtime.getURL('/ui/res/fonts/Heebo.ttf'))
|
||||||
|
.replace('__FONT_SCP__', chrome.runtime.getURL('/ui/res/fonts/SourceCodePro.ttf'))
|
||||||
|
.replace('__FONT_SCPI__', chrome.runtime.getURL('/ui/res/fonts/SourceCodePro-Italic.ttf'))
|
||||||
|
.replaceAll('html,', '')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
private injectContent(content: WindowContent) {
|
||||||
|
const container = this.shadow.querySelector('.uw-content')!;
|
||||||
|
if (typeof content === 'string') {
|
||||||
|
container.innerHTML = content;
|
||||||
|
} else {
|
||||||
|
container.appendChild(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region interactivity
|
||||||
|
private bindEvents() {
|
||||||
|
this.windowEl.addEventListener('mousedown', this.bringToFront);
|
||||||
|
|
||||||
|
this.titleBar.addEventListener('mousedown', this.startDrag);
|
||||||
|
|
||||||
|
this.shadow.querySelector('.uw-close')!
|
||||||
|
.addEventListener('click', () => this.destroy());
|
||||||
|
|
||||||
|
this.shadow.querySelector('.uw-resize-handle')!
|
||||||
|
.addEventListener('mousedown', this.startResize);
|
||||||
|
|
||||||
|
window.addEventListener('mousemove', this.onMouseMove);
|
||||||
|
window.addEventListener('mouseup', this.stopActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private startDrag = (e: MouseEvent) => {
|
||||||
|
const rect = this.windowEl.getBoundingClientRect();
|
||||||
|
this.dragging = true;
|
||||||
|
this.dragOffsetX = e.clientX - rect.left;
|
||||||
|
this.dragOffsetY = e.clientY - rect.top;
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
private startResize = (e: MouseEvent) => {
|
||||||
|
this.resizing = true;
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
private onMouseMove = (e: MouseEvent) => {
|
||||||
|
const rect = this.windowEl.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (this.dragging) {
|
||||||
|
const x = Math.min(
|
||||||
|
window.innerWidth - rect.width,
|
||||||
|
Math.max(0, e.clientX - this.dragOffsetX)
|
||||||
|
);
|
||||||
|
const y = Math.min(
|
||||||
|
window.innerHeight - rect.height,
|
||||||
|
Math.max(0, e.clientY - this.dragOffsetY)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.windowEl.style.left = `${x}px`;
|
||||||
|
this.windowEl.style.top = `${y}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.resizing) {
|
||||||
|
const width = Math.max(160, e.clientX - rect.left);
|
||||||
|
const height = Math.max(120, e.clientY - rect.top);
|
||||||
|
|
||||||
|
this.windowEl.style.width = `${width}px`;
|
||||||
|
this.windowEl.style.height = `${height}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private stopActions = () => {
|
||||||
|
this.dragging = false;
|
||||||
|
this.resizing = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
private setGeometry(x: number, y: number, w: number, h: number) {
|
||||||
|
Object.assign(this.windowEl.style, {
|
||||||
|
left: `${x}px`,
|
||||||
|
top: `${y}px`,
|
||||||
|
width: `${w}px`,
|
||||||
|
height: `${h}px`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//#endregion interactivity
|
||||||
|
|
||||||
|
//#region bakcground handling
|
||||||
|
setBackground(mode: WindowBackgroundMode) {
|
||||||
|
this.background = mode;
|
||||||
|
this.applyBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyBackground() {
|
||||||
|
this.windowEl.classList.remove(
|
||||||
|
'uw-window-bg-transparent',
|
||||||
|
'uw-window-bg-blurred',
|
||||||
|
'uw-window-bg-solid'
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (this.background) {
|
||||||
|
case 'transparent':
|
||||||
|
this.windowEl.classList.add('uw-window-bg-transparent');
|
||||||
|
break;
|
||||||
|
case 'blur':
|
||||||
|
this.windowEl.classList.add('uw-window-bg-blurred');
|
||||||
|
break;
|
||||||
|
case 'solid':
|
||||||
|
this.windowEl.classList.add('uw-window-bg-solid');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bindBackgroundMenu() {
|
||||||
|
this.shadow.querySelectorAll('[data-bg]')
|
||||||
|
.forEach(el => {
|
||||||
|
el.addEventListener('click', () => {
|
||||||
|
const mode = el.getAttribute('data-bg') as WindowBackgroundMode;
|
||||||
|
this.setBackground(mode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
}
|
||||||
@ -7,14 +7,15 @@
|
|||||||
@import '@ui/res/styles/buttons.css';
|
@import '@ui/res/styles/buttons.css';
|
||||||
|
|
||||||
@import '@ui/res/styles/player-menu.css';
|
@import '@ui/res/styles/player-menu.css';
|
||||||
|
@import '@ui/res/styles/player-window.css';
|
||||||
|
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
@apply bg-stone-950 text-stone-300;
|
@apply bg-transparent text-stone-300;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
html, body {
|
html, body {
|
||||||
@apply bg-stone-950 text-stone-300;
|
@apply bg-transparent text-stone-300;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -95,6 +95,15 @@
|
|||||||
></SiteExtensionSettings>
|
></SiteExtensionSettings>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-if="settings && selectedTab === 'window.site-extension-settings'" >
|
||||||
|
<h3>Settings for {{site?.host}}</h3>
|
||||||
|
<SiteExtensionSettings
|
||||||
|
:settings="settings"
|
||||||
|
:siteSettings="siteSettings"
|
||||||
|
:isDefaultConfiguration="false"
|
||||||
|
></SiteExtensionSettings>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template v-if="settings && selectedTab === 'embedded-extension-settings'" >
|
<template v-if="settings && selectedTab === 'embedded-extension-settings'" >
|
||||||
<h3>Settings for embedded sites</h3>
|
<h3>Settings for embedded sites</h3>
|
||||||
<FrameSiteSettings
|
<FrameSiteSettings
|
||||||
@ -223,6 +232,15 @@ const AVAILABLE_TABS = {
|
|||||||
{ id: 'default-extension-settings', label: 'Default settings' }
|
{ id: 'default-extension-settings', label: 'Default settings' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
'window.site-extension-settings': {
|
||||||
|
id: 'window.site-extension-settings', label: 'Site and Extension options', icon: 'cogs',
|
||||||
|
children: [
|
||||||
|
{ id: 'window.site-extension-settings', label: 'For this site', },
|
||||||
|
{ id: 'embedded-extension-settings', label: 'For embedded sites', disabled: true, badgeCount: 0, },
|
||||||
|
{ id: 'default-extension-settings', label: 'Default settings' },
|
||||||
|
{ id: 'website-extension-settings', label: 'Website exceptions' },
|
||||||
|
]
|
||||||
|
},
|
||||||
'default-extension-settings': {
|
'default-extension-settings': {
|
||||||
id: 'default-extension-settings', label: 'Site and Extension options', icon: 'cogs',
|
id: 'default-extension-settings', label: 'Site and Extension options', icon: 'cogs',
|
||||||
children: [
|
children: [
|
||||||
@ -258,7 +276,15 @@ const TAB_LOADOUT = {
|
|||||||
'debugging',
|
'debugging',
|
||||||
],
|
],
|
||||||
'ui': [
|
'ui': [
|
||||||
'window.player-element-settings'
|
'window.site-extension-settings',
|
||||||
|
'window.player-element-settings',
|
||||||
|
'autodetectionSettings',
|
||||||
|
'ui-settings',
|
||||||
|
'keyboardShortcuts',
|
||||||
|
'changelog',
|
||||||
|
'about',
|
||||||
|
'import-export-settings',
|
||||||
|
'debugging',
|
||||||
],
|
],
|
||||||
'updated': [
|
'updated': [
|
||||||
'updated',
|
'updated',
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
@change="settings.saveWithoutReload"
|
@change="settings.saveWithoutReload"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full grid grid-cols-1 min-[1200px]:grid-cols-2 min-[1920px]:grid-cols-3 max-w-[2300px] gap-8">
|
<div class="w-full grid grid-cols-1 min-[1200px]:grid-cols-2 min-[1920px]:grid-cols-3 max-w-[2300px] gap-8">
|
||||||
<div class="grow shrink">
|
<div class="grow shrink">
|
||||||
<h3 class="mb-4">Logger configuration</h3>
|
<h3 class="mb-4">Logger configuration</h3>
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="
|
<div
|
||||||
w-full h-[100dvh] overflow-hidden
|
class="
|
||||||
p-1 popup-lg:py-2 popup-lg:px-2 window:py-4 window:px-8
|
w-full h-[100dvh] overflow-hidden
|
||||||
flex flex-row justify-center items-center
|
flex flex-row justify-center items-center
|
||||||
">
|
"
|
||||||
|
:class="{
|
||||||
|
'p-1 popup-lg:py-2 popup-lg:px-2 window:py-4 window:px-8 bg-stone-950': role !== 'ui'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
|
||||||
<!-- page content -->
|
<!-- page content -->
|
||||||
<div
|
<div
|
||||||
class="w-full h-[100dvh] overflow-hidden flex flex-col"
|
class="w-full h-[100dvh] overflow-hidden flex flex-col"
|
||||||
:class="{'max-w-[1920px]': !isDebugging}"
|
:class="{'max-w-[1920px]': !isDebugging && role !== 'ui'}"
|
||||||
>
|
>
|
||||||
<PopupHead
|
<PopupHead
|
||||||
v-if="role === 'popup' && settings && siteSettings && eventBus"
|
v-if="role === 'popup' && settings && siteSettings && eventBus"
|
||||||
@ -18,6 +22,9 @@
|
|||||||
:eventBus="eventBus"
|
:eventBus="eventBus"
|
||||||
>
|
>
|
||||||
</PopupHead>
|
</PopupHead>
|
||||||
|
<div v-else-if="role === 'ui'" class="flex flex-row font-mono text-[0.8rem] text-stone-500 border-stone-500">
|
||||||
|
url: {{getUrl}}
|
||||||
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h1 class="text-[3em] grow-0 shrink-0">Ultrawidify settings</h1>
|
<h1 class="text-[3em] grow-0 shrink-0">Ultrawidify settings</h1>
|
||||||
</div>
|
</div>
|
||||||
@ -78,6 +85,11 @@ export default defineComponent({
|
|||||||
isDebugging: false,
|
isDebugging: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
getUrl() {
|
||||||
|
return window.location.href;
|
||||||
|
}
|
||||||
|
},
|
||||||
async created() {
|
async created() {
|
||||||
const [segment, ...path] = window.location.hash.split('/');
|
const [segment, ...path] = window.location.hash.split('/');
|
||||||
this.initialPath = path;
|
this.initialPath = path;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en"; style="position: relative; width: 799px; min-width: 320px; height: 600px; overflow: hidden;">
|
<html lang="en"; style="position: relative; width: 799px; min-width: 320px; height: 600px; overflow: hidden; background-color: transparent;">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark">
|
||||||
|
|||||||
169
src/ui/res/styles/player-window.css
Normal file
169
src/ui/res/styles/player-window.css
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
@import "tailwindcss/utilities";
|
||||||
|
|
||||||
|
:host {
|
||||||
|
all: initial;
|
||||||
|
color-scheme: dark light;
|
||||||
|
|
||||||
|
@apply font-mono text-stone-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uw-window {
|
||||||
|
@apply fixed flex flex-col pointer-events-auto border-stone-500;
|
||||||
|
|
||||||
|
.uw-content {
|
||||||
|
@apply p-4 flex grow-1 font-sans overflow-hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.uw-window-bg-transparent {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&.uw-window-bg-blurred {
|
||||||
|
@apply bg-stone-950/75;
|
||||||
|
backdrop-filter: brightness(50%) saturate(50%) blur(16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.uw-window-bg-solid {
|
||||||
|
@apply bg-stone-950;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.uw-resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: nwse-resize;
|
||||||
|
background:
|
||||||
|
linear-gradient(135deg, transparent 50%, #666 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uw-titlebar {
|
||||||
|
@apply flex flex-row gap-4 items-center cursor-move select-none justify-between
|
||||||
|
bg-stone-950/80 border-b border-b-stone-700;
|
||||||
|
|
||||||
|
.uw-title {
|
||||||
|
@apply px-4 py-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uw-actions {
|
||||||
|
@apply flex flex-row;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply h-[32px] w-[28px] relative p-0 m-0
|
||||||
|
text-stone-300 hover:text-primary-200 bg-transparent border-none border-transparent px-2;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
@apply h-[24px] w-[24px] fill-current;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.uw-close {
|
||||||
|
@apply w-[40px] px-[8px];
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@apply bg-red-600 text-[#fff];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.uw-bg-toggle {
|
||||||
|
@apply relative;
|
||||||
|
|
||||||
|
.uw-bg-menu {
|
||||||
|
@apply absolute top-[100%] right-0 bg-stone-950/75;
|
||||||
|
|
||||||
|
display: none;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-full text-left px-4 py-2 hover:bg-stone-800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&:hover .uw-bg-menu {
|
||||||
|
@apply flex flex-col gap-2
|
||||||
|
min-w-[220px]
|
||||||
|
text-stone-300 hover:text-primary-200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-categories {
|
||||||
|
@apply
|
||||||
|
relative
|
||||||
|
w-[4.5em] popup:w-[18em] window:w-[24em]
|
||||||
|
mr-[1em]
|
||||||
|
grow-0 shrink-0 flex flex-col
|
||||||
|
|
||||||
|
text-right;
|
||||||
|
|
||||||
|
.tab-column {
|
||||||
|
@apply absolute popup:relative top-0 right-0
|
||||||
|
w-[18em] window:w-full h-full z-[1000]
|
||||||
|
hover:bg-stone-950 popup:hover:bg-transparent
|
||||||
|
border-r border-r-stone-800
|
||||||
|
hover:translate-x-[calc(100%-4.5em)] popup:hover:translate-x-0
|
||||||
|
transition-transform duration-200;
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
@apply
|
||||||
|
flex flex-col
|
||||||
|
cursor-pointer
|
||||||
|
border-r-2 border-r-transparent
|
||||||
|
border-r-primary-400;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
.main-tab {
|
||||||
|
@apply !bg-transparent !text-primary-300 bg-gradient-to-r from-transparent to-black hover:!text-primary-200 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
@apply pointer-events-none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-tab {
|
||||||
|
@apply
|
||||||
|
px-[1em] py-[0.5em]
|
||||||
|
flex flex-row gap-4 justify-end items-center
|
||||||
|
text-[1.125em] text-stone-300 text-right font-mono
|
||||||
|
cursor-pointer
|
||||||
|
hover:bg-stone-800
|
||||||
|
hover:text-primary-200
|
||||||
|
hover:border-r-stone-600;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
@apply grow-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.suboption {
|
||||||
|
@apply
|
||||||
|
px-6 py-2
|
||||||
|
uppercase text-stone-400/75 font-mono
|
||||||
|
relative
|
||||||
|
hover:bg-stone-800
|
||||||
|
hover:text-primary-200
|
||||||
|
hover:border-r-stone-600;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
@apply !bg-transparent !text-primary-300 bg-gradient-to-r from-transparent to-black hover:!text-primary-200;
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
@apply pointer-events-none text-stone-600/75;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
@apply absolute right-[0.25rem] bottom-0 w-4 h-4 text-stone-950 bg-primary-300 rounded flex justify-center items-center font-bold text-[0.8rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
@apply
|
||||||
|
mb-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user