-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
238 lines (201 loc) · 7.29 KB
/
Copy pathscript.js
File metadata and controls
238 lines (201 loc) · 7.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
const resources = [
{
title: "MDN Web Docs",
description: "Reference guides for HTML, CSS, JavaScript, browser APIs, and web accessibility.",
href: "https://developer.mozilla.org/",
tags: ["docs", "html", "javascript"],
},
{
title: "CodePen",
description: "A quick place to prototype front-end ideas and share small website demos.",
href: "https://codepen.io/",
tags: ["frontend", "projects", "sharing"],
},
{
title: "Scratch",
description: "A beginner-friendly place to build animations, games, and interactive stories.",
href: "https://scratch.mit.edu/",
tags: ["games", "beginner", "creative"],
},
{
title: "GitHub Skills",
description: "Short interactive courses for learning GitHub, pull requests, and Markdown.",
href: "https://skills.github.com/",
tags: ["git", "github", "collaboration"],
},
{
title: "The Coding Train",
description: "Friendly creative-coding videos covering p5.js, visuals, games, and simulations.",
href: "https://thecodingtrain.com/",
tags: ["creative", "videos", "games"],
},
{
title: "FreeCodeCamp",
description: "Structured lessons and practice projects for web development and programming.",
href: "https://www.freecodecamp.org/",
tags: ["courses", "practice", "web"],
},
];
const resourceGrid = document.querySelector("#resourceGrid");
const resourceSearch = document.querySelector("#resourceSearch");
const loginMessage = document.querySelector("#loginMessage");
const linkForm = document.querySelector("#linkForm");
const linkInput = document.querySelector("#linkInput");
const linkMessage = document.querySelector("#linkMessage");
const previewFrame = document.querySelector("#previewFrame");
const previewTitle = document.querySelector("#previewTitle");
const previewLink = document.querySelector("#previewLink");
const saveLinkButton = document.querySelector("#saveLink");
const savedLinks = document.querySelector("#savedLinks");
const copyStepsButton = document.querySelector("#copySteps");
const copyMessage = document.querySelector("#copyMessage");
const savedLinksKey = "anywebsite.savedLinks";
function renderResources(filter = "") {
const normalizedFilter = filter.trim().toLowerCase();
const visibleResources = resources.filter((resource) => {
const text = [resource.title, resource.description, ...resource.tags].join(" ").toLowerCase();
return text.includes(normalizedFilter);
});
resourceGrid.innerHTML = "";
if (visibleResources.length === 0) {
resourceGrid.innerHTML = '<p class="notice">No approved links match that search yet.</p>';
return;
}
visibleResources.forEach((resource) => {
const card = document.createElement("article");
card.className = "resource-card";
const tags = resource.tags.map((tag) => `<span class="tag">${tag}</span>`).join("");
card.innerHTML = `
<div>
<h3>${resource.title}</h3>
<p>${resource.description}</p>
<div class="tag-list" aria-label="Tags">${tags}</div>
</div>
<a class="button secondary" href="${resource.href}" target="_blank" rel="noreferrer">
Open resource
</a>
`;
resourceGrid.append(card);
});
}
function showLoginMessage() {
const params = new URLSearchParams(window.location.search);
const login = params.get("login");
if (!login || !loginMessage) {
return;
}
loginMessage.textContent =
login === "success" ? "You are logged in." : "You have been logged out.";
}
function normalizeUrl(value) {
const trimmedValue = value.trim();
const candidate = /^https?:\/\//i.test(trimmedValue) ? trimmedValue : `https://${trimmedValue}`;
const url = new URL(candidate);
if (!["http:", "https:"].includes(url.protocol)) {
throw new Error("Unsupported URL");
}
return url;
}
function previewUrl(url) {
previewFrame.src = url.toString();
previewTitle.textContent = url.hostname;
previewLink.href = url.toString();
previewLink.removeAttribute("aria-disabled");
linkMessage.textContent =
"Preview loaded. If the frame stays blank, that website does not allow embedding.";
}
function handlePreview(event) {
event.preventDefault();
try {
previewUrl(normalizeUrl(linkInput.value));
} catch {
linkMessage.textContent = "Paste a valid website URL, like https://example.com.";
}
}
function getSavedLinks() {
try {
const saved = JSON.parse(localStorage.getItem(savedLinksKey) || "[]");
return Array.isArray(saved) ? saved : [];
} catch {
return [];
}
}
function setSavedLinks(links) {
localStorage.setItem(savedLinksKey, JSON.stringify(links));
}
function renderSavedLinks() {
const links = getSavedLinks();
savedLinks.innerHTML = "";
if (links.length === 0) {
savedLinks.innerHTML = '<p class="notice">No saved shortcuts yet.</p>';
return;
}
links.forEach((link) => {
const url = new URL(link);
const item = document.createElement("article");
item.className = "saved-link";
const title = document.createElement("strong");
title.textContent = url.hostname;
const href = document.createElement("span");
href.textContent = url.toString();
const actions = document.createElement("div");
actions.className = "saved-link-actions";
const previewButton = document.createElement("button");
previewButton.className = "button secondary";
previewButton.type = "button";
previewButton.textContent = "Preview";
previewButton.addEventListener("click", () => previewUrl(url));
const openLink = document.createElement("a");
openLink.className = "button secondary";
openLink.href = url.toString();
openLink.target = "_blank";
openLink.rel = "noreferrer";
openLink.textContent = "Open";
const removeButton = document.createElement("button");
removeButton.className = "button secondary";
removeButton.type = "button";
removeButton.textContent = "Remove";
removeButton.addEventListener("click", () => {
setSavedLinks(links.filter((savedLink) => savedLink !== link));
renderSavedLinks();
});
actions.append(previewButton, openLink, removeButton);
item.append(title, href, actions);
savedLinks.append(item);
});
}
function saveCurrentLink() {
try {
const url = normalizeUrl(linkInput.value);
const links = getSavedLinks();
if (!links.includes(url.toString())) {
links.unshift(url.toString());
setSavedLinks(links.slice(0, 12));
}
renderSavedLinks();
previewUrl(url);
linkMessage.textContent = "Shortcut saved on this device.";
} catch {
linkMessage.textContent = "Paste a valid website URL before saving.";
}
}
async function copyFriendSteps() {
const steps = [...document.querySelectorAll("#friendSteps li")]
.map((step, index) => `${index + 1}. ${step.textContent}`)
.join("\n");
try {
await navigator.clipboard.writeText(steps);
copyMessage.textContent = "Copied the friend setup steps.";
} catch {
copyMessage.textContent = "Could not copy automatically. Select the steps and copy them manually.";
}
}
resourceSearch.addEventListener("input", (event) => {
renderResources(event.target.value);
});
linkForm.addEventListener("submit", handlePreview);
saveLinkButton.addEventListener("click", saveCurrentLink);
copyStepsButton.addEventListener("click", copyFriendSteps);
showLoginMessage();
renderResources();
renderSavedLinks();