Initial commit
# Conflicts: # README.md
This commit is contained in:
256
layout2_plan.md
Normal file
256
layout2_plan.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# Beautify “Connect to Device” Popup (Tauri + HTML)
|
||||
|
||||
## Goal
|
||||
|
||||
Redesign the **Connect to Device** popup/modal to match the app’s **glassmorphism + neon purple** style:
|
||||
|
||||
* Frosted glass modal
|
||||
* Blurred/dimmed overlay background
|
||||
* Clean device list with hover + selected states
|
||||
* Premium rounded corners and soft glow
|
||||
* Works smoothly inside **Tauri WebView** (desktop)
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
### Functional
|
||||
|
||||
* Modal opens/closes via existing app logic (do not change behavior).
|
||||
* Device list supports:
|
||||
|
||||
* Hover highlight
|
||||
* Single selected device (one at a time)
|
||||
* Click selects device (and triggers existing handler)
|
||||
* “Cancel” button closes modal (existing handler).
|
||||
* Include “This Computer (Local Playback)” option at top.
|
||||
|
||||
### Visual
|
||||
|
||||
* Overlay blur + dark tint behind modal.
|
||||
* Modal background: semi-transparent glass with blur.
|
||||
* No harsh borders; use subtle border + soft shadow.
|
||||
* Selected device: gradient accent + glow.
|
||||
* Smooth animation on open (scale + fade).
|
||||
* Desktop-friendly sizing (320–420px wide).
|
||||
|
||||
### Tauri Safety / Performance
|
||||
|
||||
* Keep CSS lightweight.
|
||||
* Avoid heavy SVG masks or expensive filters beyond `backdrop-filter: blur(...)`.
|
||||
* Ensure modal area is `-webkit-app-region: no-drag` if you use draggable window headers.
|
||||
|
||||
---
|
||||
|
||||
## Target Structure
|
||||
|
||||
### HTML (keep semantic + simple)
|
||||
|
||||
Use or adapt this structure in the renderer HTML:
|
||||
|
||||
```html
|
||||
<div id="deviceOverlay" class="overlay hidden" aria-hidden="true">
|
||||
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="deviceTitle">
|
||||
<h2 id="deviceTitle">Connect to Device</h2>
|
||||
|
||||
<ul id="deviceList" class="device-list">
|
||||
<!-- Render device items here -->
|
||||
<!-- Example item:
|
||||
<li class="device local selected" data-device="local">
|
||||
<div class="device-main">This Computer</div>
|
||||
<div class="device-sub">Local Playback</div>
|
||||
</li>
|
||||
-->
|
||||
</ul>
|
||||
|
||||
<button id="deviceCancelBtn" class="btn cancel" type="button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
* Use `hidden` class to toggle visibility.
|
||||
* Each `<li>` must have `data-device="<name-or-id>"` for click handling.
|
||||
* Selected item uses `.selected`.
|
||||
|
||||
---
|
||||
|
||||
## CSS (Glassmorphism Modal)
|
||||
|
||||
Add/merge this CSS into your stylesheet:
|
||||
|
||||
```css
|
||||
/* Overlay */
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(20, 10, 35, 0.45);
|
||||
backdrop-filter: blur(14px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.hidden { display: none !important; }
|
||||
|
||||
/* Modal */
|
||||
.modal {
|
||||
width: min(420px, calc(100vw - 48px));
|
||||
padding: 22px;
|
||||
border-radius: 22px;
|
||||
background: rgba(30, 30, 40, 0.82);
|
||||
border: 1px solid rgba(255,255,255,0.12);
|
||||
box-shadow: 0 30px 80px rgba(0,0,0,0.6);
|
||||
color: #fff;
|
||||
animation: pop 0.22s ease;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
@keyframes pop {
|
||||
from { transform: scale(0.94); opacity: 0; }
|
||||
to { transform: scale(1); opacity: 1; }
|
||||
}
|
||||
|
||||
.modal h2 {
|
||||
margin: 0 0 14px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* Device list */
|
||||
.device-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 18px;
|
||||
max-height: 360px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Device row */
|
||||
.device {
|
||||
padding: 12px 14px;
|
||||
border-radius: 14px;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
background: rgba(255,255,255,0.05);
|
||||
transition: transform 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.device:hover {
|
||||
background: rgba(255,255,255,0.10);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.device .device-main {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.device .device-sub {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Selected device */
|
||||
.device.selected {
|
||||
background: linear-gradient(135deg, #c77dff, #8b5cf6);
|
||||
box-shadow: 0 0 18px rgba(199,125,255,0.65);
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.device.selected .device-sub {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* Optional: disabled group devices */
|
||||
.device.disabled {
|
||||
opacity: 0.45;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Cancel button */
|
||||
.btn.cancel {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border-radius: 999px;
|
||||
border: none;
|
||||
background: #d16b7d;
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.btn.cancel:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## JavaScript Behavior (Minimal)
|
||||
|
||||
### Selection logic
|
||||
|
||||
* When a device row is clicked:
|
||||
|
||||
1. Remove `.selected` from all device `<li>`
|
||||
2. Add `.selected` to clicked `<li>`
|
||||
3. Call existing “connect/cast to device” handler with `data-device`
|
||||
|
||||
Pseudo-code (adapt to existing app code):
|
||||
|
||||
```js
|
||||
deviceList.addEventListener("click", (e) => {
|
||||
const item = e.target.closest(".device");
|
||||
if (!item) return;
|
||||
|
||||
deviceList.querySelectorAll(".device.selected")
|
||||
.forEach(el => el.classList.remove("selected"));
|
||||
|
||||
item.classList.add("selected");
|
||||
|
||||
const deviceName = item.dataset.device;
|
||||
// call existing connect logic:
|
||||
// connectToDevice(deviceName);
|
||||
});
|
||||
```
|
||||
|
||||
### Close modal
|
||||
|
||||
* Cancel button closes modal (existing function):
|
||||
|
||||
```js
|
||||
deviceCancelBtn.addEventListener("click", closeDeviceModal);
|
||||
```
|
||||
|
||||
### Optional: close on overlay click
|
||||
|
||||
* Only if app UX allows:
|
||||
|
||||
```js
|
||||
deviceOverlay.addEventListener("click", (e) => {
|
||||
if (e.target === deviceOverlay) closeDeviceModal();
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
* Popup visually matches glassmorphism theme.
|
||||
* Overlay dims and blurs background.
|
||||
* Device list has hover + selected glow.
|
||||
* Exactly one device can be selected.
|
||||
* Cancel closes modal.
|
||||
* Runs smoothly in Tauri WebView without lag.
|
||||
|
||||
---
|
||||
|
||||
## Notes / Future Enhancements (Optional)
|
||||
|
||||
* Mark “Speaker Groups” as `.disabled` if casting library can’t support them.
|
||||
* Add small icons per device type (local vs cast).
|
||||
* Remember last selected device and preselect it on open.
|
||||
Reference in New Issue
Block a user