mirror of
https://gitlab.com/vyla-entertainment/home.git
synced 2026-11-13 21:57:21 -05:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fbb5a4437d | |||
| dbaab9a00e | |||
| fc49bb93a7 | |||
| 9229f0c2dd | |||
| 843abf7df4 | |||
| 27fda0430b | |||
| 8b49d679bd | |||
| 62883b3180 | |||
| 3c6ae0125b | |||
| be0810ea6d | |||
| dff55060e7 | |||
| df767b5ffc | |||
| 1b70c6784a | |||
| e25e1c93f9 | |||
| 4c708ad97c | |||
| b81a4e044b | |||
| f6aa2daa01 | |||
| e03eb38adc | |||
| 2b690b47c1 | |||
| dffbdb92a5 | |||
| 45d6515f2e | |||
| a3e6a278fe |
1
DOCUEMENTATION/CLEAR.bash
Normal file
1
DOCUEMENTATION/CLEAR.bash
Normal file
@@ -0,0 +1 @@
|
||||
bash -c 'pkill -9 -x node 2>/dev/null; pkill -9 -x "Vyla Home" 2>/dev/null; pkill -9 -x "vyla-home" 2>/dev/null; rm -rf "$HOME/Library/Application Support/com.vyla.home" "$HOME/Library/Application Support/vyla-home" "$HOME/Library/Application Support/Vyla Home" "$HOME/Library/Caches/com.vyla.home" "$HOME/Library/Caches/vyla-home" "$HOME/Library/Caches/Vyla Home" "$HOME/Library/WebKit/com.vyla.home" "$HOME/Library/WebKit/vyla-home" "$HOME/Library/WebKit/Vyla Home" "$HOME/Library/Logs/Vyla Home" "$HOME/Library/Preferences/com.vyla.home.plist" "$HOME/.vyla-home" "/Applications/Vyla Home.app" "/Applications/vyla-home.app" "$HOME/Applications/Vyla Home.app" "$HOME/Applications/vyla-home.app" "src-tauri/target" "dist-build" "temp-validation-extract" "dist" "frontend" "player" "auth-proxy" "stream-api" "logs" "*.log" "download-temp.zip" "update-payload.zip" "manifest.json" "validation-report.json" "config/encrypted-credentials.json" "config/credentials.json"; echo "Vyla Home cleanup complete."'
|
||||
@@ -22,8 +22,8 @@ const clonedRepos = new Set();
|
||||
|
||||
function clonePrivateRepo(repoConfig, targetDir) {
|
||||
if (fs.existsSync(targetDir)) {
|
||||
console.log(`[DEV] ${repoConfig.name} already exists locally. Skipping clone to use local changes.`);
|
||||
return;
|
||||
console.log(`Removing stale ${repoConfig.name} before fresh clone...`);
|
||||
fs.rmSync(targetDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
const token = process.env.GITLAB_TOKEN || process.env.VYLA_GITLAB_TOKEN;
|
||||
|
||||
@@ -27,6 +27,20 @@ workflows:
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
||||
node release.js --installer --tag="v$PACKAGE_VERSION"
|
||||
- name: Verify bundled node permissions
|
||||
script: |
|
||||
if [ -f "bin/node" ]; then
|
||||
chmod +x bin/node
|
||||
xattr -cr bin/node || true
|
||||
ls -la bin/node
|
||||
file bin/node
|
||||
fi
|
||||
APP_NODE=$(find src-tauri/target/release/bundle -name "node" -path "*bin*" 2>/dev/null | head -1)
|
||||
if [ -n "$APP_NODE" ]; then
|
||||
chmod +x "$APP_NODE"
|
||||
xattr -cr "$APP_NODE" || true
|
||||
ls -la "$APP_NODE"
|
||||
fi
|
||||
artifacts:
|
||||
- src-tauri/target/release/bundle/dmg/*.dmg
|
||||
- src-tauri/target/release/bundle/macos/*.app
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vyla-home",
|
||||
"version": "1.1.14",
|
||||
"version": "1.1.25",
|
||||
"description": "Vyla Home Desktop App Launcher",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
11
release.js
11
release.js
@@ -295,11 +295,18 @@ function ensureBundledNode() {
|
||||
try {
|
||||
execSync(`tar -xzf node.tar.gz ${tarName}/bin/node`, { cwd: binDir });
|
||||
|
||||
fs.renameSync(path.join(binDir, tarName, 'bin', 'node'), path.join(binDir, 'node'));
|
||||
const extractedNode = path.join(binDir, tarName, 'bin', 'node');
|
||||
const finalNode = path.join(binDir, 'node');
|
||||
|
||||
fs.renameSync(extractedNode, finalNode);
|
||||
fs.rmSync(path.join(binDir, tarName), { recursive: true, force: true });
|
||||
fs.unlinkSync(tarPath);
|
||||
|
||||
execSync(`chmod +x node`, { cwd: binDir });
|
||||
fs.chmodSync(finalNode, 0o755);
|
||||
|
||||
try {
|
||||
execSync(`xattr -d com.apple.quarantine "${finalNode}"`);
|
||||
} catch (_) { }
|
||||
|
||||
fs.writeFileSync(versionMarker, nodeVersion, 'utf8');
|
||||
resolve();
|
||||
|
||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@@ -4222,7 +4222,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vyla-home"
|
||||
version = "1.1.14"
|
||||
version = "1.1.25"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"serde",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "vyla-home"
|
||||
version = "1.1.14"
|
||||
version = "1.1.25"
|
||||
description = "Vyla Home Desktop App Launcher"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
21
src-tauri/Info.plist
Normal file
21
src-tauri/Info.plist
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>localhost</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
<key>NSIncludesSubdomains</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -58,15 +58,23 @@ fn kill_child_process(child: &mut Child) {
|
||||
|
||||
fn find_node_binary(app: &tauri::App) -> Option<String> {
|
||||
if let Ok(resource_dir) = app.path().resource_dir() {
|
||||
#[cfg(windows)]
|
||||
let candidates = [
|
||||
resource_dir.join("bin").join("node.exe"),
|
||||
resource_dir.join("bin").join("node"),
|
||||
resource_dir.join("node.exe"),
|
||||
resource_dir.join("node"),
|
||||
resource_dir.join("_up_").join("bin").join("node.exe"),
|
||||
resource_dir.join("_up_").join("bin").join("node"),
|
||||
resource_dir.join("_up_").join("node.exe"),
|
||||
resource_dir.join("up").join("bin").join("node.exe"),
|
||||
resource_dir.join("up").join("node.exe"),
|
||||
];
|
||||
#[cfg(not(windows))]
|
||||
let candidates = [
|
||||
resource_dir.join("bin").join("node"),
|
||||
resource_dir.join("node"),
|
||||
resource_dir.join("_up_").join("bin").join("node"),
|
||||
resource_dir.join("_up_").join("node"),
|
||||
resource_dir.join("up").join("bin").join("node"),
|
||||
resource_dir.join("up").join("node"),
|
||||
];
|
||||
for candidate in candidates {
|
||||
if candidate.exists() {
|
||||
@@ -156,6 +164,7 @@ fn resolve_script_and_root(app: &tauri::App) -> (String, String) {
|
||||
let candidates = vec![
|
||||
resource_dir.join("main.js"),
|
||||
resource_dir.join("_up_").join("main.js"),
|
||||
resource_dir.join("up").join("main.js"),
|
||||
];
|
||||
|
||||
for candidate in candidates {
|
||||
@@ -589,10 +598,23 @@ fn main() {
|
||||
.setup(|app| {
|
||||
debug_log("Tauri setup started");
|
||||
let app_data = app.path().app_data_dir().unwrap_or_default();
|
||||
let _app_data_str = clean_path(&app_data);
|
||||
|
||||
let vyla_files = if let Ok(appdata_env) = std::env::var("APPDATA") {
|
||||
std::path::PathBuf::from(appdata_env).join("vyla-home").join("vyla-home-files")
|
||||
std::path::PathBuf::from(appdata_env)
|
||||
.join("vyla-home")
|
||||
.join("vyla-home-files")
|
||||
} else if let Ok(home) = std::env::var("HOME") {
|
||||
#[cfg(target_os = "macos")]
|
||||
let base = std::path::PathBuf::from(&home)
|
||||
.join("Library")
|
||||
.join("Application Support");
|
||||
#[cfg(target_os = "linux")]
|
||||
let base = std::path::PathBuf::from(&home)
|
||||
.join(".local")
|
||||
.join("share");
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||
let base = app_data.clone();
|
||||
base.join("vyla-home").join("vyla-home-files")
|
||||
} else {
|
||||
app_data.join("vyla-home-files")
|
||||
};
|
||||
@@ -631,27 +653,31 @@ fn main() {
|
||||
.inner_size(1280.0, 800.0)
|
||||
.decorations(false)
|
||||
.resizable(true)
|
||||
.devtools(cfg!(debug_assertions))
|
||||
.devtools(true)
|
||||
.initialization_script("window.__VYLA_WINDOW_LABEL = 'main';")
|
||||
.initialization_script(LINK_HANDLER_SCRIPT)
|
||||
.build()?;
|
||||
|
||||
let (main_js, root_dir) = resolve_script_and_root(app);
|
||||
debug_log("Searching for node binary...");
|
||||
let node_bin = match find_node_binary(app) {
|
||||
Some(bin) => bin,
|
||||
Some(bin) => {
|
||||
debug_log(&format!("Found node binary: {}", bin));
|
||||
bin
|
||||
}
|
||||
None => {
|
||||
let _ = window.emit(
|
||||
"error",
|
||||
serde_json::json!({
|
||||
"message": "Node.js runtime not found. Please ensure Node.js is installed or bundled correctly."
|
||||
}),
|
||||
);
|
||||
debug_log("FATAL: No node binary found in bundle or PATH.");
|
||||
std::thread::sleep(std::time::Duration::from_millis(600));
|
||||
let _ = window.eval("document.getElementById('status-message').textContent='Error: Node runtime missing. Please reinstall.';");
|
||||
let _ = window.eval("var b=document.getElementById('debug-log-box');b.style.display='block';b.textContent='Node binary not found. bin/node missing from app bundle or not executable.';");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let vyla_files_str = clean_path(&vyla_files);
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(400));
|
||||
|
||||
let mut cmd = Command::new(&node_bin);
|
||||
cmd.arg(&main_js)
|
||||
.current_dir(&root_dir)
|
||||
@@ -847,12 +873,12 @@ fn main() {
|
||||
}
|
||||
Err(e) => {
|
||||
debug_log(&format!("Failed to spawn node: {}", e));
|
||||
let _ = window.emit(
|
||||
"error",
|
||||
serde_json::json!({
|
||||
"message": format!("Failed to launch backend runtime: {}", e)
|
||||
}),
|
||||
let emsg = format!("Failed to spawn node: {}", e);
|
||||
let js = format!(
|
||||
"document.getElementById('status-message').textContent='Spawn Error';var b=document.getElementById('debug-log-box');b.style.display='block';b.textContent={};",
|
||||
serde_json::to_string(&emsg).unwrap_or_default()
|
||||
);
|
||||
let _ = window.eval(&js);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Vyla Home",
|
||||
"version": "1.1.14",
|
||||
"version": "1.1.25",
|
||||
"identifier": "com.vyla.home",
|
||||
"build": {
|
||||
"frontendDist": "../ui"
|
||||
@@ -9,7 +9,7 @@
|
||||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
"security": {
|
||||
"csp": null
|
||||
"csp": "default-src 'self' http://localhost:4890 http://127.0.0.1:4890; script-src 'self' 'unsafe-inline' 'unsafe-eval' http://localhost:4890 http://127.0.0.1:4890 https://esm.sh; style-src 'self' 'unsafe-inline' http://localhost:4890 http://127.0.0.1:4890; img-src 'self' data: https: http://localhost:4890 http://127.0.0.1:4890; font-src 'self' data: http://localhost:4890 http://127.0.0.1:4890; connect-src 'self' http://localhost: http://127.0.0.1:"
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
@@ -22,6 +22,10 @@
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"macOS": {
|
||||
"exceptionDomain": "localhost",
|
||||
"infoPlist": "../Info.plist"
|
||||
},
|
||||
"windows": {
|
||||
"webviewInstallMode": {
|
||||
"type": "downloadBootstrapper"
|
||||
|
||||
275
ui/index.html
275
ui/index.html
@@ -271,61 +271,66 @@
|
||||
console.warn("OGL Shader background failed to load (offline):", err);
|
||||
}
|
||||
|
||||
if (!window.__OGL_LOADED__) {
|
||||
document.body.style.background = "radial-gradient(circle at 80% 20%, #1e1b4b 0%, #050505 70%)";
|
||||
} else {
|
||||
const { Renderer, Program, Triangle, Mesh } = window.__OGL_LOADED__;
|
||||
const rayContainer = document.getElementById("side-rays");
|
||||
const settings = {
|
||||
speed: 2.5,
|
||||
rayColor1: "#EAB308",
|
||||
rayColor2: "#96c8ff",
|
||||
intensity: 2,
|
||||
spread: 2,
|
||||
origin: "top-right",
|
||||
tilt: 0,
|
||||
saturation: 1.5,
|
||||
blend: 0.75,
|
||||
falloff: 1.6,
|
||||
opacity: 1
|
||||
};
|
||||
window.dispatchEvent(new Event('ogl-ready'));
|
||||
</script>
|
||||
|
||||
function hexToRgb(hex) {
|
||||
const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
if (!match) return [1, 1, 1];
|
||||
return [
|
||||
parseInt(match[1], 16) / 255,
|
||||
parseInt(match[2], 16) / 255,
|
||||
parseInt(match[3], 16) / 255
|
||||
];
|
||||
}
|
||||
<script>
|
||||
window.addEventListener('ogl-ready', () => {
|
||||
if (!window.__OGL_LOADED__) {
|
||||
document.body.style.background = "radial-gradient(circle at 80% 20%, #1e1b4b 0%, #050505 70%)";
|
||||
} else {
|
||||
const { Renderer, Program, Triangle, Mesh } = window.__OGL_LOADED__;
|
||||
const rayContainer = document.getElementById("side-rays");
|
||||
const settings = {
|
||||
speed: 2.5,
|
||||
rayColor1: "#EAB308",
|
||||
rayColor2: "#96c8ff",
|
||||
intensity: 2,
|
||||
spread: 2,
|
||||
origin: "top-right",
|
||||
tilt: 0,
|
||||
saturation: 1.5,
|
||||
blend: 0.75,
|
||||
falloff: 1.6,
|
||||
opacity: 1
|
||||
};
|
||||
|
||||
function originToFlip(origin) {
|
||||
switch (origin) {
|
||||
case "top-left": return [1, 0];
|
||||
case "bottom-right": return [0, 1];
|
||||
case "bottom-left": return [1, 1];
|
||||
default: return [0, 0];
|
||||
function hexToRgb(hex) {
|
||||
const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
if (!match) return [1, 1, 1];
|
||||
return [
|
||||
parseInt(match[1], 16) / 255,
|
||||
parseInt(match[2], 16) / 255,
|
||||
parseInt(match[3], 16) / 255
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
const renderer = new Renderer({
|
||||
dpr: Math.min(window.devicePixelRatio, 2),
|
||||
alpha: true
|
||||
});
|
||||
const gl = renderer.gl;
|
||||
gl.canvas.style.width = "100%";
|
||||
gl.canvas.style.height = "100%";
|
||||
rayContainer.appendChild(gl.canvas);
|
||||
function originToFlip(origin) {
|
||||
switch (origin) {
|
||||
case "top-left": return [1, 0];
|
||||
case "bottom-right": return [0, 1];
|
||||
case "bottom-left": return [1, 1];
|
||||
default: return [0, 0];
|
||||
}
|
||||
}
|
||||
|
||||
const vertexShader = `
|
||||
const renderer = new Renderer({
|
||||
dpr: Math.min(window.devicePixelRatio, 2),
|
||||
alpha: true
|
||||
});
|
||||
const gl = renderer.gl;
|
||||
gl.canvas.style.width = "100%";
|
||||
gl.canvas.style.height = "100%";
|
||||
rayContainer.appendChild(gl.canvas);
|
||||
|
||||
const vertexShader = `
|
||||
attribute vec2 position;
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
const fragmentShader = `
|
||||
const fragmentShader = `
|
||||
precision highp float;
|
||||
uniform float iTime;
|
||||
uniform vec2 iResolution;
|
||||
@@ -386,77 +391,77 @@ void main() {
|
||||
}
|
||||
`;
|
||||
|
||||
const [flipX, flipY] = originToFlip(settings.origin);
|
||||
const uniforms = {
|
||||
iTime: { value: 0 },
|
||||
iResolution: { value: [1, 1] },
|
||||
iSpeed: { value: settings.speed },
|
||||
iRayColor1: { value: hexToRgb(settings.rayColor1) },
|
||||
iRayColor2: { value: hexToRgb(settings.rayColor2) },
|
||||
iIntensity: { value: settings.intensity },
|
||||
iSpread: { value: settings.spread },
|
||||
iFlipX: { value: flipX },
|
||||
iFlipY: { value: flipY },
|
||||
iTilt: { value: settings.tilt },
|
||||
iSaturation: { value: settings.saturation },
|
||||
iBlend: { value: settings.blend },
|
||||
iFalloff: { value: settings.falloff },
|
||||
iOpacity: { value: settings.opacity }
|
||||
};
|
||||
const [flipX, flipY] = originToFlip(settings.origin);
|
||||
const uniforms = {
|
||||
iTime: { value: 0 },
|
||||
iResolution: { value: [1, 1] },
|
||||
iSpeed: { value: settings.speed },
|
||||
iRayColor1: { value: hexToRgb(settings.rayColor1) },
|
||||
iRayColor2: { value: hexToRgb(settings.rayColor2) },
|
||||
iIntensity: { value: settings.intensity },
|
||||
iSpread: { value: settings.spread },
|
||||
iFlipX: { value: flipX },
|
||||
iFlipY: { value: flipY },
|
||||
iTilt: { value: settings.tilt },
|
||||
iSaturation: { value: settings.saturation },
|
||||
iBlend: { value: settings.blend },
|
||||
iFalloff: { value: settings.falloff },
|
||||
iOpacity: { value: settings.opacity }
|
||||
};
|
||||
|
||||
const geometry = new Triangle(gl);
|
||||
const program = new Program(gl, { vertex: vertexShader, fragment: fragmentShader, uniforms });
|
||||
const mesh = new Mesh(gl, { geometry, program });
|
||||
const geometry = new Triangle(gl);
|
||||
const program = new Program(gl, { vertex: vertexShader, fragment: fragmentShader, uniforms });
|
||||
const mesh = new Mesh(gl, { geometry, program });
|
||||
|
||||
function resize() {
|
||||
const width = rayContainer.clientWidth;
|
||||
const height = rayContainer.clientHeight;
|
||||
renderer.dpr = Math.min(window.devicePixelRatio, 2);
|
||||
renderer.setSize(width, height);
|
||||
uniforms.iResolution.value = [width * renderer.dpr, height * renderer.dpr];
|
||||
}
|
||||
function resize() {
|
||||
const width = rayContainer.clientWidth;
|
||||
const height = rayContainer.clientHeight;
|
||||
renderer.dpr = Math.min(window.devicePixelRatio, 2);
|
||||
renderer.setSize(width, height);
|
||||
uniforms.iResolution.value = [width * renderer.dpr, height * renderer.dpr];
|
||||
}
|
||||
|
||||
window.addEventListener("resize", resize);
|
||||
resize();
|
||||
window.addEventListener("resize", resize);
|
||||
resize();
|
||||
|
||||
function animate(time) {
|
||||
uniforms.iTime.value = time * 0.001;
|
||||
renderer.render({ scene: mesh });
|
||||
function animate(time) {
|
||||
uniforms.iTime.value = time * 0.001;
|
||||
renderer.render({ scene: mesh });
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
function initLiquidButtons() {
|
||||
const borderWidth = 0.16;
|
||||
const brightness = 35;
|
||||
const opacity = 0.55;
|
||||
const blur = 4;
|
||||
const displace = 1.2;
|
||||
const borderRadius = 9999;
|
||||
const distortionScale = -380;
|
||||
const redOffset = -25;
|
||||
const greenOffset = 0;
|
||||
const blueOffset = 25;
|
||||
const xChannel = "R";
|
||||
const yChannel = "G";
|
||||
const mixBlendMode = "screen";
|
||||
function initLiquidButtons() {
|
||||
const borderWidth = 0.16;
|
||||
const brightness = 35;
|
||||
const opacity = 0.55;
|
||||
const blur = 4;
|
||||
const displace = 1.2;
|
||||
const borderRadius = 9999;
|
||||
const distortionScale = -380;
|
||||
const redOffset = -25;
|
||||
const greenOffset = 0;
|
||||
const blueOffset = 25;
|
||||
const xChannel = "R";
|
||||
const yChannel = "G";
|
||||
const mixBlendMode = "screen";
|
||||
|
||||
document.querySelectorAll(".liquid-glass-btn").forEach((btn, index) => {
|
||||
const filterId = `glass-filter-${index + 1}`;
|
||||
btn.style.setProperty("--filter-id", `url(#${filterId})`);
|
||||
document.querySelectorAll(".liquid-glass-btn").forEach((btn, index) => {
|
||||
const filterId = `glass-filter-${index + 1}`;
|
||||
btn.style.setProperty("--filter-id", `url(#${filterId})`);
|
||||
|
||||
const feImage = btn.querySelector(".fe-image");
|
||||
const redChannel = btn.querySelector(".redchannel");
|
||||
const greenChannel = btn.querySelector(".greenchannel");
|
||||
const blueChannel = btn.querySelector(".bluechannel");
|
||||
const gaussianBlur = btn.querySelector(".gaussianBlur");
|
||||
const feImage = btn.querySelector(".fe-image");
|
||||
const redChannel = btn.querySelector(".redchannel");
|
||||
const greenChannel = btn.querySelector(".greenchannel");
|
||||
const blueChannel = btn.querySelector(".bluechannel");
|
||||
const gaussianBlur = btn.querySelector(".gaussianBlur");
|
||||
|
||||
function generateDisplacementMap() {
|
||||
const rect = btn.getBoundingClientRect();
|
||||
const actualWidth = rect.width || 140;
|
||||
const actualHeight = rect.height || 48;
|
||||
function generateDisplacementMap() {
|
||||
const rect = btn.getBoundingClientRect();
|
||||
const actualWidth = rect.width || 140;
|
||||
const actualHeight = rect.height || 48;
|
||||
|
||||
const svgContent = `
|
||||
const svgContent = `
|
||||
<svg viewBox="0 0 ${actualWidth} ${actualHeight}" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="red-grad-${index}" x1="100%" y1="0%" x2="0%" y2="0%">
|
||||
@@ -473,32 +478,33 @@ void main() {
|
||||
<rect width="${actualWidth}" height="${actualHeight}" rx="${borderRadius}" fill="url(#blue-grad-${index})" style="mix-blend-mode:${mixBlendMode}"/>
|
||||
</svg>
|
||||
`;
|
||||
return "data:image/svg+xml," + encodeURIComponent(svgContent);
|
||||
}
|
||||
return "data:image/svg+xml," + encodeURIComponent(svgContent);
|
||||
}
|
||||
|
||||
function update() {
|
||||
feImage.setAttribute("href", generateDisplacementMap());
|
||||
redChannel.setAttribute("scale", distortionScale + redOffset);
|
||||
greenChannel.setAttribute("scale", distortionScale + greenOffset);
|
||||
blueChannel.setAttribute("scale", distortionScale + blueOffset);
|
||||
[redChannel, greenChannel, blueChannel].forEach((ch) => {
|
||||
ch.setAttribute("xChannelSelector", xChannel);
|
||||
ch.setAttribute("yChannelSelector", yChannel);
|
||||
});
|
||||
gaussianBlur.setAttribute("stdDeviation", displace);
|
||||
}
|
||||
function update() {
|
||||
feImage.setAttribute("href", generateDisplacementMap());
|
||||
redChannel.setAttribute("scale", distortionScale + redOffset);
|
||||
greenChannel.setAttribute("scale", distortionScale + greenOffset);
|
||||
blueChannel.setAttribute("scale", distortionScale + blueOffset);
|
||||
[redChannel, greenChannel, blueChannel].forEach((ch) => {
|
||||
ch.setAttribute("xChannelSelector", xChannel);
|
||||
ch.setAttribute("yChannelSelector", yChannel);
|
||||
});
|
||||
gaussianBlur.setAttribute("stdDeviation", displace);
|
||||
}
|
||||
|
||||
update();
|
||||
btn.classList.remove("glass-surface--fallback");
|
||||
btn.classList.add("glass-surface--svg");
|
||||
update();
|
||||
btn.classList.remove("glass-surface--fallback");
|
||||
btn.classList.add("glass-surface--svg");
|
||||
|
||||
const observer = new ResizeObserver(() => setTimeout(update, 0));
|
||||
observer.observe(btn);
|
||||
});
|
||||
const observer = new ResizeObserver(() => setTimeout(update, 0));
|
||||
observer.observe(btn);
|
||||
});
|
||||
}
|
||||
|
||||
initLiquidButtons();
|
||||
}
|
||||
|
||||
initLiquidButtons();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
@@ -535,8 +541,17 @@ void main() {
|
||||
}
|
||||
|
||||
async function initTauriEvents() {
|
||||
const eventApi = window.__TAURI__?.event || window.__TAURI_INTERNALS__;
|
||||
if (!eventApi || typeof eventApi.listen !== 'function') {
|
||||
let eventApi = null;
|
||||
|
||||
if (window.__TAURI__?.event && typeof window.__TAURI__.event.listen === 'function') {
|
||||
eventApi = window.__TAURI__.event;
|
||||
} else if (window.__TAURI_INTERNALS__ && typeof window.__TAURI_INTERNALS__.listen === 'function') {
|
||||
eventApi = window.__TAURI_INTERNALS__;
|
||||
} else if (window.__TAURI__ && typeof window.__TAURI__.listen === 'function') {
|
||||
eventApi = window.__TAURI__;
|
||||
}
|
||||
|
||||
if (!eventApi) {
|
||||
setTimeout(initTauriEvents, 50);
|
||||
return;
|
||||
}
|
||||
@@ -572,7 +587,7 @@ void main() {
|
||||
const data = e.payload || e;
|
||||
if (data && data.url) {
|
||||
setStatus("Launching...");
|
||||
window.location.href = data.url;
|
||||
window.location.replace(data.url);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user