profileShare

rasmusjy / profileshare

Read-only snapshot

No repository description.

main default branch 54 files Expires Sep 13, 2026, 9:06 AM
app.js 4,574 bytes
1 const copyButton = document.querySelector("#copy-link");
2
3 async function copyText(button, value) {
4 const originalLabel = button.textContent;
5 try {
6 await navigator.clipboard.writeText(value);
7 button.textContent = "Copied";
8 } catch {
9 button.textContent = "Copy failed";
10 }
11 window.setTimeout(() => {
12 button.textContent = originalLabel;
13 }, 1800);
14 }
15
16 copyButton?.addEventListener("click", () => {
17 const shareUrl = document.querySelector("#share-url");
18 copyText(copyButton, shareUrl.value);
19 });
20
21 document.querySelectorAll("[data-copy-text]").forEach((button) => {
22 button.addEventListener("click", (event) => {
23 // Some copy buttons sit inside a <summary>, where a plain click would also
24 // collapse the file the reader just asked about.
25 event.preventDefault();
26 copyText(button, button.dataset.copyText);
27 });
28 });
29
30 const WRAP_STORAGE_KEY = "profileshare-diff-wrap";
31
32 function readStoredWrap() {
33 try {
34 return window.localStorage.getItem(WRAP_STORAGE_KEY) === "on";
35 } catch {
36 return false;
37 }
38 }
39
40 document.querySelectorAll("[data-diff-wrap]").forEach((button) => {
41 function apply(wrapped) {
42 document.body.classList.toggle("diff-wrapped", wrapped);
43 button.setAttribute("aria-pressed", String(wrapped));
44 button.textContent = wrapped ? "No wrap" : "Wrap lines";
45 }
46 apply(readStoredWrap());
47 button.addEventListener("click", () => {
48 const wrapped = !document.body.classList.contains("diff-wrapped");
49 apply(wrapped);
50 try {
51 window.localStorage.setItem(WRAP_STORAGE_KEY, wrapped ? "on" : "off");
52 } catch {
53 // A blocked storage quota is not a reason to lose the toggle itself.
54 }
55 });
56 });
57
58 document.querySelectorAll("[data-diff-toggle-all]").forEach((button) => {
59 const files = [...document.querySelectorAll("details.diff-file")];
60 button.addEventListener("click", () => {
61 const collapse = files.some((file) => file.open);
62 files.forEach((file) => { file.open = !collapse; });
63 button.textContent = collapse ? "Expand all" : "Collapse all";
64 });
65 });
66
67 document.addEventListener("keydown", (event) => {
68 if (event.key !== "/" || event.ctrlKey || event.metaKey || event.altKey) return;
69 if (event.target.closest("input, textarea, select, [contenteditable]")) return;
70 const searchInput = document.querySelector("[data-search-input]");
71 if (!searchInput) return;
72 event.preventDefault();
73 searchInput.focus();
74 });
75
76 document.querySelectorAll("[data-ref-filter]").forEach((input) => {
77 const menu = input.closest(".ref-menu");
78 const options = [...menu.querySelectorAll("[data-ref-option]")];
79 const emptyState = menu.querySelector("[data-ref-empty]");
80 input.addEventListener("input", () => {
81 const query = input.value.trim().toLocaleLowerCase("en");
82 let visible = 0;
83 options.forEach((option) => {
84 option.hidden = !option.dataset.refName.includes(query);
85 if (!option.hidden) visible += 1;
86 });
87 emptyState.hidden = visible > 0;
88 });
89 input.addEventListener("keydown", (event) => {
90 if (event.key !== "Escape") return;
91 const details = input.closest("details");
92 details.open = false;
93 details.querySelector("summary").focus();
94 });
95 });
96
97 document.addEventListener("click", (event) => {
98 document.querySelectorAll(".ref-switcher[open]").forEach((details) => {
99 if (!details.contains(event.target)) details.open = false;
100 });
101 });
102
103 const shareForm = document.querySelector(".share-form");
104 const repositoryInputs = [...document.querySelectorAll('input[name="repositories"]')];
105 const selectionCount = document.querySelector("#selection-count");
106 const createButton = shareForm?.querySelector('button[type="submit"]');
107 const creationStatus = document.querySelector("#creation-status");
108
109 function updateSelection() {
110 const count = repositoryInputs.filter((input) => input.checked).length;
111 if (selectionCount) {
112 selectionCount.textContent = `${count} ${count === 1 ? "repository" : "repositories"} selected`;
113 }
114 if (createButton) createButton.disabled = count === 0;
115 }
116
117 repositoryInputs.forEach((input) => input.addEventListener("change", updateSelection));
118 updateSelection();
119
120 shareForm?.addEventListener("submit", () => {
121 createButton.disabled = true;
122 createButton.textContent = "Creating snapshot...";
123 creationStatus.textContent = "Creating the snapshot. Large repositories may take a few minutes.";
124 });
125
126 document.querySelectorAll("form[data-confirm]").forEach((form) => {
127 form.addEventListener("submit", (event) => {
128 if (!window.confirm(form.dataset.confirm)) event.preventDefault();
129 });
130 });
131