Compare commits
No commits in common. "b62f6feaea69b5ccd9a7b8c8d7110ea9ecaf1d7a" and "e651e51c503b7db99c4858ac812905809bf64b46" have entirely different histories.
b62f6feaea
...
e651e51c50
@ -9,17 +9,9 @@ import { MenuPosition as MenuPosition } from '@src/common/interfaces/ClientUiMen
|
|||||||
import { CommandInterface } from '@src/common/interfaces/SettingsInterface';
|
import { CommandInterface } from '@src/common/interfaces/SettingsInterface';
|
||||||
import { SiteSupportLevel } from '@src/common/enums/SiteSupportLevel.enum';
|
import { SiteSupportLevel } from '@src/common/enums/SiteSupportLevel.enum';
|
||||||
import { ComponentLogger } from '../logging/ComponentLogger';
|
import { ComponentLogger } from '../logging/ComponentLogger';
|
||||||
import { setupVideoAlignmentIndicatorInteraction } from '@ui/utils/video-alignment-indicator-handling';
|
|
||||||
|
|
||||||
import alignmentIndicatorSvg from '!!raw-loader!@ui/res/img/alignment-indicators.svg';
|
import alignmentIndicatorSvg from '!!raw-loader!@ui/res/img/alignment-indicators.svg';
|
||||||
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 { 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");
|
||||||
@ -39,18 +31,6 @@ class UI {
|
|||||||
private extensionMenu: ClientMenu;
|
private extensionMenu: ClientMenu;
|
||||||
private logger: ComponentLogger;
|
private logger: ComponentLogger;
|
||||||
|
|
||||||
private uiState = {
|
|
||||||
lockXY: true,
|
|
||||||
zoom: { // log2 scale — 100% is 0
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
},
|
|
||||||
videoAlignment: {
|
|
||||||
x: VideoAlignmentType.Default,
|
|
||||||
y: VideoAlignmentType.Default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public interfaceId,
|
public interfaceId,
|
||||||
public uiConfig, // {parentElement?, eventBus?, isGlobal?, playerData}
|
public uiConfig, // {parentElement?, eventBus?, isGlobal?, playerData}
|
||||||
@ -259,7 +239,7 @@ class UI {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- X/Y LOCK, LINK BAR EDITION -->
|
<!-- X/Y LOCK, LINK BAR EDITION -->
|
||||||
<div id="slider-lock" class="uw-slider-lock-bar-container uw-linked">
|
<div class="uw-slider-lock-bar-container uw-linked">
|
||||||
${lockBarIndicatorSvg}
|
${lockBarIndicatorSvg}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -268,8 +248,8 @@ class UI {
|
|||||||
id="_button_toggle_aspect_lock"
|
id="_button_toggle_aspect_lock"
|
||||||
class="uw-freeform-zoom-button uw-link-button uw-linked"
|
class="uw-freeform-zoom-button uw-link-button uw-linked"
|
||||||
>
|
>
|
||||||
<svg id="_button_toggle_aspect_lock_locked" class="svg-icon uw-linked" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>link-variant</title><path d="M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z" /></svg>
|
<svg id="_button_toggle_aspect_lock_locked" class="uw-linked" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>link-variant</title><path d="M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z" /></svg>
|
||||||
<svg id="_button_toggle_aspect_lock_unlocked" class="svg-icon uw-unlinked" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>link-variant-off</title><path d="M2,5.27L3.28,4L20,20.72L18.73,22L13.9,17.17L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L12.5,15.76L10.88,14.15C10.87,14.39 10.77,14.64 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C8.12,13.77 7.63,12.37 7.72,11L2,5.27M12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.79,8.97L9.38,7.55L12.71,4.22M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.2,10.54 16.61,12.5 16.06,14.23L14.28,12.46C14.23,11.78 13.94,11.11 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z" /></svg>
|
<svg id="_button_toggle_aspect_lock_unlocked" class="uw-unlinked" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>link-variant-off</title><path d="M2,5.27L3.28,4L20,20.72L18.73,22L13.9,17.17L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L12.5,15.76L10.88,14.15C10.87,14.39 10.77,14.64 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C8.12,13.77 7.63,12.37 7.72,11L2,5.27M12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.79,8.97L9.38,7.55L12.71,4.22M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.2,10.54 16.61,12.5 16.06,14.23L14.28,12.46C14.23,11.78 13.94,11.11 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z" /></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -278,7 +258,7 @@ class UI {
|
|||||||
id="_button_reset_zoom"
|
id="_button_reset_zoom"
|
||||||
class="uw-freeform-zoom-button"
|
class="uw-freeform-zoom-button"
|
||||||
>
|
>
|
||||||
<svg class="svg-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>restore</title><path d="M13,3A9,9 0 0,0 4,12H1L4.89,15.89L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3Z" /></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>restore</title><path d="M13,3A9,9 0 0,0 4,12H1L4.89,15.89L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3Z" /></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -288,142 +268,20 @@ class UI {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Align video to ...',
|
label: 'Align',
|
||||||
subitems: [{
|
subitems: [{label: 'todo pls'}]
|
||||||
customId: 'videoAlignmentController',
|
|
||||||
customClassList: '',
|
|
||||||
customHTML: `<div class="svg-icon">
|
|
||||||
${alignmentIndicatorSvg}
|
|
||||||
</div>`,
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Extension settings',
|
label: 'todo: open settings'
|
||||||
action: () => this.createSettingsWindow(),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Cropping issues?',
|
label: 'todo: first-time "customize/hide menu" option'
|
||||||
action: () => this.createSettingsWindow('ui-settings'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Report a problem',
|
|
||||||
action: () => this.createSettingsWindow('about'),
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
this.extensionMenu = new ClientMenu(menuConfig);
|
this.extensionMenu = new ClientMenu(menuConfig);
|
||||||
this.extensionMenu.mount(this.uiConfig.parentElement);
|
this.extensionMenu.mount(this.uiConfig.parentElement);
|
||||||
|
|
||||||
/**
|
|
||||||
* SETUP MENU INTERACTIONS
|
|
||||||
* ———————————————————————————————————
|
|
||||||
* Interactions are needed for the following things:
|
|
||||||
* 0. [ ] both sliders. Needs to read the state of the sliders and update the labels
|
|
||||||
* 1. [ ] lock X/Y button — needs to update icon state of the button and the linked bar
|
|
||||||
* 2. [ ] reset button — just needs to reset, no icon changes necessary
|
|
||||||
* 3. [X] alignment indicator — also needs to update indicator state
|
|
||||||
*/
|
|
||||||
const menuElement = this.extensionMenu.root;
|
|
||||||
|
|
||||||
// 0. SLIDERS —————————————————————————————————————————————————————————————————————————————
|
|
||||||
const zoomWidthSlider: HTMLInputElement = menuElement.querySelector('#_input_zoom_slider');
|
|
||||||
const zoomHeightSlider: HTMLInputElement = menuElement.querySelector('#_input_zoom_slider_2');
|
|
||||||
const zoomWidthLabel: HTMLDivElement = menuElement.querySelector('#zoomWidth');
|
|
||||||
const zoomHeightLabel: HTMLDivElement = menuElement.querySelector('#zoomHeight');
|
|
||||||
|
|
||||||
const updateZoomDisplayValues = () => {
|
|
||||||
zoomWidthLabel.textContent = `${Math.round((Math.exp(this.uiState.zoom.x) * 100))}%`;
|
|
||||||
zoomHeightLabel.textContent = `${Math.round((Math.exp(this.uiState.zoom.y) * 100))}%`;
|
|
||||||
zoomWidthSlider.value = this.uiState.zoom.x.toString();
|
|
||||||
zoomHeightSlider.value = this.uiState.zoom.y.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateZoom = (event: InputEvent, axis: 'x' | 'y') => {
|
|
||||||
const parsedValue = parseFloat((event.currentTarget as HTMLInputElement).value);
|
|
||||||
|
|
||||||
if (this.uiState.lockXY) {
|
|
||||||
this.uiState.zoom = {x: parsedValue, y: parsedValue};
|
|
||||||
} else {
|
|
||||||
this.uiState.zoom[axis] = parsedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateZoomDisplayValues();
|
|
||||||
|
|
||||||
this.eventBus?.send('set-zoom', {
|
|
||||||
zoom: {
|
|
||||||
x: Math.pow(2, this.uiState.zoom.x),
|
|
||||||
y: Math.pow(2, this.uiState.zoom.y)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
zoomWidthSlider.addEventListener('input', (event: InputEvent) => updateZoom(event, 'x'));
|
|
||||||
zoomHeightSlider.addEventListener('input', (event: InputEvent) => updateZoom(event, 'y'));
|
|
||||||
|
|
||||||
// 1. LOCK X/Y ————————————————————————————————————————————————————————————————————————————
|
|
||||||
const lockXYButton = menuElement.querySelector('#_button_toggle_aspect_lock');
|
|
||||||
const sliderLockBar = menuElement.querySelector('#slider-lock');
|
|
||||||
lockXYButton.addEventListener('click', () => {
|
|
||||||
this.uiState.lockXY = !this.uiState.lockXY;
|
|
||||||
|
|
||||||
if (this.uiState.lockXY) {
|
|
||||||
lockXYButton.classList.add('uw-linked');
|
|
||||||
lockXYButton.classList.remove('uw-unlinked');
|
|
||||||
sliderLockBar.classList.add('uw-linked');
|
|
||||||
sliderLockBar.classList.remove('uw-unlinked');
|
|
||||||
} else {
|
|
||||||
lockXYButton.classList.add('uw-unlinked');
|
|
||||||
lockXYButton.classList.remove('uw-linked');
|
|
||||||
sliderLockBar.classList.add('uw-unlinked');
|
|
||||||
sliderLockBar.classList.remove('uw-linked');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. ZOOM RESET BUTTON ———————————————————————————————————————————————————————————————————
|
|
||||||
const zoomResetButton = menuElement.querySelector('#_button_reset_zoom');
|
|
||||||
zoomResetButton.addEventListener('click', () => {
|
|
||||||
this.eventBus?.send('set-zoom', { zoom: {x: 1, y: 1} });
|
|
||||||
this.uiState.zoom = {x: 0, y: 0};
|
|
||||||
updateZoomDisplayValues();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. VIDEO ALIGNMENT INDICATOR ———————————————————————————————————————————————————————————
|
|
||||||
const videoAlignmentIndicatorElement: SVGSVGElement = menuElement.querySelector('#_uw_ui_alignment_indicator');
|
|
||||||
setupVideoAlignmentIndicatorInteraction(
|
|
||||||
videoAlignmentIndicatorElement,
|
|
||||||
(x: VideoAlignmentType, y: VideoAlignmentType) => {
|
|
||||||
setVideoAlignmentIndicatorState(videoAlignmentIndicatorElement, x, y);
|
|
||||||
if (this.eventBus) {
|
|
||||||
this.eventBus?.send('set-alignment', {x,y});
|
|
||||||
this.uiState.videoAlignment = {x,y};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
||||||
|
|||||||
@ -1,336 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -73,11 +73,7 @@ class Resizer {
|
|||||||
if (this._lastAr?.type !== x.type || this._lastAr?.ratio !== x.ratio) {
|
if (this._lastAr?.type !== x.type || this._lastAr?.ratio !== x.ratio) {
|
||||||
this.eventBus.send('uw-config-broadcast', {type: 'ar', config: x});
|
this.eventBus.send('uw-config-broadcast', {type: 'ar', config: x});
|
||||||
}
|
}
|
||||||
if (x) {
|
|
||||||
this._lastAr = x;
|
this._lastAr = x;
|
||||||
} else {
|
|
||||||
this._lastAr = {type: AspectRatioType.Initial};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
get lastAr() {
|
get lastAr() {
|
||||||
return this._lastAr;
|
return this._lastAr;
|
||||||
@ -493,9 +489,8 @@ class Resizer {
|
|||||||
|
|
||||||
toFixedAr() {
|
toFixedAr() {
|
||||||
// converting to fixed AR means we also turn off autoAR
|
// converting to fixed AR means we also turn off autoAR
|
||||||
|
|
||||||
this.setAr({
|
this.setAr({
|
||||||
ratio: this.lastAr.ratio ?? this.getFileAr(),
|
ratio: this.lastAr.ratio,
|
||||||
type: AspectRatioType.Fixed
|
type: AspectRatioType.Fixed
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,15 +7,14 @@
|
|||||||
@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-transparent text-stone-300;
|
@apply bg-stone-950 text-stone-300;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
html, body {
|
html, body {
|
||||||
@apply bg-transparent text-stone-300;
|
@apply bg-stone-950 text-stone-300;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -95,15 +95,6 @@
|
|||||||
></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
|
||||||
@ -232,15 +223,6 @@ 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: [
|
||||||
@ -276,15 +258,7 @@ const TAB_LOADOUT = {
|
|||||||
'debugging',
|
'debugging',
|
||||||
],
|
],
|
||||||
'ui': [
|
'ui': [
|
||||||
'window.site-extension-settings',
|
'window.player-element-settings'
|
||||||
'window.player-element-settings',
|
|
||||||
'autodetectionSettings',
|
|
||||||
'ui-settings',
|
|
||||||
'keyboardShortcuts',
|
|
||||||
'changelog',
|
|
||||||
'about',
|
|
||||||
'import-export-settings',
|
|
||||||
'debugging',
|
|
||||||
],
|
],
|
||||||
'updated': [
|
'updated': [
|
||||||
'updated',
|
'updated',
|
||||||
|
|||||||
@ -23,7 +23,6 @@
|
|||||||
@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,18 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="
|
||||||
class="
|
|
||||||
w-full h-[100dvh] overflow-hidden
|
w-full h-[100dvh] overflow-hidden
|
||||||
|
p-1 popup-lg:py-2 popup-lg:px-2 window:py-4 window:px-8
|
||||||
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 && role !== 'ui'}"
|
:class="{'max-w-[1920px]': !isDebugging}"
|
||||||
>
|
>
|
||||||
<PopupHead
|
<PopupHead
|
||||||
v-if="role === 'popup' && settings && siteSettings && eventBus"
|
v-if="role === 'popup' && settings && siteSettings && eventBus"
|
||||||
@ -22,9 +18,6 @@
|
|||||||
: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>
|
||||||
@ -85,11 +78,6 @@ 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; background-color: transparent;">
|
<html lang="en"; style="position: relative; width: 799px; min-width: 320px; height: 600px; overflow: hidden;">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark">
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import "tailwindcss/utilities";
|
@import "tailwindcss/utilities";
|
||||||
|
|
||||||
|
svg {
|
||||||
|
@apply text-inherit fill-current stroke-current;
|
||||||
|
|
||||||
|
* {
|
||||||
|
@apply text-inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.uw-menu-root {
|
.uw-menu-root {
|
||||||
@apply h-full w-full font-mono text-stone-200 text-[16px] flex flex-row bg-transparent;
|
@apply h-full w-full font-mono text-stone-200 text-[16px] flex flex-row bg-transparent;
|
||||||
|
|
||||||
@ -53,18 +61,6 @@
|
|||||||
/* * {
|
/* * {
|
||||||
@apply font-mono text-stone-200 text-[1em];
|
@apply font-mono text-stone-200 text-[1em];
|
||||||
} */
|
} */
|
||||||
|
|
||||||
svg {
|
|
||||||
@apply text-inherit fill-current stroke-transparent;
|
|
||||||
|
|
||||||
* {
|
|
||||||
@apply text-inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
@apply fill-stone-300 stroke-transparent border-transparent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.uw-hidden {
|
.uw-hidden {
|
||||||
@ -158,6 +154,7 @@
|
|||||||
@apply inline-flex flex-row items-center !gap-4 rounded-[0.5rem] relative;
|
@apply inline-flex flex-row items-center !gap-4 rounded-[0.5rem] relative;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
@apply fill-current stroke-current;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +171,7 @@
|
|||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
@apply fill-current stroke-current;
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +189,7 @@
|
|||||||
@apply flex flex-row items-center justify-center w-[420px];
|
@apply flex flex-row items-center justify-center w-[420px];
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
@apply fill-current stroke-current text-inherit;
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,26 +250,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#videoAlignmentController {
|
|
||||||
@apply text-stone-400;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
@apply border-transparent fill-stone-300 stroke-transparent;
|
|
||||||
|
|
||||||
* {
|
|
||||||
@apply border-transparent text-inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
rect {
|
|
||||||
stroke: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected {
|
|
||||||
@apply fill-primary-400 stroke-primary-400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.uw-link-button.uw-linked .uw-unlinked {
|
.uw-link-button.uw-linked .uw-unlinked {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,169 +0,0 @@
|
|||||||
@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