mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 22:39:22 +00:00
AvatarScaleMod: renamed folder
This commit is contained in:
parent
a1d73bf156
commit
fd4fe2ea9d
28 changed files with 6 additions and 6 deletions
414
AvatarScaleMod/resources/menu.js
Normal file
414
AvatarScaleMod/resources/menu.js
Normal file
|
@ -0,0 +1,414 @@
|
|||
(function() {
|
||||
|
||||
/* -------------------------------
|
||||
* CSS Embedding
|
||||
* ------------------------------- */
|
||||
function injectCSS() {
|
||||
const embeddedCSS = `
|
||||
|
||||
// ass stands for Avatar Scale Slider
|
||||
|
||||
/* Container styles */
|
||||
.ass-flex-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ass Slider styles */
|
||||
.ass-slider-container {
|
||||
width: 100%;
|
||||
}
|
||||
.ass-slider-base {
|
||||
height: 3.25em;
|
||||
position: relative;
|
||||
background: #555;
|
||||
border-radius: 1.5em;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ass-slider-inner {
|
||||
height: 100%;
|
||||
background: #a9a9a9;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.ass-snap-point {
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
background: white;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
.ass-slider-value {
|
||||
font-size: 2em;
|
||||
position: relative;
|
||||
left: 0.5em;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Category (label) styles */
|
||||
.ass-category-label {
|
||||
font-size: 2.2em;
|
||||
position: relative;
|
||||
left: 0.5em;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
/* Circle Button styles */
|
||||
.ass-circle-button {
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
border-radius: 50%;
|
||||
background-color: #555;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
font-size: 1.75em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
.ass-circle-button:hover {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
/* Custom Toggle styles */
|
||||
.ass-custom-toggle {
|
||||
width: 5em;
|
||||
height: 2.5em;
|
||||
background-color: #555;
|
||||
border-radius: 1.25em;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-65%);
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.ass-toggle-circle {
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
background-color: #a9a9a9;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transition: left 0.3s;
|
||||
}
|
||||
|
||||
.ass-custom-toggle.active .ass-toggle-circle {
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
/* Label styles */
|
||||
.ass-label {
|
||||
font-size: 2em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.ass-toggle-setting {
|
||||
position: relative;
|
||||
height: 3.5em;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
const styleElement = document.createElement('style');
|
||||
styleElement.type = 'text/css';
|
||||
styleElement.innerHTML = embeddedCSS;
|
||||
document.head.appendChild(styleElement);
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* Main Content Element
|
||||
* ------------------------------- */
|
||||
class MainContent {
|
||||
constructor(targetId) {
|
||||
this.element = document.createElement('div');
|
||||
this.element.id = "AvatarScaleModContainer";
|
||||
const targetElement = document.getElementById(targetId);
|
||||
if (targetElement) {
|
||||
targetElement.appendChild(this.element);
|
||||
} else {
|
||||
console.warn(`Target element "${targetId}" not found!`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* Generic Element Class
|
||||
* ------------------------------- */
|
||||
class Element {
|
||||
constructor(tagName, parentElement) {
|
||||
this.element = document.createElement(tagName);
|
||||
parentElement.appendChild(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* Container Object
|
||||
* ------------------------------- */
|
||||
class Container extends Element {
|
||||
constructor(parentElement, {
|
||||
width = '100%',
|
||||
padding = '0em',
|
||||
paddingTop = null,
|
||||
paddingRight = null,
|
||||
paddingBottom = null,
|
||||
paddingLeft = null,
|
||||
margin = '0em',
|
||||
marginTop = null,
|
||||
marginRight = null,
|
||||
marginBottom = null,
|
||||
marginLeft = null
|
||||
} = {}) {
|
||||
super('div', parentElement);
|
||||
this.element.className = "ass-container";
|
||||
this.element.style.width = width;
|
||||
this.element.style.padding = padding;
|
||||
this.element.style.margin = margin;
|
||||
|
||||
// padding values
|
||||
if (paddingTop) this.element.style.paddingTop = paddingTop;
|
||||
if (paddingRight) this.element.style.paddingRight = paddingRight;
|
||||
if (paddingBottom) this.element.style.paddingBottom = paddingBottom;
|
||||
if (paddingLeft) this.element.style.paddingLeft = paddingLeft;
|
||||
|
||||
// margin values
|
||||
if (marginTop) this.element.style.marginTop = marginTop;
|
||||
if (marginRight) this.element.style.marginRight = marginRight;
|
||||
if (marginBottom) this.element.style.marginBottom = marginBottom;
|
||||
if (marginLeft) this.element.style.marginLeft = marginLeft;
|
||||
|
||||
this.flexContainer = new Element('div', this.element);
|
||||
this.flexContainer.element.className = "ass-flex-container";
|
||||
}
|
||||
|
||||
appendElementToFlex(element) {
|
||||
this.flexContainer.element.appendChild(element);
|
||||
}
|
||||
|
||||
appendElement(element) {
|
||||
this.element.appendChild(element);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* Category (label) Class
|
||||
* ------------------------------- */
|
||||
class Category extends Element {
|
||||
constructor(parentElement, text) {
|
||||
super('span', parentElement);
|
||||
this.element.className = "ass-category-label";
|
||||
this.element.textContent = text;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* Circle Button Class
|
||||
* ------------------------------- */
|
||||
class CircleButton extends Element {
|
||||
constructor(parentElement, text) {
|
||||
super('button', parentElement);
|
||||
this.element.className = "ass-circle-button";
|
||||
this.element.textContent = text;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* Custom Toggle Class
|
||||
* ------------------------------- */
|
||||
class CustomToggle extends Element {
|
||||
constructor(parentElement) {
|
||||
super('div', parentElement);
|
||||
this.element.className = "ass-custom-toggle";
|
||||
|
||||
this.toggleCircle = new Element('div', this.element);
|
||||
this.toggleCircle.element.className = "ass-toggle-circle";
|
||||
this.state = false;
|
||||
|
||||
this.element.addEventListener('click', () => {
|
||||
this.toggle();
|
||||
});
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.state = !this.state;
|
||||
if (this.state) {
|
||||
this.toggleCircle.element.style.left = '50%';
|
||||
} else {
|
||||
this.toggleCircle.element.style.left = '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* Label Class
|
||||
* ------------------------------- */
|
||||
class Label extends Element {
|
||||
constructor(parentElement, text) {
|
||||
super('span', parentElement);
|
||||
this.element.className = "ass-label";
|
||||
this.element.textContent = text;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* ToggleSetting Class
|
||||
* ------------------------------- */
|
||||
class ToggleSetting extends Element {
|
||||
constructor(parentElement, labelText) {
|
||||
super('div', parentElement);
|
||||
this.element.className = "ass-toggle-setting";
|
||||
|
||||
const label = new Label(this.element, labelText);
|
||||
this.toggle = new CustomToggle(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
* Slider Object
|
||||
* ------------------------------- */
|
||||
class Slider extends Element {
|
||||
constructor(parentElement, min = 0.1, max = 5, initialValue = 1.8) {
|
||||
super('div', parentElement);
|
||||
this.element.className = "ass-slider-container";
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
|
||||
// Value display
|
||||
this.valueDisplay = new Element('span', this.element);
|
||||
this.valueDisplay.element.className = "ass-slider-value";
|
||||
|
||||
// Slider content
|
||||
this.sliderBase = new Element('div', this.element);
|
||||
this.sliderBase.element.className = "ass-slider-base";
|
||||
|
||||
this.trackInner = new Element('div', this.sliderBase.element);
|
||||
this.trackInner.element.className = "ass-slider-inner";
|
||||
|
||||
this.addEventListeners();
|
||||
|
||||
this.setInitialValue(initialValue);
|
||||
}
|
||||
|
||||
setInitialValue(value) {
|
||||
const percentage = (value - this.min) / (this.max - this.min);
|
||||
this.trackInner.element.style.width = `${percentage * 100}%`;
|
||||
this.valueDisplay.element.textContent = value.toFixed(2) + "m";
|
||||
this.addSnapPoint(percentage);
|
||||
}
|
||||
|
||||
addEventListeners() {
|
||||
this.snapPoints = [];
|
||||
let isDragging = false;
|
||||
|
||||
this.element.addEventListener('mousedown', (e) => {
|
||||
isDragging = true;
|
||||
this.updateTrackWidth(e.clientX);
|
||||
});
|
||||
|
||||
window.addEventListener('mousemove', (e) => {
|
||||
if (!isDragging) return;
|
||||
this.updateTrackWidth(e.clientX);
|
||||
});
|
||||
|
||||
window.addEventListener('mouseup', () => {
|
||||
isDragging = false;
|
||||
});
|
||||
}
|
||||
|
||||
updateTrackWidth(clientX) {
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
const paddingLeft = parseFloat(getComputedStyle(this.element).paddingLeft);
|
||||
const paddingRight = parseFloat(getComputedStyle(this.element).paddingRight);
|
||||
const effectiveWidth = rect.width - paddingLeft - paddingRight;
|
||||
let x = clientX - rect.left - paddingLeft;
|
||||
|
||||
x = Math.min(Math.max(0, x), effectiveWidth);
|
||||
|
||||
let percentage = x / effectiveWidth;
|
||||
const closestSnap = this.snapPoints.reduce((closest, snap) => {
|
||||
return Math.abs(closest - percentage) < Math.abs(snap - percentage) ? closest : snap;
|
||||
}, 1);
|
||||
|
||||
const SNAP_TOLERANCE = 0.01;
|
||||
if (Math.abs(closestSnap - percentage) <= SNAP_TOLERANCE) {
|
||||
x = closestSnap * effectiveWidth;
|
||||
percentage = closestSnap;
|
||||
}
|
||||
|
||||
this.trackInner.element.style.width = `${x}px`;
|
||||
|
||||
const value = this.min + (this.max - this.min) * percentage;
|
||||
this.valueDisplay.element.textContent = value.toFixed(2) + "m";
|
||||
|
||||
engine.call("asm-AvatarHeightUpdated", value);
|
||||
}
|
||||
|
||||
addSnapPoint(percentage) {
|
||||
if (percentage < 0 || percentage > 1) return;
|
||||
const snap = new Element('div', this.sliderBase.element);
|
||||
snap.element.className = 'ass-snap-point';
|
||||
snap.element.style.left = `${percentage * 100}%`;
|
||||
this.snapPoints.push(percentage);
|
||||
}
|
||||
|
||||
addEvenSnapPoints(count) {
|
||||
for (let i = 1; i <= count; i++) {
|
||||
this.addSnapPoint(i / (count + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialization
|
||||
injectCSS();
|
||||
const mainContent = new MainContent('btkUI-AvatarScaleMod-MainPage');
|
||||
if (mainContent.element) {
|
||||
|
||||
const mainContainer = new Container(mainContent.element, {
|
||||
width: '75%',
|
||||
marginTop: '2em',
|
||||
marginLeft: '2em',
|
||||
marginBottom: '1em'
|
||||
});
|
||||
|
||||
const slider = new Slider(mainContainer.flexContainer.element, 0.1, 3);
|
||||
const buttonContainer = new Container(mainContainer.flexContainer.element, {
|
||||
width: '20%',
|
||||
marginTop: '2.5em',
|
||||
marginLeft: '1em',
|
||||
});
|
||||
const circleButton1 = new CircleButton(buttonContainer.flexContainer.element, "+");
|
||||
const circleButton2 = new CircleButton(buttonContainer.flexContainer.element, "-");
|
||||
|
||||
const settingsContainer = new Container(mainContent.element, {
|
||||
width: '100%',
|
||||
marginTop: '1em',
|
||||
marginLeft: '1em',
|
||||
});
|
||||
const categoryLabel = new Category(settingsContainer.element, "Universal Scaling Settings:");
|
||||
|
||||
const settingsContainerInner = new Container(mainContent.element, {
|
||||
width: '90%',
|
||||
marginTop: '1em',
|
||||
marginLeft: '3em',
|
||||
});
|
||||
|
||||
const toggleSetting = new ToggleSetting(settingsContainerInner.element, "Universal Scaling (Mod Network)");
|
||||
const toggleSetting2 = new ToggleSetting(settingsContainerInner.element, "Recognize Scale Gesture");
|
||||
const toggleSetting3 = new ToggleSetting(settingsContainerInner.element, "Scale Components");
|
||||
}
|
||||
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue