@networkpro/web 1.6.5 → 1.7.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/CODE_OF_CONDUCT.md +2 -2
- package/LICENSE.md +20 -9
- package/_redirects +1 -0
- package/cspell.json +2 -0
- package/package.json +4 -4
- package/playwright.config.js +1 -0
- package/src/lib/components/FullWidthSection.svelte +19 -4
- package/src/lib/components/LegalNav.svelte +31 -29
- package/src/lib/components/PostHog.svelte +20 -8
- package/src/lib/components/layout/Footer.svelte +1 -1
- package/src/lib/components/layout/HeaderDefault.svelte +2 -2
- package/src/lib/components/layout/HeaderHome.svelte +2 -2
- package/src/lib/images.js +3 -2
- package/src/lib/index.js +2 -1
- package/src/lib/meta.js +6 -1
- package/src/lib/pages/LicenseContent.svelte +17 -17
- package/src/lib/pages/PrivacyContent.svelte +116 -6
- package/src/lib/pages/PrivacyDashboard.svelte +240 -0
- package/src/lib/pages/TermsUseContent.svelte +1 -1
- package/src/lib/styles/css/default.css +23 -10
- package/src/lib/styles/global.min.css +1 -3
- package/src/lib/utils/privacy.js +18 -3
- package/src/lib/utils/trackingCookies.js +40 -0
- package/src/lib/utils/trackingStatus.js +46 -0
- package/src/lib/utils/utm.js +8 -1
- package/src/routes/about/+page.svelte +1 -7
- package/src/routes/foss-spotlight/+page.svelte +1 -7
- package/src/routes/license/+page.svelte +2 -8
- package/src/routes/privacy/+page.server.js +18 -0
- package/src/routes/{privacy-policy → privacy}/+page.svelte +5 -11
- package/src/routes/{privacy-policy → privacy-dashboard}/+page.server.js +2 -2
- package/src/routes/privacy-dashboard/+page.svelte +69 -0
- package/src/routes/terms-conditions/+page.svelte +2 -8
- package/src/routes/terms-of-use/+page.svelte +2 -8
- package/src/service-worker.js +31 -6
- package/static/sitemap.xml +10 -22
- package/tests/e2e/app.spec.js +21 -63
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
<!-- ==========================================================================
|
|
2
|
+
src/lib/pages/PrivacyDashboard.svelte
|
|
3
|
+
|
|
4
|
+
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
|
+
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
6
|
+
This file is part of Network Pro.
|
|
7
|
+
========================================================================== -->
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import { base } from "$app/paths";
|
|
11
|
+
import { onMount } from "svelte";
|
|
12
|
+
import { getTrackingPreferences } from "$lib/utils/trackingStatus.js";
|
|
13
|
+
/** @type {(type: 'enable' | 'disable') => void} */
|
|
14
|
+
import {
|
|
15
|
+
setTrackingPreference,
|
|
16
|
+
clearTrackingPreferences,
|
|
17
|
+
} from "$lib/utils/trackingCookies.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @type {string}
|
|
21
|
+
* Style class for the div element.
|
|
22
|
+
*/
|
|
23
|
+
const spaceStyle = "spacer";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* URL to the full Privacy Policy using the base path
|
|
27
|
+
* @type {string}
|
|
28
|
+
*/
|
|
29
|
+
const privacyPolicy = `${base}/privacy`;
|
|
30
|
+
const prightsLink = `${base}/privacy-rights`;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Constants used throughout the component for consistent styling and behavior
|
|
34
|
+
* @type {{
|
|
35
|
+
* classSmall: string,
|
|
36
|
+
* rel: string,
|
|
37
|
+
* backTop: string,
|
|
38
|
+
* hrefTop: string,
|
|
39
|
+
* targetSelf: string,
|
|
40
|
+
* targetBlank: string
|
|
41
|
+
* }}
|
|
42
|
+
*/
|
|
43
|
+
const constants = {
|
|
44
|
+
classSmall: "small-text",
|
|
45
|
+
rel: "noopener noreferrer",
|
|
46
|
+
backTop: "Back to top",
|
|
47
|
+
hrefTop: "#top",
|
|
48
|
+
targetSelf: "_self",
|
|
49
|
+
targetBlank: "_blank",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
let optedOut = false;
|
|
53
|
+
let optedIn = false;
|
|
54
|
+
let trackingStatus = "";
|
|
55
|
+
|
|
56
|
+
onMount(() => {
|
|
57
|
+
const prefs = getTrackingPreferences();
|
|
58
|
+
optedOut = prefs.optedOut;
|
|
59
|
+
optedIn = prefs.optedIn;
|
|
60
|
+
trackingStatus = prefs.status;
|
|
61
|
+
console.log("[Tracking] Status:", trackingStatus);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Toggle tracking opt-out.
|
|
66
|
+
* @param {boolean} value
|
|
67
|
+
*/
|
|
68
|
+
function toggleTracking(value) {
|
|
69
|
+
optedOut = value;
|
|
70
|
+
if (optedOut) {
|
|
71
|
+
console.log("[Tracking] User opted out");
|
|
72
|
+
setTrackingPreference("disable");
|
|
73
|
+
} else {
|
|
74
|
+
console.log("[Tracking] User cleared opt-out");
|
|
75
|
+
clearTrackingPreferences();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Toggle tracking opt-in.
|
|
81
|
+
* @param {boolean} value
|
|
82
|
+
*/
|
|
83
|
+
function toggleOptIn(value) {
|
|
84
|
+
optedIn = value;
|
|
85
|
+
if (optedIn) {
|
|
86
|
+
console.log("[Tracking] User opted in");
|
|
87
|
+
setTrackingPreference("enable");
|
|
88
|
+
} else {
|
|
89
|
+
console.log("[Tracking] User cleared opt-in");
|
|
90
|
+
clearTrackingPreferences();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<section id="top">
|
|
96
|
+
<span class={constants.classSmall}>
|
|
97
|
+
<a
|
|
98
|
+
rel={constants.rel}
|
|
99
|
+
href="https://spdx.dev/learn/handling-license-info"
|
|
100
|
+
target={constants.targetBlank}>
|
|
101
|
+
SPDX License Identifier
|
|
102
|
+
</a>: <code>CC-BY-4.0 OR GPL-3.0-or-later</code>
|
|
103
|
+
</span>
|
|
104
|
+
</section>
|
|
105
|
+
|
|
106
|
+
<h1>Privacy Dashboard</h1>
|
|
107
|
+
|
|
108
|
+
<div class={spaceStyle}></div>
|
|
109
|
+
|
|
110
|
+
<h2>Take Control of Your Data</h2>
|
|
111
|
+
|
|
112
|
+
<nav class="tracking-nav">
|
|
113
|
+
<ul>
|
|
114
|
+
<li
|
|
115
|
+
><a href="#tracking" target={constants.targetSelf}>Tracking Preferences</a
|
|
116
|
+
></li>
|
|
117
|
+
<li
|
|
118
|
+
><a href="#rights" target={constants.targetSelf}
|
|
119
|
+
>Your Rights and Choices</a
|
|
120
|
+
></li>
|
|
121
|
+
</ul>
|
|
122
|
+
</nav>
|
|
123
|
+
|
|
124
|
+
<p class="bquote">
|
|
125
|
+
For full details, please see our <a href={privacyPolicy} target="_self"
|
|
126
|
+
>Privacy Policy</a
|
|
127
|
+
>.
|
|
128
|
+
</p>
|
|
129
|
+
|
|
130
|
+
<div class={spaceStyle}></div>
|
|
131
|
+
|
|
132
|
+
<hr />
|
|
133
|
+
|
|
134
|
+
<div class={spaceStyle}></div>
|
|
135
|
+
|
|
136
|
+
<section id="tracking">
|
|
137
|
+
<h3>Tracking Preferences</h3>
|
|
138
|
+
|
|
139
|
+
<p>
|
|
140
|
+
<strong
|
|
141
|
+
>Analytics tracking is automatically disabled when a user's browser sends
|
|
142
|
+
a “Do Not Track” (DNT) or <a
|
|
143
|
+
rel={constants.rel}
|
|
144
|
+
href="https://globalprivacycontrol.org/"
|
|
145
|
+
target={constants.targetBlank}
|
|
146
|
+
>“Global Privacy Control” (GPC / Sec-GPC)</a> signal.</strong>
|
|
147
|
+
No further action is required—your browser settings are honored by default.
|
|
148
|
+
</p>
|
|
149
|
+
|
|
150
|
+
<p>
|
|
151
|
+
You can view your current tracking status below, along with manual opt-out
|
|
152
|
+
and opt-in settings stored as browser cookies. These settings override any
|
|
153
|
+
Do Not Track (DNT) or Global Privacy Control (GPC) signals. <strong
|
|
154
|
+
>If you opt out, analytics tracking via PostHog is disabled entirely until
|
|
155
|
+
you change your preference.</strong> Your selection will persist until manually
|
|
156
|
+
updated.
|
|
157
|
+
</p>
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
<p id="tracking-status" aria-live="polite">
|
|
162
|
+
<strong>Tracking Status:</strong>
|
|
163
|
+
{trackingStatus}
|
|
164
|
+
</p>
|
|
165
|
+
|
|
166
|
+
<!-- Opt-out checkbox -->
|
|
167
|
+
<label>
|
|
168
|
+
<input
|
|
169
|
+
type="checkbox"
|
|
170
|
+
checked={optedOut}
|
|
171
|
+
disabled={optedIn}
|
|
172
|
+
aria-describedby="tracking-status"
|
|
173
|
+
on:change={(e) =>
|
|
174
|
+
toggleTracking(/** @type {HTMLInputElement} */ (e.target).checked)} />
|
|
175
|
+
<strong> Disable analytics tracking (opt-out)</strong>
|
|
176
|
+
</label>
|
|
177
|
+
|
|
178
|
+
<br />
|
|
179
|
+
|
|
180
|
+
<!-- Opt-in checkbox -->
|
|
181
|
+
<label>
|
|
182
|
+
<input
|
|
183
|
+
type="checkbox"
|
|
184
|
+
checked={optedIn}
|
|
185
|
+
disabled={optedOut}
|
|
186
|
+
aria-describedby="tracking-status"
|
|
187
|
+
on:change={(e) =>
|
|
188
|
+
toggleOptIn(/** @type {HTMLInputElement} */ (e.target).checked)} />
|
|
189
|
+
<strong> Enable analytics tracking (opt-in)</strong>
|
|
190
|
+
</label>
|
|
191
|
+
|
|
192
|
+
<div class={spaceStyle}></div>
|
|
193
|
+
|
|
194
|
+
<p>
|
|
195
|
+
Analytics are used to understand how the site is used. No personally
|
|
196
|
+
identifiable information is tracked.
|
|
197
|
+
</p>
|
|
198
|
+
</section>
|
|
199
|
+
|
|
200
|
+
<span class={constants.classSmall}>
|
|
201
|
+
<a href={constants.hrefTop} target={constants.targetSelf}
|
|
202
|
+
>{constants.backTop}</a>
|
|
203
|
+
</span>
|
|
204
|
+
|
|
205
|
+
<div class={spaceStyle}></div>
|
|
206
|
+
|
|
207
|
+
<hr class="hr-styled" />
|
|
208
|
+
|
|
209
|
+
<div class={spaceStyle}></div>
|
|
210
|
+
|
|
211
|
+
<section id="rights">
|
|
212
|
+
<h3>Your Rights and Choices</h3>
|
|
213
|
+
|
|
214
|
+
<p> Under applicable state and federal law, you may have rights to: </p>
|
|
215
|
+
|
|
216
|
+
<ul>
|
|
217
|
+
<li
|
|
218
|
+
><strong>Access, update, or delete</strong> your personal information, subject
|
|
219
|
+
to legal and contractual limitations.</li>
|
|
220
|
+
<li
|
|
221
|
+
><strong>Restrict or object to processing</strong> under certain conditions,
|
|
222
|
+
as permitted by law.</li>
|
|
223
|
+
<li><strong>Opt out of direct marketing</strong></li>
|
|
224
|
+
</ul>
|
|
225
|
+
|
|
226
|
+
<p>
|
|
227
|
+
To exercise these rights, please use our <a
|
|
228
|
+
rel={constants.rel}
|
|
229
|
+
href={prightsLink}
|
|
230
|
+
target={constants.targetBlank}>Privacy Rights Request Form</a>
|
|
231
|
+
or email us at <code>contact (at) s.neteng.pro</code>.
|
|
232
|
+
</p>
|
|
233
|
+
</section>
|
|
234
|
+
|
|
235
|
+
<span class={constants.classSmall}>
|
|
236
|
+
<a href={constants.hrefTop} target={constants.targetSelf}
|
|
237
|
+
>{constants.backTop}</a>
|
|
238
|
+
</span>
|
|
239
|
+
|
|
240
|
+
<!-- cspell:ignore prefs prights -->
|
|
@@ -26,6 +26,12 @@ This file is part of Network Pro.
|
|
|
26
26
|
max-width: 1200px;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/* Constrain paragraph/text-heavy content to 900px */
|
|
30
|
+
.readable {
|
|
31
|
+
margin: 0 auto;
|
|
32
|
+
max-width: 900px;
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
/* Header & Footer follow the same container width */
|
|
30
36
|
header,
|
|
31
37
|
footer {
|
|
@@ -168,26 +174,21 @@ footer .container {
|
|
|
168
174
|
|
|
169
175
|
.bnav {
|
|
170
176
|
margin: 0 auto;
|
|
177
|
+
text-align: center;
|
|
171
178
|
border-collapse: collapse;
|
|
172
179
|
border-spacing: 0;
|
|
173
180
|
}
|
|
174
181
|
|
|
175
|
-
.bnav td
|
|
176
|
-
padding: 10px;
|
|
177
|
-
font-size: 0.875rem;
|
|
178
|
-
font-weight: bold;
|
|
179
|
-
line-height: 1.125rem;
|
|
180
|
-
border-style: none;
|
|
181
|
-
overflow: hidden;
|
|
182
|
-
word-break: normal;
|
|
183
|
-
}
|
|
184
|
-
|
|
182
|
+
.bnav td,
|
|
185
183
|
.bnav th {
|
|
186
184
|
padding: 10px;
|
|
187
185
|
font-size: 0.875rem;
|
|
186
|
+
font-weight: bold; /* Only needed for <td>, if desired */
|
|
188
187
|
line-height: 1.125rem;
|
|
188
|
+
text-align: center; /* Center horizontally */
|
|
189
189
|
border-style: none;
|
|
190
190
|
overflow: hidden;
|
|
191
|
+
vertical-align: middle; /* Center vertically */
|
|
191
192
|
word-break: normal;
|
|
192
193
|
}
|
|
193
194
|
|
|
@@ -377,6 +378,18 @@ footer .container {
|
|
|
377
378
|
font-variant: small-caps;
|
|
378
379
|
}
|
|
379
380
|
|
|
381
|
+
.bold {
|
|
382
|
+
font-weight: bold;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.emphasis {
|
|
386
|
+
font-style: italic;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.uline {
|
|
390
|
+
text-decoration: underline;
|
|
391
|
+
}
|
|
392
|
+
|
|
380
393
|
.bolditalic {
|
|
381
394
|
font-weight: bold;
|
|
382
395
|
font-style: italic;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/*! ==========================================================================
|
|
2
|
-
src/lib/styles/css/global.min.css
|
|
3
|
-
|
|
4
2
|
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
3
|
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
6
4
|
This file is part of Network Pro.
|
|
7
5
|
========================================================================== */
|
|
8
|
-
html{-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{margin:.67em 0;font-size:2em}hr{box-sizing:content-box}pre{font-family:monospace;font-size:1em}a{background-color:#0000}abbr[title]{border-bottom:none;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:100%;line-height:1.15}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted buttontext}fieldset{padding:.35em .75em .625em}legend{color:inherit;box-sizing:border-box;white-space:normal;max-width:100%;padding:0;display:table}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}details{display:block}summary{display:list-item}template{display:none}html{color:#222;scroll-behavior:smooth;font-size:1em;line-height:1.4}::-moz-selection{text-shadow:none;background:#191919}::selection{text-shadow:none;background:#191919}hr{border:0;border-top:1px solid #ccc;height:1px;margin:1em 0;padding:0;display:block;overflow:visible}audio,canvas,iframe,img,svg,video{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}body{color:#fafafa;background-color:#191919;margin:10px;font-family:Arial,Helvetica,sans-serif}a{text-decoration:none}a:link{color:#ffc627}a:hover,a:active{color:#ffc627;text-decoration:underline}a:focus{color:#191919;background-color:#ffc627}a:visited,a:visited:hover{color:#7f6227}.hidden,[hidden]{display:none!important}.visually-hidden{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.visually-hidden.focusable:active,.visually-hidden.focusable:focus{clip:auto;width:auto;height:auto;white-space:inherit;margin:0;position:static;overflow:visible}.invisible{visibility:hidden}.clearfix:before,.clearfix:after{content:"";display:table}.clearfix:after{clear:both}@media print{*,:before,:after{color:#000!important;box-shadow:none!important;text-shadow:none!important;background:#fff!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^=\#]:after,a[href^=javascript\:]:after{content:""}pre{white-space:pre-wrap!important}pre,blockquote{page-break-inside:avoid;border:1px solid #999}tr,img{page-break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.full-width-section{background-position:50%;background-size:cover;width:100%;max-width:1920px;margin:0 auto}.container{max-width:1200px;margin:0 auto;padding:0 12px}header,footer{width:100%}header .container,footer .container{max-width:1200px;margin:0 auto;padding:20px 12px}.gh{border-collapse:collapse;border-spacing:0;margin:0 auto}.gh td,.gh th{border-collapse:collapse;word-break:normal;padding:10px 5px;overflow:hidden}.gh .gh-tcell{text-align:center;vertical-align:middle}@media screen and (width<=767px){.gh,.gh col{width:auto!important}.gh-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.soc{border-collapse:collapse;border-spacing:0;margin:0 auto}.soc td,.soc th{border-collapse:collapse;word-break:normal;padding:8px;overflow:hidden}.soc .soc-fa{text-align:center;vertical-align:middle}@media screen and (width<=767px){.soc,.soc col{width:auto!important}.soc-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.foss{border-collapse:collapse;border-spacing:0}.foss td,.foss th{border-collapse:collapse;word-break:normal;padding:10px 5px;overflow:hidden}.foss .foss-cell{text-align:center;vertical-align:middle}@media screen and (width<=767px){.foss,.foss col{width:auto!important}.foss-wrap{-webkit-overflow-scrolling:touch;overflow-x:auto}}.bnav{border-collapse:collapse;border-spacing:0;margin:0 auto}.bnav td{word-break:normal;border-style:none;padding:10px;font-size:.875rem;font-weight:700;line-height:1.125rem;overflow:hidden}.bnav
|
|
6
|
+
html{-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{margin:.67em 0;font-size:2em}hr{box-sizing:content-box}pre{font-family:monospace;font-size:1em}a{background-color:#0000}abbr[title]{border-bottom:none;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:100%;line-height:1.15}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted buttontext}fieldset{padding:.35em .75em .625em}legend{color:inherit;box-sizing:border-box;white-space:normal;max-width:100%;padding:0;display:table}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}details{display:block}summary{display:list-item}template{display:none}html{color:#222;scroll-behavior:smooth;font-size:1em;line-height:1.4}::-moz-selection{text-shadow:none;background:#191919}::selection{text-shadow:none;background:#191919}hr{border:0;border-top:1px solid #ccc;height:1px;margin:1em 0;padding:0;display:block;overflow:visible}audio,canvas,iframe,img,svg,video{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}body{color:#fafafa;background-color:#191919;margin:10px;font-family:Arial,Helvetica,sans-serif}a{text-decoration:none}a:link{color:#ffc627}a:hover,a:active{color:#ffc627;text-decoration:underline}a:focus{color:#191919;background-color:#ffc627}a:visited,a:visited:hover{color:#7f6227}.hidden,[hidden]{display:none!important}.visually-hidden{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.visually-hidden.focusable:active,.visually-hidden.focusable:focus{clip:auto;width:auto;height:auto;white-space:inherit;margin:0;position:static;overflow:visible}.invisible{visibility:hidden}.clearfix:before,.clearfix:after{content:"";display:table}.clearfix:after{clear:both}@media print{*,:before,:after{color:#000!important;box-shadow:none!important;text-shadow:none!important;background:#fff!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^=\#]:after,a[href^=javascript\:]:after{content:""}pre{white-space:pre-wrap!important}pre,blockquote{page-break-inside:avoid;border:1px solid #999}tr,img{page-break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.full-width-section{background-position:50%;background-size:cover;width:100%;max-width:1920px;margin:0 auto}.container{max-width:1200px;margin:0 auto;padding:0 12px}.readable{max-width:900px;margin:0 auto}header,footer{width:100%}header .container,footer .container{max-width:1200px;margin:0 auto;padding:20px 12px}.gh{border-collapse:collapse;border-spacing:0;margin:0 auto}.gh td,.gh th{border-collapse:collapse;word-break:normal;padding:10px 5px;overflow:hidden}.gh .gh-tcell{text-align:center;vertical-align:middle}@media screen and (width<=767px){.gh,.gh col{width:auto!important}.gh-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.soc{border-collapse:collapse;border-spacing:0;margin:0 auto}.soc td,.soc th{border-collapse:collapse;word-break:normal;padding:8px;overflow:hidden}.soc .soc-fa{text-align:center;vertical-align:middle}@media screen and (width<=767px){.soc,.soc col{width:auto!important}.soc-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.foss{border-collapse:collapse;border-spacing:0}.foss td,.foss th{border-collapse:collapse;word-break:normal;padding:10px 5px;overflow:hidden}.foss .foss-cell{text-align:center;vertical-align:middle}@media screen and (width<=767px){.foss,.foss col{width:auto!important}.foss-wrap{-webkit-overflow-scrolling:touch;overflow-x:auto}}.bnav{text-align:center;border-collapse:collapse;border-spacing:0;margin:0 auto}.bnav td,.bnav th{text-align:center;vertical-align:middle;word-break:normal;border-style:none;padding:10px;font-size:.875rem;font-weight:700;line-height:1.125rem;overflow:hidden}.bnav .bnav-cell{text-align:center;vertical-align:middle;align-content:center}@media screen and (width<=767px){.bnav,.bnav col{width:auto!important}.bnav-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.bnav2{border-collapse:collapse;border-spacing:0;margin:0 auto}.bnav2 td{word-break:normal;border-style:none;padding:10px;font-size:.875rem;font-weight:700;line-height:1.125rem;overflow:hidden}.bnav2 th{word-break:normal;border-style:none;padding:12px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.bnav2 .bnav2-cell{text-align:center;vertical-align:middle;align-content:center}@media screen and (width<=767px){.bnav2,.bnav2 col{width:auto!important}.bnav2-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.pgp{border-collapse:collapse;border-spacing:0;margin:0 auto}.pgp td{word-break:normal;border-style:none;padding:10px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.pgp th{word-break:normal;border:1px solid #000;padding:10px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.pgp .pgp-col1{text-align:right;vertical-align:middle;padding-right:1rem}.pgp .pgp-col2{text-align:left;vertical-align:middle;padding-left:1rem}@media screen and (width<=767px){.pgp,.pgp col{width:auto!important}.pgp-wrap{-webkit-overflow-scrolling:touch;margin:2rem 0 auto;overflow-x:auto}}.logo{margin-left:auto;margin-right:auto;display:block}.index-title1{text-align:center;font-style:italic;font-weight:700}.index-title2{letter-spacing:-.015em;text-align:center;font-variant:small-caps;font-size:1.25rem;line-height:1.625rem}.index1{letter-spacing:-.035em;text-align:center;font-style:italic;font-weight:700;line-height:2.125rem}.index2{letter-spacing:-.035em;text-align:center;font-variant:small-caps;font-size:1.5rem;line-height:1.75rem}.index3{letter-spacing:-.035em;text-align:center;font-size:1.5rem;line-height:1.75rem}.index4{letter-spacing:-.035em;text-align:center;font-size:1.5rem;line-height:1.75rem;text-decoration:underline}.subhead{letter-spacing:-.035em;font-variant:small-caps;font-size:1.5rem;line-height:1.75rem}.bold{font-weight:700}.emphasis{font-style:italic}.uline{text-decoration:underline}.bolditalic{font-style:italic;font-weight:700}.bquote{border-left:3px solid #9e9e9e;margin-left:30px;padding-left:10px;font-style:italic}.small-text{font-size:.75rem;line-height:1.125rem}.large-text-center{text-align:center;font-size:1.25rem;line-height:1.75rem}.prewrap{white-space:pre-wrap;display:block}.hr-styled{width:75%;margin:auto}.center-text{text-align:center}.copyright{text-align:center;font-size:.75rem;line-height:1.125rem}.visited{color:#7f6227}.center-nav{text-align:center;padding:5px;font-size:.875rem;line-height:1.125rem}.block{resize:none;background:0 0;border:none;border-radius:0;outline:none;width:100%;font-size:.75rem;line-height:1.125rem}.fingerprint{white-space:pre-line;font-weight:700;display:block}.pgp-image{width:125px;height:125px}.spacer{margin:2rem 0}.separator{margin:0 .5rem}
|
package/src/lib/utils/privacy.js
CHANGED
|
@@ -7,17 +7,32 @@ This file is part of Network Pro.
|
|
|
7
7
|
========================================================================== */
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* @file privacy.js
|
|
11
|
+
* @description Determines whether the user allows tracking based on DNT, GPC, or manual opt-out.
|
|
12
|
+
* @module src/lib/utils/
|
|
13
|
+
* @author SunDevil311
|
|
14
|
+
* @updated 2025-05-28
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
11
18
|
* @returns {boolean}
|
|
12
19
|
*/
|
|
13
20
|
export function shouldTrackUser() {
|
|
14
|
-
/** @type {string | undefined} */
|
|
15
21
|
const windowDNT = /** @type {any} */ (window).doNotTrack;
|
|
16
|
-
/** @type {boolean | undefined} */
|
|
17
22
|
const navigatorGPC = /** @type {any} */ (navigator).globalPrivacyControl;
|
|
18
23
|
|
|
19
24
|
const dnt = navigator.doNotTrack === "1" || windowDNT === "1";
|
|
20
25
|
const gpc = navigatorGPC === true;
|
|
21
26
|
|
|
27
|
+
const manualOptOut = document.cookie.includes("disable_tracking=true");
|
|
28
|
+
const manualOptIn = document.cookie.includes("enable_tracking=true");
|
|
29
|
+
|
|
30
|
+
console.log("[Privacy] Opt-in cookie present:", manualOptIn);
|
|
31
|
+
console.log("[Privacy] Opt-out cookie present:", manualOptOut);
|
|
32
|
+
|
|
33
|
+
// Opt-in overrides everything; opt-out disables regardless of DNT/GPC
|
|
34
|
+
if (manualOptIn) return true;
|
|
35
|
+
if (manualOptOut) return false;
|
|
36
|
+
|
|
22
37
|
return !dnt && !gpc;
|
|
23
38
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
src/lib/utils/trackingCookies.js
|
|
3
|
+
|
|
4
|
+
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
|
+
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
6
|
+
This file is part of Network Pro.
|
|
7
|
+
========================================================================== */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @file trackingCookies.js
|
|
11
|
+
* @description Handles setting, clearing, and toggling tracking preference cookies.
|
|
12
|
+
* @module src/lib/utils/
|
|
13
|
+
* @author SunDevil311
|
|
14
|
+
* @updated 2025-05-28
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Set a tracking preference cookie.
|
|
19
|
+
* @param {"enable" | "disable"} type
|
|
20
|
+
*/
|
|
21
|
+
export function setTrackingPreference(type) {
|
|
22
|
+
const maxAge = 60 * 60 * 24 * 365 * 10; // 10 years
|
|
23
|
+
const cookieSettings = `path=/; max-age=${maxAge}; SameSite=Lax`;
|
|
24
|
+
|
|
25
|
+
if (type === "enable") {
|
|
26
|
+
document.cookie = `enable_tracking=true; ${cookieSettings}`;
|
|
27
|
+
document.cookie = `disable_tracking=; path=/; max-age=0; SameSite=Lax`;
|
|
28
|
+
} else if (type === "disable") {
|
|
29
|
+
document.cookie = `disable_tracking=true; ${cookieSettings}`;
|
|
30
|
+
document.cookie = `enable_tracking=; path=/; max-age=0; SameSite=Lax`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Clear both tracking cookies.
|
|
36
|
+
*/
|
|
37
|
+
export function clearTrackingPreferences() {
|
|
38
|
+
document.cookie = `enable_tracking=; path=/; max-age=0; SameSite=Lax`;
|
|
39
|
+
document.cookie = `disable_tracking=; path=/; max-age=0; SameSite=Lax`;
|
|
40
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
src/lib/utils/trackingStatus.js
|
|
3
|
+
|
|
4
|
+
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
|
+
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
6
|
+
This file is part of Network Pro.
|
|
7
|
+
========================================================================== */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @file trackingStatus.js
|
|
11
|
+
* @description Get tracking preferences based on cookies and browser privacy signals.
|
|
12
|
+
* @module src/lib/utils/
|
|
13
|
+
* @author SunDevil311
|
|
14
|
+
* @updated 2025-05-28
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @returns {{
|
|
19
|
+
* optedOut: boolean,
|
|
20
|
+
* optedIn: boolean,
|
|
21
|
+
* dnt: boolean,
|
|
22
|
+
* gpc: boolean,
|
|
23
|
+
* status: string
|
|
24
|
+
* }}
|
|
25
|
+
*/
|
|
26
|
+
export function getTrackingPreferences() {
|
|
27
|
+
const cookies = document.cookie;
|
|
28
|
+
const optedOut = cookies.includes("disable_tracking=true");
|
|
29
|
+
const optedIn = cookies.includes("enable_tracking=true");
|
|
30
|
+
const dnt = navigator.doNotTrack === "1";
|
|
31
|
+
|
|
32
|
+
// @ts-expect-error: 'globalPrivacyControl' is a non-standard property
|
|
33
|
+
const gpc = navigator.globalPrivacyControl === true;
|
|
34
|
+
|
|
35
|
+
let status = "⚙️ Using default settings (tracking enabled)";
|
|
36
|
+
|
|
37
|
+
if (optedOut) {
|
|
38
|
+
status = "🔒 Tracking disabled (manual opt-out)";
|
|
39
|
+
} else if (optedIn) {
|
|
40
|
+
status = "✅ Tracking enabled (manual opt-in)";
|
|
41
|
+
} else if (dnt || gpc) {
|
|
42
|
+
status = "🛑 Tracking disabled (via browser signal)";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { optedOut, optedIn, dnt, gpc, status };
|
|
46
|
+
}
|
package/src/lib/utils/utm.js
CHANGED
|
@@ -7,7 +7,14 @@ This file is part of Network Pro.
|
|
|
7
7
|
========================================================================== */
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* @file utm.js
|
|
11
|
+
* @description Append UTM parameter from window.location to a given URL.
|
|
12
|
+
* @module src/lib/utils/
|
|
13
|
+
* @author SunDevil311
|
|
14
|
+
* @updated 2025-05-28
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
11
18
|
* Returns `null` if not in a browser context.
|
|
12
19
|
* @param {string} url - The base URL to append to
|
|
13
20
|
* @returns {string | null}
|
|
@@ -14,12 +14,6 @@ This file is part of Network Pro.
|
|
|
14
14
|
import SocialMedia from "$lib/components/SocialMedia.svelte";
|
|
15
15
|
import MetaTags from "$lib/components/MetaTags.svelte";
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* @type {string}
|
|
19
|
-
* Style class for the horizontal rule element.
|
|
20
|
-
*/
|
|
21
|
-
const hrStyle = "hr-styled";
|
|
22
|
-
|
|
23
17
|
/**
|
|
24
18
|
* @type {string}
|
|
25
19
|
* Style class for the div element.
|
|
@@ -48,7 +42,7 @@ This file is part of Network Pro.
|
|
|
48
42
|
<SocialMedia />
|
|
49
43
|
</section>
|
|
50
44
|
|
|
51
|
-
<hr
|
|
45
|
+
<hr />
|
|
52
46
|
|
|
53
47
|
<div class={spaceStyle}></div>
|
|
54
48
|
|
|
@@ -14,12 +14,6 @@ This file is part of Network Pro.
|
|
|
14
14
|
import SocialMedia from "$lib/components/SocialMedia.svelte";
|
|
15
15
|
import MetaTags from "$lib/components/MetaTags.svelte";
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* @type {string}
|
|
19
|
-
* Style class for the horizontal rule element.
|
|
20
|
-
*/
|
|
21
|
-
const hrStyle = "hr-styled";
|
|
22
|
-
|
|
23
17
|
/**
|
|
24
18
|
* @type {string}
|
|
25
19
|
* Style class for the div element.
|
|
@@ -49,7 +43,7 @@ This file is part of Network Pro.
|
|
|
49
43
|
</section>
|
|
50
44
|
<!-- END SOCIAL MEDIA -->
|
|
51
45
|
|
|
52
|
-
<hr
|
|
46
|
+
<hr />
|
|
53
47
|
|
|
54
48
|
<div class={spaceStyle}></div>
|
|
55
49
|
|
|
@@ -14,12 +14,6 @@ This file is part of Network Pro.
|
|
|
14
14
|
import SocialMedia from "$lib/components/SocialMedia.svelte";
|
|
15
15
|
import MetaTags from "$lib/components/MetaTags.svelte";
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* @type {string}
|
|
19
|
-
* Style class for the horizontal rule element.
|
|
20
|
-
*/
|
|
21
|
-
const hrStyle = "hr-styled";
|
|
22
|
-
|
|
23
17
|
/**
|
|
24
18
|
* @type {string}
|
|
25
19
|
* Style class for the div element.
|
|
@@ -34,7 +28,7 @@ This file is part of Network Pro.
|
|
|
34
28
|
<link rel="canonical" href="https://netwk.pro/license" />
|
|
35
29
|
|
|
36
30
|
<section id="license">
|
|
37
|
-
<FullWidthSection>
|
|
31
|
+
<FullWidthSection containerClass="readable">
|
|
38
32
|
<!-- BEGIN LEGAL, COPYRIGHT, AND LICENSING -->
|
|
39
33
|
<section id="main-content">
|
|
40
34
|
<LicenseContent />
|
|
@@ -49,7 +43,7 @@ This file is part of Network Pro.
|
|
|
49
43
|
</section>
|
|
50
44
|
<!-- END SOCIAL MEDIA -->
|
|
51
45
|
|
|
52
|
-
<hr
|
|
46
|
+
<hr />
|
|
53
47
|
|
|
54
48
|
<div class={spaceStyle}></div>
|
|
55
49
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
src/routes/privacy/+page.server.js
|
|
3
|
+
|
|
4
|
+
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
|
+
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
6
|
+
This file is part of Network Pro.
|
|
7
|
+
========================================================================== */
|
|
8
|
+
|
|
9
|
+
import { defaultMeta, meta } from "$lib/meta.js";
|
|
10
|
+
|
|
11
|
+
export const prerender = false;
|
|
12
|
+
|
|
13
|
+
/** @type {import('./$types').PageServerLoad} */
|
|
14
|
+
export function load() {
|
|
15
|
+
return {
|
|
16
|
+
meta: meta["/privacy"] || defaultMeta,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- ==========================================================================
|
|
2
|
-
src/routes/privacy
|
|
2
|
+
src/routes/privacy/+page.svelte
|
|
3
3
|
|
|
4
4
|
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
5
|
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
@@ -14,12 +14,6 @@ This file is part of Network Pro.
|
|
|
14
14
|
import SocialMedia from "$lib/components/SocialMedia.svelte";
|
|
15
15
|
import MetaTags from "$lib/components/MetaTags.svelte";
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* @type {string}
|
|
19
|
-
* Style class for the horizontal rule element.
|
|
20
|
-
*/
|
|
21
|
-
const hrStyle = "hr-styled";
|
|
22
|
-
|
|
23
17
|
/**
|
|
24
18
|
* @type {string}
|
|
25
19
|
* Style class for the div element.
|
|
@@ -31,10 +25,10 @@ This file is part of Network Pro.
|
|
|
31
25
|
|
|
32
26
|
<MetaTags title={data.meta.title} description={data.meta.description} />
|
|
33
27
|
|
|
34
|
-
<link rel="canonical" href="https://netwk.pro/privacy
|
|
28
|
+
<link rel="canonical" href="https://netwk.pro/privacy" />
|
|
35
29
|
|
|
36
|
-
<section id="privacy
|
|
37
|
-
<FullWidthSection>
|
|
30
|
+
<section id="privacy">
|
|
31
|
+
<FullWidthSection containerClass="readable">
|
|
38
32
|
<!-- BEGIN PRIVACY POLICY -->
|
|
39
33
|
<section id="main-content">
|
|
40
34
|
<PrivacyContent />
|
|
@@ -49,7 +43,7 @@ This file is part of Network Pro.
|
|
|
49
43
|
</section>
|
|
50
44
|
<!-- END SOCIAL MEDIA -->
|
|
51
45
|
|
|
52
|
-
<hr
|
|
46
|
+
<hr />
|
|
53
47
|
|
|
54
48
|
<div class={spaceStyle}></div>
|
|
55
49
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* ==========================================================================
|
|
2
|
-
src/routes/privacy
|
|
2
|
+
src/routes/privacy/+page.server.js
|
|
3
3
|
|
|
4
4
|
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
5
|
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
@@ -13,6 +13,6 @@ export const prerender = false;
|
|
|
13
13
|
/** @type {import('./$types').PageServerLoad} */
|
|
14
14
|
export function load() {
|
|
15
15
|
return {
|
|
16
|
-
meta: meta["/privacy-
|
|
16
|
+
meta: meta["/privacy-dashboard"] || defaultMeta,
|
|
17
17
|
};
|
|
18
18
|
}
|