289 lines
8.5 KiB
HTML
289 lines
8.5 KiB
HTML
<!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; }
|
|
#versionText {
|
|
font-size: 12px;
|
|
color: #fff;
|
|
text-align: center;
|
|
padding-top: 8px;
|
|
}
|
|
#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>Your Name</label>
|
|
<select id="userId">
|
|
<option value="">— Select your name —</option>
|
|
</select>
|
|
</div>
|
|
<p class="hint">Shared across all buttons. Select 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>
|
|
<p id="versionText"></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,
|
|
};
|
|
$PI.setGlobalSettings(creds);
|
|
setCredStatus("Credentials saved.", "ok");
|
|
}
|
|
|
|
function populateUsers(users, savedUserId) {
|
|
var sel = document.getElementById("userId");
|
|
var current = savedUserId || sel.value;
|
|
sel.innerHTML = '<option value="">— Select your name —</option>';
|
|
users.forEach(function(u) {
|
|
var opt = document.createElement("option");
|
|
opt.value = u.id;
|
|
opt.textContent = u.name;
|
|
if (u.id === current) opt.selected = true;
|
|
sel.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
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);
|
|
document.getElementById("notionToken").addEventListener("input", scheduleCredSave);
|
|
document.getElementById("userId").addEventListener("change", saveCredentials);
|
|
});
|
|
|
|
$PI.onDidReceiveGlobalSettings(function(jsn) {
|
|
var s = jsn.payload.settings || {};
|
|
document.getElementById("notionToken").value = s.notionToken || "";
|
|
if (s.userId) {
|
|
var sel = document.getElementById("userId");
|
|
if (sel.querySelector('option[value="' + s.userId + '"]')) {
|
|
sel.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.version) {
|
|
document.getElementById("versionText").textContent = "v" + payload.version;
|
|
}
|
|
if (payload.users) {
|
|
var savedUserId = document.getElementById("userId").value;
|
|
populateUsers(payload.users, savedUserId);
|
|
}
|
|
if (payload.error) {
|
|
setStatus(payload.error, "error");
|
|
} else {
|
|
populateProjects(payload.data);
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|