Initial commit
This commit is contained in:
255
com.pdma.notion-timer.sdPlugin/ui/property-inspector.html
Normal file
255
com.pdma.notion-timer.sdPlugin/ui/property-inspector.html
Normal file
@@ -0,0 +1,255 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
font-size: 13px;
|
||||
color: #ccc;
|
||||
background: transparent;
|
||||
padding: 8px;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: #888;
|
||||
margin: 14px 0 8px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.section-title:first-child { margin-top: 0; }
|
||||
.section-title .arrow { font-size: 9px; }
|
||||
.collapsible { overflow: hidden; }
|
||||
.collapsible.collapsed { display: none; }
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
label {
|
||||
width: 90px;
|
||||
flex-shrink: 0;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
select, input[type="text"], input[type="password"] {
|
||||
flex: 1;
|
||||
background: #1a1a1a;
|
||||
border: 1px solid #444;
|
||||
border-radius: 4px;
|
||||
color: #eee;
|
||||
padding: 5px 8px;
|
||||
font-size: 12px;
|
||||
outline: none;
|
||||
}
|
||||
.hint {
|
||||
font-size: 11px;
|
||||
color: #555;
|
||||
margin-top: -4px;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 98px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.divider {
|
||||
border: none;
|
||||
border-top: 1px solid #333;
|
||||
margin: 10px 0;
|
||||
}
|
||||
#statusText {
|
||||
font-size: 11px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
padding-top: 4px;
|
||||
min-height: 16px;
|
||||
}
|
||||
#statusText.running { color: #4caf50; }
|
||||
#statusText.error { color: #e57373; }
|
||||
#credStatus {
|
||||
font-size: 11px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
padding-top: 2px;
|
||||
margin-bottom: 6px;
|
||||
min-height: 14px;
|
||||
}
|
||||
#credStatus.ok { color: #4caf50; }
|
||||
#credStatus.error { color: #e57373; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Credentials (collapsed by default once configured) -->
|
||||
<p class="section-title" id="credToggle">
|
||||
<span class="arrow" id="credArrow">▶</span> Notion Credentials
|
||||
</p>
|
||||
<div class="collapsible collapsed" id="credSection">
|
||||
<div class="row">
|
||||
<label>API Token</label>
|
||||
<input type="password" id="notionToken" placeholder="ntn_…">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>User ID</label>
|
||||
<input type="text" id="userId" placeholder="Your Notion user UUID">
|
||||
</div>
|
||||
<p class="hint">Shared across all buttons. Enter once per device.</p>
|
||||
<p id="credStatus"></p>
|
||||
<hr class="divider">
|
||||
</div>
|
||||
|
||||
<!-- Per-button settings -->
|
||||
<p class="section-title" style="cursor:default;">
|
||||
<span class="arrow" style="visibility:hidden;">▶</span> Button
|
||||
</p>
|
||||
<div class="row">
|
||||
<label>Project</label>
|
||||
<select id="projectSelect">
|
||||
<option value="">Loading projects…</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<p id="statusText"></p>
|
||||
|
||||
<script src="libs/constants.js"></script>
|
||||
<script src="libs/prototypes.js"></script>
|
||||
<script src="libs/timers.js"></script>
|
||||
<script src="libs/utils.js"></script>
|
||||
<script src="libs/events.js"></script>
|
||||
<script src="libs/api.js"></script>
|
||||
<script src="libs/property-inspector.js"></script>
|
||||
|
||||
<script>
|
||||
var ACTION_UUID = "com.pdma.notion-timer.toggle";
|
||||
var currentSettings = {};
|
||||
var credSaveTimer = null;
|
||||
var credConfigured = false;
|
||||
|
||||
function setStatus(msg, cls) {
|
||||
var el = document.getElementById("statusText");
|
||||
el.textContent = msg;
|
||||
el.className = cls || "";
|
||||
}
|
||||
|
||||
function setCredStatus(msg, cls) {
|
||||
var el = document.getElementById("credStatus");
|
||||
el.textContent = msg;
|
||||
el.className = cls || "";
|
||||
}
|
||||
|
||||
// Collapsible credentials section
|
||||
document.getElementById("credToggle").addEventListener("click", function() {
|
||||
var section = document.getElementById("credSection");
|
||||
var arrow = document.getElementById("credArrow");
|
||||
if (section.classList.contains("collapsed")) {
|
||||
section.classList.remove("collapsed");
|
||||
arrow.textContent = "▼";
|
||||
} else {
|
||||
section.classList.add("collapsed");
|
||||
arrow.textContent = "▶";
|
||||
}
|
||||
});
|
||||
|
||||
function saveCredentials() {
|
||||
var creds = {
|
||||
notionToken: document.getElementById("notionToken").value.trim(),
|
||||
userId: document.getElementById("userId").value.trim(),
|
||||
};
|
||||
$PI.setGlobalSettings(creds);
|
||||
setCredStatus("Credentials saved.", "ok");
|
||||
}
|
||||
|
||||
function scheduleCredSave() {
|
||||
clearTimeout(credSaveTimer);
|
||||
credSaveTimer = setTimeout(saveCredentials, 600);
|
||||
}
|
||||
|
||||
function save() {
|
||||
var sel = document.getElementById("projectSelect");
|
||||
var opt = sel.options[sel.selectedIndex];
|
||||
currentSettings.projectId = sel.value;
|
||||
currentSettings.projectName = sel.value ? opt.textContent.trim() : "";
|
||||
$PI.setSettings(currentSettings);
|
||||
$PI.sendToPlugin({ event: "saveSettings", settings: currentSettings });
|
||||
setStatus(currentSettings.projectName ? "Saved: " + currentSettings.projectName : "", "");
|
||||
}
|
||||
|
||||
function populateProjects(projects) {
|
||||
var sel = document.getElementById("projectSelect");
|
||||
sel.innerHTML = '<option value="">— Select project —</option>';
|
||||
projects.forEach(function(p) {
|
||||
var opt = document.createElement("option");
|
||||
opt.value = p.id;
|
||||
opt.textContent = p.name;
|
||||
if (currentSettings.projectId === p.id) opt.selected = true;
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
if (!currentSettings.projectId) {
|
||||
setStatus("Select a project to get started.", "");
|
||||
} else if (currentSettings.activeEntryId) {
|
||||
setStatus("⏱ Timer running", "running");
|
||||
} else {
|
||||
setStatus("", "");
|
||||
}
|
||||
}
|
||||
|
||||
$PI.onConnected(function(jsn) {
|
||||
currentSettings = jsn.actionInfo.payload.settings || {};
|
||||
$PI.getSettings();
|
||||
$PI.getGlobalSettings();
|
||||
|
||||
document.getElementById("projectSelect").addEventListener("change", save);
|
||||
["notionToken", "userId"].forEach(function(id) {
|
||||
document.getElementById(id).addEventListener("input", scheduleCredSave);
|
||||
});
|
||||
});
|
||||
|
||||
$PI.onDidReceiveGlobalSettings(function(jsn) {
|
||||
var s = jsn.payload.settings || {};
|
||||
document.getElementById("notionToken").value = s.notionToken || "";
|
||||
document.getElementById("userId").value = s.userId || "";
|
||||
|
||||
credConfigured = !!(s.notionToken && s.userId);
|
||||
|
||||
// Auto-collapse if already configured, expand if not
|
||||
var section = document.getElementById("credSection");
|
||||
var arrow = document.getElementById("credArrow");
|
||||
if (credConfigured) {
|
||||
section.classList.add("collapsed");
|
||||
arrow.textContent = "▶";
|
||||
} else {
|
||||
section.classList.remove("collapsed");
|
||||
arrow.textContent = "▼";
|
||||
}
|
||||
});
|
||||
|
||||
$PI.onDidReceiveSettings(ACTION_UUID, function(jsn) {
|
||||
currentSettings = jsn.payload.settings || {};
|
||||
var sel = document.getElementById("projectSelect");
|
||||
if (currentSettings.projectId && sel.options.length > 1) {
|
||||
sel.value = currentSettings.projectId;
|
||||
}
|
||||
if (currentSettings.activeEntryId) {
|
||||
setStatus("⏱ Timer running", "running");
|
||||
}
|
||||
});
|
||||
|
||||
$PI.onSendToPropertyInspector(ACTION_UUID, function(jsn) {
|
||||
var payload = jsn.payload;
|
||||
if (payload.event === "projects") {
|
||||
if (payload.error) {
|
||||
setStatus(payload.error, "error");
|
||||
} else {
|
||||
populateProjects(payload.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user