@networkpro/web 1.12.8 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -1
- package/README.md +8 -8
- package/cspell.json +1 -0
- package/eslint.config.mjs +48 -48
- package/jsconfig.template.jsonc +3 -1
- package/netlify/edge-functions/csp-report.js +31 -31
- package/package.json +6 -6
- package/playwright.config.js +14 -14
- package/postcss.config.mjs +1 -1
- package/scripts/auditScripts.js +16 -16
- package/scripts/bundleCss.js +5 -5
- package/scripts/checkEnv.js +6 -6
- package/scripts/checkNode.js +10 -10
- package/scripts/checkVersions.js +6 -6
- package/scripts/flattenHeaders.js +13 -13
- package/scripts/generateTest.js +5 -5
- package/scripts/openReport.js +3 -3
- package/scripts/validateHeaders.js +13 -13
- package/src/hooks.client.ts +1 -1
- package/src/hooks.server.js +31 -31
- package/src/lib/components/Badges.svelte +9 -9
- package/src/lib/components/CodeBlock.svelte +13 -0
- package/src/lib/components/ContainerSection.svelte +1 -1
- package/src/lib/components/FullWidthSection.svelte +3 -3
- package/src/lib/components/LegalNav.svelte +6 -6
- package/src/lib/components/Logo.svelte +9 -9
- package/src/lib/components/MetaTags.svelte +3 -3
- package/src/lib/components/PWAInstallButton.svelte +4 -4
- package/src/lib/components/RedirectPage.svelte +4 -4
- package/src/lib/components/SocialMedia.svelte +16 -16
- package/src/lib/components/foss/FossItemContent.svelte +18 -18
- package/src/lib/components/layout/Footer.svelte +17 -17
- package/src/lib/components/layout/HeaderDefault.svelte +16 -16
- package/src/lib/components/layout/HeaderHome.svelte +14 -14
- package/src/lib/images.js +34 -34
- package/src/lib/index.js +15 -15
- package/src/lib/meta.js +29 -29
- package/src/lib/pages/AboutContent.svelte +24 -24
- package/src/lib/pages/FossContent.svelte +12 -12
- package/src/lib/pages/HomeContent.svelte +6 -6
- package/src/lib/pages/LicenseContent.svelte +38 -38
- package/src/lib/pages/PGPContent.svelte +61 -29
- package/src/lib/pages/PrivacyContent.svelte +39 -39
- package/src/lib/pages/PrivacyDashboard.svelte +12 -12
- package/src/lib/pages/TermsConditionsContent.svelte +28 -28
- package/src/lib/pages/TermsUseContent.svelte +26 -26
- package/src/lib/registerServiceWorker.js +25 -25
- package/src/lib/stores/posthog.js +13 -13
- package/src/lib/stores/trackingPreferences.js +19 -19
- package/src/lib/styles/css/default.css +5 -1
- package/src/lib/styles/global.min.css +1 -1
- package/src/lib/unregisterServiceWorker.js +1 -1
- package/src/lib/utils/purify.js +4 -4
- package/src/lib/utils/utm.js +2 -2
- package/src/routes/+error.svelte +4 -4
- package/src/routes/+layout.js +6 -6
- package/src/routes/+layout.svelte +29 -29
- package/src/routes/+page.server.js +2 -2
- package/src/routes/+page.svelte +9 -9
- package/src/routes/about/+page.server.js +2 -2
- package/src/routes/about/+page.svelte +7 -7
- package/src/routes/api/mock-csp/+server.js +3 -3
- package/src/routes/consultation/+page.svelte +5 -5
- package/src/routes/contact/+page.svelte +5 -5
- package/src/routes/foss-spotlight/+page.server.js +2 -2
- package/src/routes/foss-spotlight/+page.svelte +7 -7
- package/src/routes/license/+page.server.js +2 -2
- package/src/routes/license/+page.svelte +7 -7
- package/src/routes/pgp/+page.server.js +2 -2
- package/src/routes/pgp/+page.svelte +7 -7
- package/src/routes/pgp/[key]/+server.js +9 -9
- package/src/routes/privacy/+page.server.js +2 -2
- package/src/routes/privacy/+page.svelte +7 -7
- package/src/routes/privacy-dashboard/+page.server.js +2 -2
- package/src/routes/privacy-dashboard/+page.svelte +8 -8
- package/src/routes/privacy-rights/+page.svelte +5 -5
- package/src/routes/status/+page.server.js +2 -2
- package/src/routes/terms-conditions/+page.server.js +2 -2
- package/src/routes/terms-conditions/+page.svelte +7 -7
- package/src/routes/terms-of-use/+page.server.js +2 -2
- package/src/routes/terms-of-use/+page.svelte +7 -7
- package/src/service-worker.js +86 -85
- package/static/disableSw.js +2 -2
- package/static/img/powered-by-proton.svg +1 -0
- package/static/offline.html +7 -7
- package/static/sitemap.xml +64 -4
- package/stylelint.config.js +56 -56
- package/svelte.config.js +6 -6
- package/tests/e2e/app.spec.js +25 -25
- package/tests/e2e/mobile.spec.js +18 -18
- package/tests/e2e/shared/helpers.js +4 -4
- package/tests/internal/auditCoverage.test.js +24 -24
- package/tests/unit/checkEnv.test.js +10 -10
- package/tests/unit/checkVersions.test.js +4 -4
- package/tests/unit/csp-report.test.js +24 -24
- package/tests/unit/demo.test.js +3 -3
- package/tests/unit/lib/utils/purify.test.js +12 -12
- package/tests/unit/routes/page.svelte.test.js +10 -10
- package/tests/unit/unregisterServiceWorker.test.js +5 -5
- package/tests/unit/utm.test.js +13 -13
- package/vite.config.js +5 -5
- package/vitest-setup-client.js +4 -4
- package/vitest.config.client.js +15 -15
- package/vitest.config.server.js +13 -13
package/src/service-worker.js
CHANGED
|
@@ -13,13 +13,13 @@ const sw = /** @type {ServiceWorkerGlobalScope} */ (
|
|
|
13
13
|
|
|
14
14
|
/// <reference types="vite/client" />
|
|
15
15
|
|
|
16
|
-
const isDev = location.hostname ===
|
|
16
|
+
const isDev = location.hostname === 'localhost';
|
|
17
17
|
const disallowedHosts = [
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
'us.i.posthog.com', // Add PostHog to disallowed hosts
|
|
19
|
+
'posthog.com', // Add PostHog to disallowed hosts
|
|
20
20
|
];
|
|
21
21
|
|
|
22
|
-
import { build, files, version } from
|
|
22
|
+
import { build, files, version } from '$service-worker';
|
|
23
23
|
|
|
24
24
|
/** @type {string} */
|
|
25
25
|
const CACHE = `cache-${version}`;
|
|
@@ -28,37 +28,38 @@ const CACHE = `cache-${version}`;
|
|
|
28
28
|
const excludedAssets = [];
|
|
29
29
|
|
|
30
30
|
const IGNORE_PATHS = new Set([
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
31
|
+
'/.well-known/security.txt.asc',
|
|
32
|
+
'/img/banner-1280x640.png',
|
|
33
|
+
'/img/logo-transparent.png',
|
|
34
|
+
'/img/logo.png',
|
|
35
|
+
'/img/svelte.png',
|
|
36
|
+
'/pgp/pgp-github.png',
|
|
37
|
+
'/pgp/pgp-github.webp',
|
|
38
|
+
'/pgp/contact@s.neteng.pro.asc',
|
|
39
|
+
'/pgp/github@sl.neteng.cc.asc',
|
|
40
|
+
'/pgp/security@s.neteng.pro.asc',
|
|
41
|
+
'/pgp/support@neteng.pro.asc',
|
|
42
|
+
'/pgp/vcard.png',
|
|
43
|
+
'/pgp/vcard.webp',
|
|
44
|
+
'/screenshots/desktop-foss.png',
|
|
45
|
+
'/webfonts/fa-brands-400.ttf',
|
|
46
|
+
'/webfonts/fa-solid-900.ttf',
|
|
47
|
+
'/robots.txt',
|
|
48
|
+
'/sitemap.xml',
|
|
49
|
+
'/CNAME',
|
|
49
50
|
]);
|
|
50
51
|
|
|
51
52
|
/** @type {string[]} */
|
|
52
53
|
const ASSETS = [
|
|
53
54
|
...new Set(
|
|
54
|
-
[...build, ...files,
|
|
55
|
+
[...build, ...files, '/offline.html'].filter((path) => {
|
|
55
56
|
try {
|
|
56
57
|
const url = new URL(path, location.origin);
|
|
57
58
|
const hostname = url.hostname;
|
|
58
59
|
|
|
59
60
|
const shouldExclude =
|
|
60
|
-
path.startsWith(
|
|
61
|
-
path.startsWith(
|
|
61
|
+
path.startsWith('http') ||
|
|
62
|
+
path.startsWith('/bin/') ||
|
|
62
63
|
disallowedHosts.some(
|
|
63
64
|
(host) => hostname === host || hostname.endsWith(`.${host}`),
|
|
64
65
|
) ||
|
|
@@ -68,7 +69,7 @@ const ASSETS = [
|
|
|
68
69
|
return !shouldExclude;
|
|
69
70
|
} catch (err) {
|
|
70
71
|
if (isDev)
|
|
71
|
-
console.warn(
|
|
72
|
+
console.warn('[SW] URL parse failed, skipping path:', path, err);
|
|
72
73
|
excludedAssets.push(path);
|
|
73
74
|
return true;
|
|
74
75
|
}
|
|
@@ -80,41 +81,41 @@ const uniqueExcludedAssets = [...new Set(excludedAssets)].sort();
|
|
|
80
81
|
|
|
81
82
|
/** @type {string[]} */
|
|
82
83
|
const REQUIRED_ASSETS = [
|
|
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
|
-
|
|
84
|
+
'/disableSw.js',
|
|
85
|
+
'/favicon.ico',
|
|
86
|
+
'/icon-192x192.png',
|
|
87
|
+
'/icon-512x512-maskable.png',
|
|
88
|
+
'/icon-512x512.png',
|
|
89
|
+
'/icon-contact.png',
|
|
90
|
+
'/icon-services.png',
|
|
91
|
+
'/icon-splash.png',
|
|
92
|
+
'/img/banner-og-1200x630.png',
|
|
93
|
+
'/pgp/pgp-contact.png',
|
|
94
|
+
'/pgp/pgp-contact.webp',
|
|
95
|
+
'/pgp/pgp-security.png',
|
|
96
|
+
'/pgp/pgp-security.webp',
|
|
97
|
+
'/pgp/pgp-support.png',
|
|
98
|
+
'/pgp/pgp-support.webp',
|
|
99
|
+
'/manifest.json',
|
|
100
|
+
'/offline.html',
|
|
101
|
+
'/offline.min.css',
|
|
102
|
+
'/screenshots/desktop-about.png',
|
|
103
|
+
'/screenshots/desktop-home.png',
|
|
104
|
+
'/screenshots/mobile-foss.png',
|
|
105
|
+
'/screenshots/mobile-home.png',
|
|
106
|
+
'/styles/brands.min.css',
|
|
107
|
+
'/styles/fontawesome.min.css',
|
|
108
|
+
'/styles/global.min.css',
|
|
109
|
+
'/styles/solid.min.css',
|
|
110
|
+
'/webfonts/fa-brands-400.woff2',
|
|
111
|
+
'/webfonts/fa-solid-900.woff2',
|
|
112
|
+
'/.well-known/dnt-policy.txt',
|
|
113
|
+
'/.well-known/gpc.json',
|
|
113
114
|
];
|
|
114
115
|
|
|
115
116
|
if (isDev) {
|
|
116
|
-
console.log(
|
|
117
|
-
console.log(
|
|
117
|
+
console.log('[SW] Assets to precache:', ASSETS);
|
|
118
|
+
console.log('[SW] Excluded assets:', uniqueExcludedAssets);
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
/**
|
|
@@ -151,7 +152,7 @@ async function cacheAssetsSafely(cache, assets, required = []) {
|
|
|
151
152
|
|
|
152
153
|
const missing = required.filter((req) => !cachedPaths.includes(req));
|
|
153
154
|
if (missing.length > 0) {
|
|
154
|
-
const errorMsg = `[SW] ⚠️ Missing required assets: ${missing.join(
|
|
155
|
+
const errorMsg = `[SW] ⚠️ Missing required assets: ${missing.join(', ')}`;
|
|
155
156
|
if (isDev) throw new Error(errorMsg);
|
|
156
157
|
console.error(errorMsg);
|
|
157
158
|
}
|
|
@@ -160,8 +161,8 @@ async function cacheAssetsSafely(cache, assets, required = []) {
|
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
// 🔹 Install event
|
|
163
|
-
sw.addEventListener(
|
|
164
|
-
if (isDev) console.log(
|
|
164
|
+
sw.addEventListener('install', (event) => {
|
|
165
|
+
if (isDev) console.log('[SW] Install event');
|
|
165
166
|
|
|
166
167
|
event.waitUntil(
|
|
167
168
|
(async () => {
|
|
@@ -171,29 +172,29 @@ sw.addEventListener("install", (event) => {
|
|
|
171
172
|
try {
|
|
172
173
|
cachedPaths = await cacheAssetsSafely(cache, ASSETS, REQUIRED_ASSETS);
|
|
173
174
|
if (isDev) {
|
|
174
|
-
console.log(
|
|
175
|
+
console.log('[SW] Cached assets:', cachedPaths);
|
|
175
176
|
}
|
|
176
177
|
} catch (err) {
|
|
177
178
|
if (isDev) throw err;
|
|
178
|
-
console.warn(
|
|
179
|
+
console.warn('[SW] Error while precaching (non-fatal in prod):', err);
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
await sw.skipWaiting();
|
|
182
|
-
if (isDev) console.log(
|
|
183
|
+
if (isDev) console.log('[SW] skipWaiting() called');
|
|
183
184
|
})(),
|
|
184
185
|
);
|
|
185
186
|
});
|
|
186
187
|
|
|
187
188
|
// 🔹 Activate event
|
|
188
|
-
sw.addEventListener(
|
|
189
|
-
if (isDev) console.log(
|
|
189
|
+
sw.addEventListener('activate', (event) => {
|
|
190
|
+
if (isDev) console.log('[SW] Activate event');
|
|
190
191
|
event.waitUntil(
|
|
191
192
|
(async () => {
|
|
192
193
|
const tasks = [];
|
|
193
194
|
|
|
194
195
|
if (sw.registration.navigationPreload) {
|
|
195
196
|
tasks.push(sw.registration.navigationPreload.enable());
|
|
196
|
-
if (isDev) console.log(
|
|
197
|
+
if (isDev) console.log('[SW] Navigation preload enabled');
|
|
197
198
|
}
|
|
198
199
|
|
|
199
200
|
tasks.push(
|
|
@@ -202,7 +203,7 @@ sw.addEventListener("activate", (event) => {
|
|
|
202
203
|
keys
|
|
203
204
|
.filter((key) => key !== CACHE)
|
|
204
205
|
.map((key) => {
|
|
205
|
-
if (isDev) console.log(
|
|
206
|
+
if (isDev) console.log('[SW] Deleting old cache:', key);
|
|
206
207
|
return caches.delete(key);
|
|
207
208
|
}),
|
|
208
209
|
),
|
|
@@ -212,8 +213,8 @@ sw.addEventListener("activate", (event) => {
|
|
|
212
213
|
await Promise.all(tasks);
|
|
213
214
|
await sw.clients.claim();
|
|
214
215
|
if (isDev) {
|
|
215
|
-
console.log(
|
|
216
|
-
console.log(
|
|
216
|
+
console.log('[SW] clients.claim() called');
|
|
217
|
+
console.log('[SW] Scope:', sw.registration.scope);
|
|
217
218
|
}
|
|
218
219
|
})(),
|
|
219
220
|
);
|
|
@@ -231,16 +232,16 @@ function shouldSkipDevModule(url) {
|
|
|
231
232
|
if (!isDev) return false;
|
|
232
233
|
|
|
233
234
|
return (
|
|
234
|
-
url.pathname.startsWith(
|
|
235
|
-
url.pathname.startsWith(
|
|
236
|
-
url.pathname.includes(
|
|
237
|
-
url.pathname.includes(
|
|
235
|
+
url.pathname.startsWith('/@fs') ||
|
|
236
|
+
url.pathname.startsWith('/node_modules') ||
|
|
237
|
+
url.pathname.includes('.vite') ||
|
|
238
|
+
url.pathname.includes('.svelte-kit') ||
|
|
238
239
|
!!url.pathname.match(/\.(js|ts|svelte)$/)
|
|
239
240
|
);
|
|
240
241
|
}
|
|
241
242
|
|
|
242
243
|
// 🔹 Fetch event
|
|
243
|
-
sw.addEventListener(
|
|
244
|
+
sw.addEventListener('fetch', (event) => {
|
|
244
245
|
const requestUrl = new URL(event.request.url);
|
|
245
246
|
|
|
246
247
|
// ✅ Skip cross-origin requests
|
|
@@ -249,23 +250,23 @@ sw.addEventListener("fetch", (event) => {
|
|
|
249
250
|
// ✅ Skip internal dev/module files (only in dev)
|
|
250
251
|
if (shouldSkipDevModule(requestUrl)) return;
|
|
251
252
|
|
|
252
|
-
if (isDev) console.log(
|
|
253
|
+
if (isDev) console.log('[SW] Fetch intercepted:', event.request.url);
|
|
253
254
|
|
|
254
255
|
event.respondWith(
|
|
255
256
|
(async () => {
|
|
256
257
|
const cached = await caches.match(event.request);
|
|
257
258
|
if (cached) {
|
|
258
|
-
if (isDev) console.log(
|
|
259
|
+
if (isDev) console.log('[SW] Serving from cache:', event.request.url);
|
|
259
260
|
return cached;
|
|
260
261
|
}
|
|
261
262
|
|
|
262
263
|
try {
|
|
263
|
-
if (event.request.mode ===
|
|
264
|
+
if (event.request.mode === 'navigate') {
|
|
264
265
|
const preloadResponse = await event.preloadResponse;
|
|
265
266
|
if (preloadResponse) {
|
|
266
267
|
if (isDev) {
|
|
267
268
|
console.log(
|
|
268
|
-
|
|
269
|
+
'[SW] Using preload response for:',
|
|
269
270
|
event.request.url,
|
|
270
271
|
);
|
|
271
272
|
}
|
|
@@ -274,23 +275,23 @@ sw.addEventListener("fetch", (event) => {
|
|
|
274
275
|
}
|
|
275
276
|
|
|
276
277
|
if (isDev)
|
|
277
|
-
console.log(
|
|
278
|
+
console.log('[SW] Fetching from network:', event.request.url);
|
|
278
279
|
|
|
279
280
|
return await fetch(event.request);
|
|
280
281
|
} catch (err) {
|
|
281
282
|
if (isDev) {
|
|
282
283
|
console.warn(
|
|
283
|
-
|
|
284
|
+
'[SW] Fetch failed; offline fallback used:',
|
|
284
285
|
event.request.url,
|
|
285
286
|
err,
|
|
286
287
|
);
|
|
287
288
|
}
|
|
288
289
|
|
|
289
|
-
if (event.request.mode ===
|
|
290
|
-
const offline = await caches.match(
|
|
290
|
+
if (event.request.mode === 'navigate') {
|
|
291
|
+
const offline = await caches.match('/offline.html');
|
|
291
292
|
if (offline) return offline;
|
|
292
|
-
return new Response(
|
|
293
|
-
headers: {
|
|
293
|
+
return new Response('<h1>Offline</h1>', {
|
|
294
|
+
headers: { 'Content-Type': 'text/html' },
|
|
294
295
|
});
|
|
295
296
|
}
|
|
296
297
|
|
package/static/disableSw.js
CHANGED
|
@@ -14,7 +14,7 @@ This file is part of Network Pro.
|
|
|
14
14
|
* @updated 2025-05-29
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
if (location.search.includes(
|
|
17
|
+
if (location.search.includes('nosw')) {
|
|
18
18
|
window.__DISABLE_SW__ = true;
|
|
19
|
-
console.warn(
|
|
19
|
+
console.warn('🧪 Service worker disabled via ?nosw flag in URL.');
|
|
20
20
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="196.114" height="28" aria-label="POWERED BY: PROTON"><g shape-rendering="crispEdges"><path fill="#555" d="M0 0h117.614v28H0z"/><path fill="#6d4aff" d="M117.614 0h78.5v28h-78.5z"/></g><g fill="#fff" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="100" text-anchor="middle" text-rendering="geometricPrecision"><image width="11.114" height="14" x="9" y="7" href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgMTkuMDUyMDAwMDAwMDAwMDAzIDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5Qcm90b248L3RpdGxlPjxwYXRoIGQ9Ik0wIDE3Ljc1VjI0aDQuNDAxdi01Ljk3OWMwLTAuNTgyIDAuMjMyLTEuMTQgMC42NDUtMS41NTFhMi4yMDQgMi4yMDQgMCAwIDEgMS41NTYtMC42NDNoNC41MTNhNy45NTUgNy45NTUgMCAwIDAgNS42MTItMi4zMTggNy45MDcgNy45MDcgMCAwIDAgMi4zMjUtNS41OTUgNy45MSA3LjkxIDAgMCAwLTIuMzI1LTUuNTk2QTcuOTU4IDcuOTU4IDAgMCAwIDExLjExMyAwSDB2Ny44MTJoNC40MDFWNC4xMjloNi40MTZjMC45OTUgMCAxLjk1MSAwLjM5NCAyLjY1NiAxLjA5NyAwLjcwNCAwLjcgMS4xIDEuNjUzIDEuMTAxIDIuNjQ2YTMuNzQyIDMuNzQyIDAgMCAxLTEuMTAxIDIuNjQ4IDMuNzY2IDMuNzY2IDAgMCAxLTIuNjU2IDEuMDk3SDYuMTUzYTYuMTU4IDYuMTU4IDAgMCAwLTQuMzUyIDEuNzk1IDYuMTMzIDYuMTMzIDAgMCAwLTEuODAxIDQuMzM4WiIvPjwvc3ZnPg=="/><text x="658.637" y="175" textLength="795" transform="scale(.1)">POWERED BY</text><text x="1568.637" y="175" font-weight="bold" textLength="545" transform="scale(.1)">PROTON</text></g></svg>
|
package/static/offline.html
CHANGED
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
function updateTimestamp() {
|
|
44
44
|
const now = new Date();
|
|
45
45
|
const timeStr = now.toLocaleTimeString([], {
|
|
46
|
-
hour:
|
|
47
|
-
minute:
|
|
46
|
+
hour: '2-digit',
|
|
47
|
+
minute: '2-digit',
|
|
48
48
|
});
|
|
49
|
-
document.getElementById(
|
|
49
|
+
document.getElementById('timestamp').textContent = timeStr;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
// Check connection status periodically
|
|
@@ -64,17 +64,17 @@
|
|
|
64
64
|
setInterval(updateTimestamp, 60000);
|
|
65
65
|
|
|
66
66
|
// Also listen for online event
|
|
67
|
-
window.addEventListener(
|
|
67
|
+
window.addEventListener('online', () => {
|
|
68
68
|
window.location.reload();
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
// Prevent default action for offline links
|
|
72
72
|
document
|
|
73
|
-
.getElementById(
|
|
74
|
-
.addEventListener(
|
|
73
|
+
.getElementById('contact-link')
|
|
74
|
+
.addEventListener('click', function (e) {
|
|
75
75
|
if (!navigator.onLine) {
|
|
76
76
|
e.preventDefault();
|
|
77
|
-
alert(
|
|
77
|
+
alert('This link will be available when you are back online.');
|
|
78
78
|
}
|
|
79
79
|
});
|
|
80
80
|
</script>
|
package/static/sitemap.xml
CHANGED
|
@@ -101,9 +101,9 @@
|
|
|
101
101
|
|
|
102
102
|
<url>
|
|
103
103
|
|
|
104
|
-
<loc>https://netwk.pro/
|
|
104
|
+
<loc>https://netwk.pro/pgp</loc>
|
|
105
105
|
|
|
106
|
-
<lastmod>2025-06-
|
|
106
|
+
<lastmod>2025-06-11</lastmod>
|
|
107
107
|
|
|
108
108
|
<changefreq>monthly</changefreq>
|
|
109
109
|
|
|
@@ -111,15 +111,75 @@
|
|
|
111
111
|
|
|
112
112
|
</url>
|
|
113
113
|
|
|
114
|
+
<url>
|
|
115
|
+
|
|
116
|
+
<loc>https://netwk.pro/bin/CC-BY-4.0.html</loc>
|
|
117
|
+
|
|
118
|
+
<lastmod>2025-06-10</lastmod>
|
|
119
|
+
|
|
120
|
+
<changefreq>yearly</changefreq>
|
|
121
|
+
|
|
122
|
+
<priority>0.3</priority>
|
|
123
|
+
|
|
124
|
+
</url>
|
|
125
|
+
|
|
114
126
|
<url>
|
|
115
127
|
|
|
116
128
|
<loc>https://netwk.pro/bin/COPYING.html</loc>
|
|
117
129
|
|
|
118
130
|
<lastmod>2025-06-10</lastmod>
|
|
119
131
|
|
|
120
|
-
<changefreq>
|
|
132
|
+
<changefreq>yearly</changefreq>
|
|
121
133
|
|
|
122
|
-
<priority>0.
|
|
134
|
+
<priority>0.3</priority>
|
|
135
|
+
|
|
136
|
+
</url>
|
|
137
|
+
|
|
138
|
+
<url>
|
|
139
|
+
|
|
140
|
+
<loc>https://netwk.pro/.well-known/security.txt</loc>
|
|
141
|
+
|
|
142
|
+
<lastmod>2025-06-11</lastmod>
|
|
143
|
+
|
|
144
|
+
<changefreq>yearly</changefreq>
|
|
145
|
+
|
|
146
|
+
<priority>0.2</priority>
|
|
147
|
+
|
|
148
|
+
</url>
|
|
149
|
+
|
|
150
|
+
<url>
|
|
151
|
+
|
|
152
|
+
<loc>https://netwk.pro/.well-known/dnt-policy.txt</loc>
|
|
153
|
+
|
|
154
|
+
<lastmod>2025-06-11</lastmod>
|
|
155
|
+
|
|
156
|
+
<changefreq>yearly</changefreq>
|
|
157
|
+
|
|
158
|
+
<priority>0.2</priority>
|
|
159
|
+
|
|
160
|
+
</url>
|
|
161
|
+
|
|
162
|
+
<url>
|
|
163
|
+
|
|
164
|
+
<loc>https://netwk.pro/.well-known/gpc.json</loc>
|
|
165
|
+
|
|
166
|
+
<lastmod>2025-06-11</lastmod>
|
|
167
|
+
|
|
168
|
+
<changefreq>yearly</changefreq>
|
|
169
|
+
|
|
170
|
+
<priority>0.2</priority>
|
|
171
|
+
|
|
172
|
+
</url>
|
|
173
|
+
|
|
174
|
+
<url>
|
|
175
|
+
|
|
176
|
+
<loc>https://netwk.pro/.well-known/humans.txt</loc>
|
|
177
|
+
|
|
178
|
+
<lastmod>2025-06-11</lastmod>
|
|
179
|
+
|
|
180
|
+
<changefreq>yearly</changefreq>
|
|
181
|
+
|
|
182
|
+
<priority>0.1</priority>
|
|
123
183
|
|
|
124
184
|
</url>
|
|
125
185
|
|
package/stylelint.config.js
CHANGED
|
@@ -9,101 +9,101 @@ This file is part of Network Pro
|
|
|
9
9
|
/** @type {import('stylelint').Config} */
|
|
10
10
|
export default {
|
|
11
11
|
extends: [
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
'stylelint-config-recommended', // Base recommended config
|
|
13
|
+
'stylelint-config-html/html', // For linting HTML files
|
|
14
|
+
'stylelint-config-html/svelte', // For linting HTML within Svelte or similar frameworks
|
|
15
|
+
'stylelint-config-html', // For linting HTML files
|
|
16
16
|
],
|
|
17
|
-
plugins: [
|
|
17
|
+
plugins: ['stylelint-order'], // Add stylelint-order plugin
|
|
18
18
|
ignoreFiles: [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
'./src/lib/styles/fa-global.css', // Ignore CSS import files
|
|
20
|
+
'./src/lib/styles/css/global.css', // Ignore CSS import files
|
|
21
|
+
'./src/lib/styles/css/brands.css', // Ignore FontAwesome CSS files
|
|
22
|
+
'**/*.min.css', // Also ignore minified CSS files as a best practice
|
|
23
23
|
],
|
|
24
24
|
rules: {
|
|
25
|
-
|
|
25
|
+
'selector-pseudo-class-no-unknown': [
|
|
26
26
|
true,
|
|
27
27
|
{
|
|
28
|
-
ignorePseudoClasses: [
|
|
28
|
+
ignorePseudoClasses: [':global'], // Allow :global for Svelte scoped styles
|
|
29
29
|
},
|
|
30
30
|
],
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
'property-no-vendor-prefix': null, // Allow vendor prefixes
|
|
32
|
+
'selector-no-vendor-prefix': null,
|
|
33
|
+
'selector-pseudo-element-colon-notation': [
|
|
34
|
+
'double',
|
|
35
35
|
{
|
|
36
|
-
severity:
|
|
36
|
+
severity: 'warning',
|
|
37
37
|
},
|
|
38
38
|
],
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
'media-feature-name-no-vendor-prefix': null,
|
|
40
|
+
'font-family-no-duplicate-names': [
|
|
41
41
|
true,
|
|
42
42
|
{
|
|
43
|
-
ignoreFontFamilyNames: [
|
|
43
|
+
ignoreFontFamilyNames: ['monospace'],
|
|
44
44
|
},
|
|
45
45
|
],
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
'selector-class-pattern': [
|
|
47
|
+
'^(?!fa-).*$', // Disallow classes starting with "fa-"
|
|
48
48
|
{
|
|
49
49
|
message:
|
|
50
50
|
"Class names must not start with 'fa-' (FontAwesome classes are ignored)",
|
|
51
51
|
},
|
|
52
52
|
],
|
|
53
|
-
|
|
53
|
+
'order/properties-order': [
|
|
54
54
|
[
|
|
55
55
|
{
|
|
56
|
-
groupName:
|
|
57
|
-
properties: [
|
|
56
|
+
groupName: 'Positioning',
|
|
57
|
+
properties: ['position', 'top', 'right', 'bottom', 'left', 'z-index'],
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
|
-
groupName:
|
|
60
|
+
groupName: 'Box Model',
|
|
61
61
|
properties: [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
'display',
|
|
63
|
+
'flex',
|
|
64
|
+
'flex-grow',
|
|
65
|
+
'flex-shrink',
|
|
66
|
+
'flex-basis',
|
|
67
|
+
'justify-content',
|
|
68
|
+
'align-items',
|
|
69
|
+
'align-self',
|
|
70
|
+
'width',
|
|
71
|
+
'height',
|
|
72
|
+
'padding',
|
|
73
|
+
'margin',
|
|
74
|
+
'border',
|
|
75
|
+
'box-shadow',
|
|
76
76
|
],
|
|
77
77
|
},
|
|
78
78
|
{
|
|
79
|
-
groupName:
|
|
79
|
+
groupName: 'Typography',
|
|
80
80
|
properties: [
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
'font',
|
|
82
|
+
'font-size',
|
|
83
|
+
'font-weight',
|
|
84
|
+
'line-height',
|
|
85
|
+
'letter-spacing',
|
|
86
|
+
'color',
|
|
87
|
+
'text-align',
|
|
88
88
|
],
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
|
-
groupName:
|
|
91
|
+
groupName: 'Visual',
|
|
92
92
|
properties: [
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
'background',
|
|
94
|
+
'background-color',
|
|
95
|
+
'background-image',
|
|
96
|
+
'opacity',
|
|
97
|
+
'visibility',
|
|
98
98
|
],
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
|
-
groupName:
|
|
102
|
-
properties: [
|
|
101
|
+
groupName: 'Animation & Transform',
|
|
102
|
+
properties: ['transition', 'transform', 'animation'],
|
|
103
103
|
},
|
|
104
104
|
],
|
|
105
105
|
{
|
|
106
|
-
unspecified:
|
|
106
|
+
unspecified: 'bottomAlphabetical', // Place unspecified properties alphabetically at the bottom
|
|
107
107
|
},
|
|
108
108
|
],
|
|
109
109
|
},
|