Skip to content

Commit 2a16dbf

Browse files
committed
Add WebView2 plugin with JavaScript bridge to Rainmeter API and a demo skin.
1 parent 6e8bb1e commit 2a16dbf

File tree

4 files changed

+841
-1
lines changed

4 files changed

+841
-1
lines changed
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Rainmeter API Bridge Demo</title>
7+
<style>
8+
* {
9+
margin: 0;
10+
padding: 0;
11+
box-sizing: border-box;
12+
}
13+
14+
body {
15+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17+
color: white;
18+
padding: 30px;
19+
min-height: 100vh;
20+
}
21+
22+
.container {
23+
max-width: 1000px;
24+
margin: 0 auto;
25+
}
26+
27+
h1 {
28+
font-size: 2.5em;
29+
margin-bottom: 10px;
30+
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
31+
}
32+
33+
.subtitle {
34+
font-size: 1.1em;
35+
opacity: 0.9;
36+
margin-bottom: 30px;
37+
}
38+
39+
.section {
40+
background: rgba(255, 255, 255, 0.1);
41+
backdrop-filter: blur(10px);
42+
border-radius: 15px;
43+
padding: 25px;
44+
margin-bottom: 20px;
45+
border: 1px solid rgba(255, 255, 255, 0.2);
46+
}
47+
48+
h2 {
49+
font-size: 1.5em;
50+
margin-bottom: 15px;
51+
border-bottom: 2px solid rgba(255, 255, 255, 0.3);
52+
padding-bottom: 10px;
53+
}
54+
55+
.button-grid {
56+
display: grid;
57+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
58+
gap: 15px;
59+
margin-top: 15px;
60+
}
61+
62+
button {
63+
background: rgba(255, 255, 255, 0.3);
64+
border: 2px solid white;
65+
color: white;
66+
padding: 12px 20px;
67+
font-size: 1em;
68+
border-radius: 8px;
69+
cursor: pointer;
70+
transition: all 0.3s ease;
71+
font-weight: 600;
72+
}
73+
74+
button:hover {
75+
background: white;
76+
color: #667eea;
77+
transform: translateY(-2px);
78+
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
79+
}
80+
81+
button:active {
82+
transform: translateY(0);
83+
}
84+
85+
.output {
86+
background: rgba(0, 0, 0, 0.3);
87+
border-radius: 8px;
88+
padding: 15px;
89+
margin-top: 15px;
90+
font-family: 'Courier New', monospace;
91+
font-size: 0.9em;
92+
min-height: 50px;
93+
max-height: 200px;
94+
overflow-y: auto;
95+
white-space: pre-wrap;
96+
word-wrap: break-word;
97+
}
98+
99+
.info-grid {
100+
display: grid;
101+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
102+
gap: 15px;
103+
margin-top: 15px;
104+
}
105+
106+
.info-item {
107+
background: rgba(0, 0, 0, 0.2);
108+
padding: 15px;
109+
border-radius: 8px;
110+
border-left: 4px solid white;
111+
}
112+
113+
.info-label {
114+
font-size: 0.85em;
115+
opacity: 0.8;
116+
margin-bottom: 5px;
117+
}
118+
119+
.info-value {
120+
font-size: 1.1em;
121+
font-weight: 600;
122+
word-break: break-all;
123+
}
124+
125+
/* Make Settings File card full width */
126+
.info-item:last-child {
127+
grid-column: 1 / -1;
128+
}
129+
130+
.info-item:last-child .info-value {
131+
font-size: 0.95em;
132+
font-family: 'Courier New', monospace;
133+
}
134+
135+
.success {
136+
color: #4ade80;
137+
}
138+
139+
.error {
140+
color: #f87171;
141+
}
142+
</style>
143+
</head>
144+
<body>
145+
<div class="container">
146+
<h1>Rainmeter API Bridge Demo</h1>
147+
<p class="subtitle">Test the JavaScript bridge to Rainmeter API</p>
148+
149+
<!-- Skin Information -->
150+
<div class="section">
151+
<h2>Skin Information</h2>
152+
<div class="info-grid" id="skinInfo">
153+
<div class="info-item">
154+
<div class="info-label">Measure Name</div>
155+
<div class="info-value" id="measureName">Loading...</div>
156+
</div>
157+
<div class="info-item">
158+
<div class="info-label">Skin Name</div>
159+
<div class="info-value" id="skinName">Loading...</div>
160+
</div>
161+
<div class="info-item">
162+
<div class="info-label">Window Handle</div>
163+
<div class="info-value" id="windowHandle">Loading...</div>
164+
</div>
165+
<div class="info-item">
166+
<div class="info-label">Settings File</div>
167+
<div class="info-value" id="settingsFile">Loading...</div>
168+
</div>
169+
</div>
170+
</div>
171+
172+
<!-- Read Options -->
173+
<div class="section">
174+
<h2>Read Options</h2>
175+
<div class="button-grid">
176+
<button onclick="testReadString()">Read String</button>
177+
<button onclick="testReadInt()">Read Int</button>
178+
<button onclick="testReadDouble()">Read Double</button>
179+
<button onclick="testReadPath()">Read Path</button>
180+
</div>
181+
<div class="output" id="readOutput">Click buttons to test reading options...</div>
182+
</div>
183+
184+
<!-- Execute Commands -->
185+
<div class="section">
186+
<h2>Execute Commands</h2>
187+
<div class="button-grid">
188+
<button onclick="testExecute()">Execute Bang</button>
189+
<button onclick="testLog()">Log Message</button>
190+
<button onclick="testReplaceVars()">Replace Variables</button>
191+
<button onclick="testPathToAbsolute()">Path to Absolute</button>
192+
</div>
193+
<div class="output" id="executeOutput">Click buttons to test commands...</div>
194+
</div>
195+
196+
<!-- Interactive Test -->
197+
<div class="section">
198+
<h2>Interactive Test</h2>
199+
<p style="margin-bottom: 15px;">Enter a Rainmeter option name to read:</p>
200+
<input type="text" id="optionInput" placeholder="e.g., Width" style="width: 100%; padding: 10px; border-radius: 5px; border: none; margin-bottom: 10px;">
201+
<button onclick="testCustomRead()" style="width: 100%;">Read Option</button>
202+
<div class="output" id="customOutput">Results will appear here...</div>
203+
</div>
204+
</div>
205+
206+
<script>
207+
// Load skin information on page load
208+
window.addEventListener('DOMContentLoaded', async function() {
209+
try {
210+
const measureName = await rm.MeasureName;
211+
const skinName = await rm.SkinName;
212+
const windowHandle = await rm.SkinWindowHandle;
213+
const settingsFile = await rm.SettingsFile;
214+
215+
document.getElementById('measureName').textContent = measureName || 'N/A';
216+
document.getElementById('skinName').textContent = skinName || 'N/A';
217+
document.getElementById('windowHandle').textContent = windowHandle || 'N/A';
218+
document.getElementById('settingsFile').textContent = settingsFile || 'N/A';
219+
220+
rm.Log('Rainmeter API Demo page loaded', 'Notice');
221+
} catch (error) {
222+
console.error('Failed to load skin info:', error);
223+
}
224+
});
225+
226+
// Test ReadString
227+
async function testReadString() {
228+
const output = document.getElementById('readOutput');
229+
try {
230+
output.innerHTML = 'Reading Url option...';
231+
const value = await rm.ReadString('Url', 'default');
232+
output.innerHTML = `<span class="success">✓ ReadString('Url'):</span>\n${value}`;
233+
} catch (error) {
234+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
235+
}
236+
}
237+
238+
// Test ReadInt
239+
async function testReadInt() {
240+
const output = document.getElementById('readOutput');
241+
try {
242+
output.innerHTML = 'Reading Width option...';
243+
const value = await rm.ReadInt('Width', 800);
244+
output.innerHTML = `<span class="success">✓ ReadInt('Width'):</span>\n${value}`;
245+
} catch (error) {
246+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
247+
}
248+
}
249+
250+
// Test ReadDouble
251+
async function testReadDouble() {
252+
const output = document.getElementById('readOutput');
253+
try {
254+
output.innerHTML = 'Reading Height option...';
255+
const value = await rm.ReadDouble('Height', 600.0);
256+
output.innerHTML = `<span class="success">✓ ReadDouble('Height'):</span>\n${value}`;
257+
} catch (error) {
258+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
259+
}
260+
}
261+
262+
// Test ReadPath
263+
async function testReadPath() {
264+
const output = document.getElementById('readOutput');
265+
try {
266+
output.innerHTML = 'Reading Url as path...';
267+
const value = await rm.ReadPath('Url', '');
268+
output.innerHTML = `<span class="success">✓ ReadPath('Url'):</span>\n${value}`;
269+
} catch (error) {
270+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
271+
}
272+
}
273+
274+
// Test Execute
275+
function testExecute() {
276+
const output = document.getElementById('executeOutput');
277+
try {
278+
output.innerHTML = 'Executing bang...';
279+
rm.Execute('[!Log "Hello from JavaScript!" Notice]');
280+
output.innerHTML = `<span class="success">✓ Execute:</span>\nExecuted: [!Log "Hello from JavaScript!" Notice]`;
281+
} catch (error) {
282+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
283+
}
284+
}
285+
286+
// Test Log
287+
function testLog() {
288+
const output = document.getElementById('executeOutput');
289+
try {
290+
output.innerHTML = 'Logging message...';
291+
rm.Log('Test message from JavaScript', 'Notice');
292+
output.innerHTML = `<span class="success">✓ Log:</span>\nLogged: "Test message from JavaScript"`;
293+
} catch (error) {
294+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
295+
}
296+
}
297+
298+
// Test ReplaceVariables
299+
async function testReplaceVars() {
300+
const output = document.getElementById('executeOutput');
301+
try {
302+
output.innerHTML = 'Replacing variables...';
303+
const value = await rm.ReplaceVariables('#CURRENTCONFIG#');
304+
output.innerHTML = `<span class="success">✓ ReplaceVariables('#CURRENTCONFIG#'):</span>\n${value}`;
305+
} catch (error) {
306+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
307+
}
308+
}
309+
310+
// Test PathToAbsolute
311+
async function testPathToAbsolute() {
312+
const output = document.getElementById('executeOutput');
313+
try {
314+
output.innerHTML = 'Converting path...';
315+
const value = await rm.PathToAbsolute('#@#example.html');
316+
output.innerHTML = `<span class="success">✓ PathToAbsolute('#@#example.html'):</span>\n${value}`;
317+
} catch (error) {
318+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
319+
}
320+
}
321+
322+
// Test custom read
323+
async function testCustomRead() {
324+
const output = document.getElementById('customOutput');
325+
const option = document.getElementById('optionInput').value;
326+
327+
if (!option) {
328+
output.innerHTML = '<span class="error">Please enter an option name</span>';
329+
return;
330+
}
331+
332+
try {
333+
output.innerHTML = `Reading option "${option}"...`;
334+
const value = await rm.ReadString(option, 'not found');
335+
output.innerHTML = `<span class="success">✓ ReadString('${option}'):</span>\n${value}`;
336+
} catch (error) {
337+
output.innerHTML = `<span class="error">✗ Error:</span> ${error.message}`;
338+
}
339+
}
340+
</script>
341+
</body>
342+
</html>

0 commit comments

Comments
 (0)