@networkpro/web 1.18.4 → 1.19.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 CHANGED
@@ -22,11 +22,71 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
22
22
 
23
23
  ---
24
24
 
25
- ## [1.18.4] - 2025-10-04
25
+ ## [1.19.0] - 2025-10-06
26
+
27
+ ### Added
28
+
29
+ - **`src/lib/components/index.js`**, **`src/lib/components/foss/index.js`**, **`src/lib/components/layout/index.js`**
30
+ - Introduced explicit component export modules to improve import consistency across the library.
31
+ - Added wildcard exports in `src/lib/index.js` for these component modules, enabling `$lib/components/...` shorthand imports.
32
+ - **`tests/unit/client/lib/PWAInstallButton.test.js`**
33
+ - Added focused unit tests for `PWAInstallButton.svelte` verifying install-event handling and user-prompt logic using `Vitest` and `@testing-library/svelte`.
34
+ - **`src/lib/README.md`**, **`src/lib/types/README.md`**
35
+ - Added contextual documentation for the library and type definition directories.
36
+ - Clarifies module structure, export hierarchy, and intended usage for contributors.
37
+
38
+ ### Changed
39
+
40
+ - Bumped project version to `v1.19.0`.
41
+ - Updated `src/lib/pages/AboutContent.svelte` with new services
42
+ - Added DOM and animation mocks (`window.matchMedia`, `Element.prototype.animate`) to `vitest-setup-client.js` to stabilize component transition tests.
43
+ - Updated `src/lib/index.js` to export all component and utility submodules explicitly, replacing previous implicit import behavior.
44
+ - Centralized page-level component exports in `src/lib/pages/index.js` for consistent import structure.
45
+ - Updated `src/routes/+layout.svelte` to import objects from submodules, instead of by their explicit alias
46
+ - Minor alignment in `src/routes/+page.svelte` and `src/routes/links/+page.svelte` with updated component imports
47
+ - Moved inline CSS fom `src/lib/components/FullWidthSection.svelte` into `src/lib/styles/css/default.css`
48
+ - Generated an updated `src/lib/styles/global.min.css` file with LightningCSS
49
+ - Updated `.gitignore` to remove duplicate `.vercel` entry
50
+ - Updated last modified dates in `static/sitemap.xml`
51
+ - Updated dependencies:
52
+ - `eslint-plugin-jsdoc` `^60.8.1` → `^60.8.2`
53
+ - `posthog-js` `^1.270.1` → `^1.271.0`
54
+ - `svelte` `5.39.8` → `5.39.9`
55
+
56
+ ---
57
+
58
+ ## [1.18.5] - 2025-10-05
59
+
60
+ ### Added
61
+
62
+ - Added Vercel CLI scripts to `package.json`, including `dev:vercel` and `build:vercel`.
63
+
64
+ ### Changed
65
+
66
+ - Bumped project version to `v1.18.5`.
67
+ - Updated generator metadata in `app.html` to reflect `SvelteKit 2.44.0`.
68
+ - Added `scripts/testRedirects.js` to `.gitignore`.
69
+ - Cleaned up header in `jsconfig.template.jsonc`.
70
+ - Updated **Repository Structure** section in `README.md`.
71
+ - Restructured `CHANGELOG.md` such that sections are presented in alphabetical order.
72
+ - Corrected JSDoc annotations in `static/disableSw.js`.
73
+ - Updated dependencies:
74
+ - `@sveltejs/kit` `2.43.8` → `2.44.0`
75
+ - `eslint-plugin-jsdoc` `^60.8.0` → `^60.8.1`
26
76
 
27
77
  ### Documentation
28
78
 
29
- - Updated **Repository Structure** to reflect current environment and files.
79
+ - Revised **Repository Structure** to accurately reflect the folders under `/tests`.
80
+
81
+ ### Removed
82
+
83
+ - Removed all references to Netlify and all Netlify-specific scripts from `package.json`.
84
+ - Removed `test:redirects` script from `package.json`.
85
+ - The `testRedirects.js` script has been removed from version control, as it is no longer needed to test Netlify redirects.
86
+
87
+ ---
88
+
89
+ ## [1.18.4] - 2025-10-04
30
90
 
31
91
  ### Changes
32
92
 
@@ -53,6 +113,10 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
53
113
  - `typescript` `^5.9.2` → `^5.9.3`
54
114
  - `vite` `^7.1.7` → `^7.1.9`
55
115
 
116
+ ### Documentation
117
+
118
+ - Updated **Repository Structure** to reflect current environment and files.
119
+
56
120
  ---
57
121
 
58
122
  ## [1.18.3] - 2025-09-27
@@ -164,31 +228,20 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
164
228
 
165
229
  ## [1.17.1] - 2025-09-17
166
230
 
231
+ ### Changed
232
+
233
+ - Bumped version to `v1.17.1`.
234
+
167
235
  ### Security
168
236
 
169
237
  - Patched transitive vulnerabilities by pinning dependencies via `overrides`:
170
238
  - Forced `tmp` to `>=0.2.4` (resolves CVE-2025-54798 reported via `@lhci/cli`).
171
239
  - Forced `cookie` to `^1.0.0` (used by `@sveltejs/kit` and `@lhci/cli`).
172
240
 
173
- ### Changed
174
-
175
- - Bumped version to `v1.17.1`.
176
-
177
241
  ---
178
242
 
179
243
  ## [1.17.0] - 2025-09-17
180
244
 
181
- ### Security
182
-
183
- - Updated dependencies to address known vulnerabilities (notably `@sveltejs/kit`, `vite`, and related plugins).
184
-
185
- ### Documentation
186
-
187
- - Clarified CSP reporting setup in `README.md`:
188
- - Explained relationship with external CSP reporting endpoint (`csp-endpoint` repo).
189
- - Documented use of both `report-uri` (legacy) and `report-to` (modern, recommended).
190
- - Added example headers including `Report-To` definition.
191
-
192
245
  ### Added
193
246
 
194
247
  - New `meta-check.yml` GitHub Actions workflow to validate `<title>` and `<meta>` descriptions using Vitest.
@@ -236,11 +289,22 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
236
289
  - `svelte-eslint-parser` `^1.3.0` → `^1.3.2`
237
290
  - `vite` `^7.0.6` → `^7.1.5`
238
291
 
292
+ ### Documentation
293
+
294
+ - Clarified CSP reporting setup in `README.md`:
295
+ - Explained relationship with external CSP reporting endpoint (`csp-endpoint` repo).
296
+ - Documented use of both `report-uri` (legacy) and `report-to` (modern, recommended).
297
+ - Added example headers including `Report-To` definition.
298
+
239
299
  ### Removed
240
300
 
241
301
  - Deleted `src/routes/example.svx`, which was unused and unneeded.
242
302
  - Removed `mdsvex` from package.json, as it is unlikely to be used.
243
303
 
304
+ ### Security
305
+
306
+ - Updated dependencies to address known vulnerabilities (notably `@sveltejs/kit`, `vite`, and related plugins).
307
+
244
308
  ### Notes
245
309
 
246
310
  - Pinned `jsdom` to `26.1.0` due to build incompatibility in `27.x` (`cssstyle` parsing error with Vite/Rollup).
@@ -502,6 +566,11 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
502
566
 
503
567
  ## [1.14.1] - 2025-06-16
504
568
 
569
+ ### Added
570
+
571
+ - Introduced `.github/workflows/publish-test.yml`, a standalone workflow to safely simulate `npm publish` without publishing.
572
+ - Added commands to display Node.js and npm versions for visibility and troubleshooting in all relevant jobs.
573
+
505
574
  ### Changed
506
575
 
507
576
  - Updated Node.js engine to `24` to match the specified engine constraints in `package.json`.
@@ -509,11 +578,6 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
509
578
  - Refactored `build-and-publish.yml` to use `git archive` for artifact preparation and aligned it with a tested publishing flow.
510
579
  - Removed `.npmrc` token-based authentication in favor of environment secrets to avoid credential conflicts.
511
580
 
512
- ### Added
513
-
514
- - Introduced `.github/workflows/publish-test.yml`, a standalone workflow to safely simulate `npm publish` without publishing.
515
- - Added commands to display Node.js and npm versions for visibility and troubleshooting in all relevant jobs.
516
-
517
581
  ---
518
582
 
519
583
  ## [1.14.0] - 2025-06-16
@@ -842,13 +906,7 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
842
906
  - Upgraded `posthog-js` from `v1.249.4` to `v1.249.5`.
843
907
  - Upgraded `vitest` from `v3.2.2` to `v3.2.3`.
844
908
 
845
- ### Fixed
846
-
847
- - Updated Lighthouse CI annotation step to explicitly select only valid Lighthouse report files (e.g., `*.report.json`, `lhr-*.json`) and ignore `assertion-results.json`, which caused `jq` parsing errors during CI runs.
848
- - Scoped Lighthouse assertions in `.lighthouserc.cjs` to `resource-summary` only, preventing unwanted failures from default performance audits.
849
- - Resolved malformed PR comment formatting in the Lighthouse GitHub Actions workflow by replacing Markdown tables with plain-text bullet lists.
850
-
851
- ### Docs
909
+ ### Documentation
852
910
 
853
911
  - Updated `README.md` with improved context and phrasing around the CHANGELOG reference.
854
912
  - Added `CHANGELOG.md` to the documented project structure with a descriptive label:
@@ -857,7 +915,13 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
857
915
  ├── CHANGELOG.md # Chronological record of notable project changes
858
916
  ```
859
917
 
860
- ### Misc
918
+ ### Fixed
919
+
920
+ - Updated Lighthouse CI annotation step to explicitly select only valid Lighthouse report files (e.g., `*.report.json`, `lhr-*.json`) and ignore `assertion-results.json`, which caused `jq` parsing errors during CI runs.
921
+ - Scoped Lighthouse assertions in `.lighthouserc.cjs` to `resource-summary` only, preventing unwanted failures from default performance audits.
922
+ - Resolved malformed PR comment formatting in the Lighthouse GitHub Actions workflow by replacing Markdown tables with plain-text bullet lists.
923
+
924
+ ### Notes
861
925
 
862
926
  - Confirmed that `Authenticate GitHub CLI` is not needed in `build-and-publish.yml`, as only the `check-codeql` job uses the GitHub CLI and is already authenticated.
863
927
  - Verified that `scripts/openReport.js` does not require unit testing, as it performs side-effect-only CLI actions. Linting and manual testing are sufficient.
@@ -977,7 +1041,9 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
977
1041
 
978
1042
  <!-- Link references -->
979
1043
 
980
- [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.18.4...HEAD
1044
+ [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.19.0...HEAD
1045
+ [1.19.0]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.19.0
1046
+ [1.18.5]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.18.5
981
1047
  [1.18.4]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.18.4
982
1048
  [1.18.3]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.18.3
983
1049
  [1.18.2]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.18.2
package/README.md CHANGED
@@ -90,6 +90,7 @@ This project follows the principles of [Keep a Changelog](https://keepachangelog
90
90
  │ └── sitemap.xml # SEO: full site map
91
91
  ├── tests/
92
92
  │ ├── e2e/ # Playwright end-to-end tests
93
+ │ ├── meta/ # Metadata end-to-end CI tests
93
94
  │ └── unit/ # Vitest unit tests
94
95
  │ ├── client/ # Client-side (jsdom) unit tests
95
96
  │ ├── server/ # Server-side (node) unit tests
@@ -1,9 +1,9 @@
1
1
  /* =========================================================================
2
2
  jsconfig.template.jsonc
3
3
 
4
- NOTE: This file is for reference only and is not actively used by SvelteKit or
5
- tooling. SvelteKit uses the jsconfig.json file without comments for actual
6
- configuration.
4
+ NOTE: This file is for reference only and is not actively used by SvelteKit
5
+ or tooling. SvelteKit uses the jsconfig.json file without comments for
6
+ actual configuration.
7
7
 
8
8
  Copyright © 2025 Network Pro Strategies (Network Pro™)
9
9
  SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@networkpro/web",
3
3
  "private": false,
4
- "version": "1.18.4",
4
+ "version": "1.19.0",
5
5
  "description": "Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro Strategies",
6
6
  "keywords": [
7
7
  "advisory",
@@ -36,10 +36,10 @@
36
36
  "scripts": {
37
37
  "dev": "vite dev",
38
38
  "start": "npm run dev",
39
- "dev:netlify": "netlify dev",
39
+ "dev:vercel": "vercel dev",
40
40
  "build": "vite build",
41
+ "build:vercel": "vercel build",
41
42
  "preview": "vite preview",
42
- "build:netlify": "netlify build",
43
43
  "css:bundle": "node scripts/bundleCss.js",
44
44
  "prepare": "svelte-kit sync || echo ''",
45
45
  "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
@@ -60,7 +60,6 @@
60
60
  "test:watch": "vitest --config vitest.config.client.js --watch",
61
61
  "test:coverage": "npm run test:client -- --run --coverage && npm run test:server -- --run --coverage",
62
62
  "test:e2e": "npx playwright test --retries=1",
63
- "test:redirects": "node scripts/testRedirects.js",
64
63
  "coverage:client": "node scripts/openReport.js client",
65
64
  "coverage:server": "node scripts/openReport.js server",
66
65
  "coverage:open": "npm run coverage:client && npm run coverage:server",
@@ -68,7 +67,7 @@
68
67
  "lint:fix": "eslint . --ext .mjs,.js,.svelte --fix",
69
68
  "lint:jsdoc": "eslint . --ext .js,.mjs,.svelte --max-warnings=0",
70
69
  "lint:css": "stylelint \"**/*.{css,svelte}\" --ignore-path .stylelintignore",
71
- "lint:md": "npx markdownlint-cli2 \"**/*.{md,markdown}\" \"#node_modules/**\" \"#build/**\" \"#.netlify/**\" \"#playwright-report/**\" \"#test-results/**\"",
70
+ "lint:md": "npx markdownlint-cli2 \"**/*.{md,markdown}\" \"#node_modules/**\" \"#build/**\" \"#playwright-report/**\" \"#test-results/**\"",
72
71
  "lint:all": "npm run lint && npm run lint:md && npm run lint:css && npm run format",
73
72
  "format": "prettier --check .",
74
73
  "format:fix": "prettier --write .",
@@ -79,9 +78,9 @@
79
78
  },
80
79
  "dependencies": {
81
80
  "dompurify": "^3.2.7",
82
- "posthog-js": "^1.270.1",
81
+ "posthog-js": "^1.271.0",
83
82
  "semver": "^7.7.2",
84
- "svelte": "5.39.8"
83
+ "svelte": "5.39.9"
85
84
  },
86
85
  "devDependencies": {
87
86
  "@eslint/compat": "^1.4.0",
@@ -89,7 +88,7 @@
89
88
  "@lhci/cli": "^0.15.1",
90
89
  "@playwright/test": "^1.55.1",
91
90
  "@sveltejs/adapter-vercel": "^5.10.3",
92
- "@sveltejs/kit": "2.43.8",
91
+ "@sveltejs/kit": "2.44.0",
93
92
  "@sveltejs/vite-plugin-svelte": "^6.2.1",
94
93
  "@testing-library/jest-dom": "^6.9.1",
95
94
  "@testing-library/svelte": "^5.2.8",
@@ -98,7 +97,7 @@
98
97
  "browserslist": "^4.26.3",
99
98
  "eslint": "^9.37.0",
100
99
  "eslint-config-prettier": "^10.1.8",
101
- "eslint-plugin-jsdoc": "^60.8.0",
100
+ "eslint-plugin-jsdoc": "^60.8.2",
102
101
  "eslint-plugin-svelte": "^3.12.4",
103
102
  "globals": "^16.4.0",
104
103
  "jsdom": "26.1.0",
package/src/app.html CHANGED
@@ -63,7 +63,7 @@
63
63
  content="bx4ham0zkpvzztzu213bhpt76m9siq" />
64
64
  <!-- cspell:enable -->
65
65
 
66
- <meta name="generator" content="SvelteKit 2.43.5" />
66
+ <meta name="generator" content="SvelteKit 2.44.0" />
67
67
 
68
68
  <script src="/disableSw.js"></script>
69
69
 
@@ -0,0 +1,160 @@
1
+ <!-- =====================================================================
2
+ src/lib/README.md
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
+ # `/src/lib` Overview
10
+
11
+ This directory contains all reusable **modules**, **assets**, and **constants** used across the app.
12
+ It acts as the project’s _internal library_.
13
+
14
+ ---
15
+
16
+ ## 📦 Importing from `$lib`
17
+
18
+ SvelteKit automatically aliases `$lib` → `src/lib/`, allowing you to import from this directory anywhere in the project:
19
+
20
+ ```js
21
+ import { something } from '$lib';
22
+ ```
23
+
24
+ > 💡 You don’t need to use relative paths like `../../../lib/...`; the `$lib` alias handles that automatically.
25
+
26
+ ---
27
+
28
+ ## 📁 Directory Structure
29
+
30
+ ```bash
31
+ src/lib/
32
+ ├── components/ # Svelte UI components
33
+ ├── img/ # Static image assets
34
+ ├── images.js # Imports and re-exports images from /img/
35
+ ├── index.js # Main export hub (images, constants, etc.)
36
+ └── README.md # You are here
37
+ ```
38
+
39
+ ---
40
+
41
+ ## 🖼️ Image Imports
42
+
43
+ All image assets are re-exported via `images.js` and then made available in `$lib/index.js`.
44
+
45
+ This allows images to be imported directly from `$lib`:
46
+
47
+ ```js
48
+ import { logoPng, faviconSvg } from '$lib';
49
+ ```
50
+
51
+ **Example (Svelte component):**
52
+
53
+ ```svelte
54
+ <script>
55
+ import { logoPng } from '$lib';
56
+ </script>
57
+
58
+ <img src={logoPng} alt="Network Pro Logo" />
59
+ ```
60
+
61
+ If you prefer, you can still import by full path:
62
+
63
+ ```js
64
+ import logoPng from '$lib/img/logo-web.png';
65
+ ```
66
+
67
+ Both are valid — the re-exports simply make imports cleaner and centralized.
68
+
69
+ ---
70
+
71
+ ## ⚙️ Constants and Utilities
72
+
73
+ `index.js` defines and exports a `CONSTANTS` object for consistent app-wide values.
74
+ These are grouped into logical categories for easy reference.
75
+
76
+ ```js
77
+ import { CONSTANTS } from '$lib';
78
+
79
+ console.log(CONSTANTS.COMPANY_INFO.APP_NAME); // "Network Pro"
80
+ ```
81
+
82
+ ### 🏢 COMPANY_INFO
83
+
84
+ | Key | Description | Example |
85
+ | ---------- | ---------------------------- | ------------------------ |
86
+ | `NAME` | Full company name | `Network Pro Strategies` |
87
+ | `APP_NAME` | Application or branding name | `Network Pro` |
88
+ | `YEAR` | Copyright / app year | `2025` |
89
+
90
+ ### 📬 CONTACT
91
+
92
+ | Key | Description | Example |
93
+ | --------- | ----------------------- | --------------------------- |
94
+ | `EMAIL` | General support email | `support (at) neteng.pro` |
95
+ | `SECURE` | Secure contact address | `contact (at) s.neteng.pro` |
96
+ | `PRIVACY` | Privacy-related contact | `privacy (at) netwk.pro` |
97
+ | `PHONE` | Company phone number | `(623) 252-4350` |
98
+
99
+ ### 🗂️ PAGE
100
+
101
+ | Key | Description | Example |
102
+ | ------- | --------------------- | --------------------- |
103
+ | `BLANK` | Opens a new tab | `_blank` |
104
+ | `REL` | Default rel attribute | `noopener noreferrer` |
105
+ | `SELF` | Opens in same tab | `_self` |
106
+
107
+ ### 🧭 NAV
108
+
109
+ | Key | Description | Example |
110
+ | --------- | ----------------------- | ------------- |
111
+ | `BACKTOP` | Label for “back to top” | `Back to top` |
112
+ | `HREFTOP` | Anchor link to top | `#top` |
113
+
114
+ ### 🌐 LINKS
115
+
116
+ | Key | Description | Example |
117
+ | ------ | ---------------- | ------------------------ |
118
+ | `HOME` | Company home URL | `https://netwk.pro` |
119
+ | `BLOG` | Company blog URL | `https://blog.netwk.pro` |
120
+
121
+ 🧠 Tip: If you add new global constants (e.g., API endpoints, metadata, etc.),
122
+ extend `CONSTANTS` here and update this table for quick reference.
123
+
124
+ ---
125
+
126
+ ## 🧩 Components (if applicable)
127
+
128
+ Reusable components can also be exported from this directory:
129
+
130
+ ```js
131
+ import { Logo } from '$lib';
132
+ ```
133
+
134
+ If you add more UI components later, re-export them from `index.js` for easy access.
135
+
136
+ ---
137
+
138
+ ## 🧠 Developer Notes
139
+
140
+ `$lib` is an alias — not a relative path.
141
+ It points directly to `src/lib/`.
142
+
143
+ `export * from './images.js';` re-exports all image imports so you can reference them easily.
144
+
145
+ Keep asset imports centralized in `images.js` to simplify maintenance.
146
+
147
+ No need to modify imports when adding new images — just add them to `images.js`.
148
+
149
+ ---
150
+
151
+ <span style="font-size: 12px; text-align: center;">
152
+
153
+ Copyright &copy; 2025
154
+ **[Network Pro Strategies](https://netwk.pro) (Network Pro&trade;)**
155
+
156
+ Network Pro&trade;, the shield logo, and the "Locking Down Networks...&trade;" slogan are [trademarks](https://netwk.pro/license#trademark) of Network Pro Strategies.
157
+
158
+ Licensed under **[CC BY 4.0](https://netwk.pro/license#cc-by)** and the **[GNU GPL](https://netwk.pro/license#gnu-gpl)**, as published by the [Free Software Foundation](https://www.fsf.org), either version 3 of the License, or (at your option) any later version.
159
+
160
+ </span>
@@ -31,12 +31,3 @@ This file is part of Network Pro.
31
31
  <slot></slot>
32
32
  </div>
33
33
  </div>
34
-
35
- <style>
36
- .full-width-section.centered {
37
- display: flex;
38
- justify-content: center;
39
- flex-direction: column;
40
- min-height: 80vh;
41
- }
42
- </style>
@@ -0,0 +1,21 @@
1
+ /* ==========================================================================
2
+ src/lib/components/foss/index.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
+ * Library index file
11
+ *
12
+ * @file index.js
13
+ * @description Export point for FOSS library components
14
+ * @module src/lib/components/foss
15
+ * @author Scott Lopez
16
+ * @updated 2025-10-05
17
+ */
18
+
19
+ export { default as FossFeatures } from './FossFeatures.svelte';
20
+ export { default as FossItemContent } from './FossItemContent.svelte';
21
+ export { default as ObtainiumBlock } from './ObtainiumBlock.svelte';
@@ -0,0 +1,30 @@
1
+ /* ==========================================================================
2
+ src/lib/components/index.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
+ * Library index file
11
+ *
12
+ * @file index.js
13
+ * @description Export point for library components
14
+ * @module src/lib/components
15
+ * @author SunDevil311
16
+ * @updated 2025-10-05
17
+ */
18
+
19
+ export { default as Badges } from './Badges.svelte';
20
+ export { default as CodeBlock } from './CodeBlock.svelte';
21
+ export { default as ContainerSection } from './ContainerSection.svelte';
22
+ export * from './foss/index.js';
23
+ export { default as FullWidthSection } from './FullWidthSection.svelte';
24
+ export * from './layout/index.js';
25
+ export { default as LegalNav } from './LegalNav.svelte';
26
+ export { default as Logo } from './Logo.svelte';
27
+ export { default as MetaTags } from './MetaTags.svelte';
28
+ export { default as PWAInstallButton } from './PWAInstallButton.svelte';
29
+ export { default as RedirectPage } from './RedirectPage.svelte';
30
+ export { default as SocialMedia } from './SocialMedia.svelte';
@@ -0,0 +1,21 @@
1
+ /* ==========================================================================
2
+ src/lib/components/layout/index.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
+ * Library index file
11
+ *
12
+ * @file index.js
13
+ * @description Export point for layout components
14
+ * @module src/lib/components/layout
15
+ * @author Scott Lopez
16
+ * @updated 2025-10-05
17
+ */
18
+
19
+ export { default as Footer } from './Footer.svelte';
20
+ export { default as HeaderDefault } from './HeaderDefault.svelte';
21
+ export { default as HeaderHome } from './HeaderHome.svelte';
package/src/lib/index.js CHANGED
@@ -10,16 +10,26 @@ This file is part of Network Pro.
10
10
  * Library index file
11
11
  *
12
12
  * @file index.js
13
- * @description Main export point for library components, utilities, and assets
13
+ * @description Main export hub for $lib modules
14
+ *
15
+ * Components, images, and utilities are organized in submodules
16
+ * and re-exported here for flat `$lib` imports.
14
17
  * @module src/lib
15
18
  * @author SunDevil311
16
- * @updated 2025-06-03
19
+ * @updated 2025-10-05
17
20
  */
18
21
 
19
- // Re-export images from dedicated images.js file
20
- // This maintains backward compatibility with existing imports
22
+ // Re-export all images so they can be imported directly from `$lib`
23
+ // Example usage:
24
+ // import { logoPng } from '$lib';
21
25
  export * from './images.js';
22
26
 
27
+ // Re-export all components so they can be imported directly from `$lib`
28
+ export * from './components/index.js';
29
+
30
+ // Re-export all pages so they can be imported directly from `$lib`
31
+ export * from './pages/index.js';
32
+
23
33
  // Export utility functions
24
34
  // Uncomment and adjust these as needed for your project
25
35
  // export * from './utils/formatting.js';
@@ -138,7 +138,7 @@ This file is part of Network Pro.
138
138
  <p>
139
139
  <strong>{COMPANY_INFO.NAME} ({COMPANY_INFO.APP_NAME}&trade;)</strong>
140
140
  <br />
141
- <em>Remote-First Cybersecurity & Privacy Consulting</em>
141
+ <em>Networking, Security, Privacy</em>
142
142
  </p>
143
143
  </section>
144
144
 
@@ -162,10 +162,11 @@ This file is part of Network Pro.
162
162
 
163
163
  <p>
164
164
  At <strong>{COMPANY_INFO.NAME} ({COMPANY_INFO.APP_NAME}&trade;)</strong>, we
165
- deliver network security, cybersecurity, and digital privacy consulting with
166
- clarity, credibility, and care. We believe that real security doesn't have to
167
- come at the cost of user autonomy, and that privacy-minded solutions can be
168
- both practical and powerful.
165
+ deliver network security and engineering, information security (IS),
166
+ information technology (IT), cyber security, and digital privacy consulting
167
+ with clarity, credibility, and care. We believe that real security doesn't
168
+ have to come at the cost of user autonomy, and that privacy-minded solutions
169
+ can be both practical and powerful.
169
170
  </p>
170
171
 
171
172
  <p>
@@ -189,7 +190,7 @@ This file is part of Network Pro.
189
190
  <ul>
190
191
  <li><strong>Network Hardening & Perimeter Defense</strong></li>
191
192
  <li><strong>Firewall Architecture & Policy Optimization</strong></li>
192
- <li><strong>Cloud Security & Zero Trust Implementation</strong></li>
193
+ <li><strong>Zero Trust Implementation</strong></li>
193
194
  <li><strong>Secure Infrastructure Design & Implementation</strong></li>
194
195
  <li><strong>Risk Reduction & Security Posture Assessment</strong></li>
195
196
  </ul>
@@ -201,6 +202,24 @@ This file is part of Network Pro.
201
202
  clear value, with zero fluff.
202
203
  </p>
203
204
 
205
+ <div class="spacer"></div>
206
+
207
+ <p>
208
+ Additionally, {COMPANY_INFO.APP_NAME}&trade; provides on-site services in the
209
+ Greater Phoenix Metro Area (Maricopa County, AZ). Our on-site services are
210
+ available to both businesses and consumers. In addition to consulting, we
211
+ offer the following services:
212
+ </p>
213
+
214
+ <ul>
215
+ <li><strong>Home Modem Setup</strong></li>
216
+ <li><strong>Basic Router Setup</strong></li>
217
+ <li><strong>Wi-Fi and Wireless Networking Setup</strong></li>
218
+ <li><strong>Network Troubleshooting</strong></li>
219
+ <li><strong>Network Security Review</strong></li>
220
+ <li><strong>Add a Wi-Fi Device</strong></li>
221
+ </ul>
222
+
204
223
  <p>
205
224
  We also believe education is a core pillar of real-world security. That's why
206
225
  we invest in raising awareness—across both technical and general audiences—on
@@ -210,7 +229,8 @@ This file is part of Network Pro.
210
229
  <p>
211
230
  <strong
212
231
  >{COMPANY_INFO.APP_NAME}&trade; exists to bring strong, thoughtful security
213
- to organizations that value integrity—without sacrificing agility or trust.</strong>
232
+ to organizations and individuals that value integrity—without sacrificing
233
+ agility or trust.</strong>
214
234
  We don't just secure infrastructure. We secure confidence.
215
235
  </p>
216
236
 
@@ -218,7 +238,7 @@ This file is part of Network Pro.
218
238
 
219
239
  <p>
220
240
  <a href={contactLink} target={PAGE.BLANK}>Let's connect</a>
221
- to discuss how we can help secure and strengthen your business today.
241
+ to discuss how we can help secure and strengthen your business or home today.
222
242
  </p>
223
243
 
224
244
  <div class="spacer"></div>
@@ -0,0 +1,27 @@
1
+ /* ==========================================================================
2
+ src/lib/pages/index.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
+ * Library index file
11
+ *
12
+ * @file index.js
13
+ * @description Export point for Svelte pages
14
+ * @module src/lib/pages
15
+ * @author SunDevil311
16
+ * @updated 2025-10-05
17
+ */
18
+
19
+ export { default as AboutContent } from './AboutContent.svelte';
20
+ export { default as FossContent } from './FossContent.svelte';
21
+ export { default as HomeContent } from './HomeContent.svelte';
22
+ export { default as LicenseContent } from './LicenseContent.svelte';
23
+ export { default as PGPContent } from './PGPContent.svelte';
24
+ export { default as PrivacyContent } from './PrivacyContent.svelte';
25
+ export { default as PrivacyDashboard } from './PrivacyDashboard.svelte';
26
+ export { default as TermsConditionsContent } from './TermsConditionsContent.svelte';
27
+ export { default as TermsUseContent } from './TermsUseContent.svelte';
@@ -469,6 +469,13 @@ footer .container {
469
469
  word-break: normal; /* avoid deprecated behavior */
470
470
  }
471
471
 
472
+ .full-width-section.centered {
473
+ display: flex;
474
+ justify-content: center;
475
+ flex-direction: column;
476
+ min-height: 80vh;
477
+ }
478
+
472
479
  .fingerprint {
473
480
  display: block;
474
481
  font-weight: bold;
@@ -1,6 +1,8 @@
1
1
  /*! ==========================================================================
2
+ src/lib/styles/css/global.css
3
+
2
4
  Copyright © 2025 Network Pro Strategies (Network Pro™)
3
5
  SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
4
6
  This file is part of Network Pro.
5
7
  ========================================================================== */
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:#111;background-color:#ffc627}a:visited,a:visited:hover{color:#cba557}a:visited:focus,a:visited:focus-visible{color:#111!important}.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{break-inside:avoid;border:1px solid #999}tr,img{break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{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}.gold{color:#ffc627}.visited{color:#cba557}.goldseparator{color:#ffc627;margin:0 .5rem}.center-nav{text-align:center;padding:5px;font-size:1rem;line-height:1.5rem}.block{overflow-wrap:break-word;resize:none;white-space:normal;word-break:normal;background:0 0;border:none;border-radius:0;outline:none;width:100%;font-family:monospace;font-size:.875rem;line-height:1.125rem}.fingerprint{white-space:pre-line;font-weight:700;display:block}.pgp-image{width:150px;height:150px}.spacer{margin:2rem 0}.separator{margin:0 .5rem}.emoji{margin-right:8px}.headline{margin-bottom:4px;font-style:italic;font-weight:700;display:block}.label{font-family:inherit;font-weight:700}.description{font-family:inherit;font-style:normal;font-weight:400;display:inline}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.pgp-entry{flex-wrap:wrap;align-items:center;gap:2rem;margin-bottom:2rem;display:flex}.pgp-text{flex:2;min-width:250px}.pgp-qr{flex:1;min-width:150px}.obtainium-direct-label{margin:.25rem 0 .75rem;font-weight:700}.obtainium-manual-label{margin-top:.75rem;font-weight:700}.obtainium-img{width:185px;height:55px;margin-bottom:.25rem}.obtainium-margin{margin-left:4px}.obtainium-fa-down{color:#ffc627;margin-left:4px}.obtainium-icon{width:50px;height:50px}.proton-img{width:168px;height:24px}.redirect-text{text-align:center;margin-top:4rem}.redirect-content{text-align:center;margin-top:2rem;font-family:system-ui,sans-serif}.loading-spinner{border:4px solid #ddd;border-top-color:#ffc627;border-radius:50%;width:48px;height:48px;margin:2rem auto;animation:1s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.cc-link{text-decoration:none}.cc-img{vertical-align:text-bottom;margin-left:3px;display:inline-block;height:18px!important}
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:#111;background-color:#ffc627}a:visited,a:visited:hover{color:#cba557}a:visited:focus,a:visited:focus-visible{color:#111!important}.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{break-inside:avoid;border:1px solid #999}tr,img{break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{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}.gold{color:#ffc627}.visited{color:#cba557}.goldseparator{color:#ffc627;margin:0 .5rem}.center-nav{text-align:center;padding:5px;font-size:1rem;line-height:1.5rem}.block{overflow-wrap:break-word;resize:none;white-space:normal;word-break:normal;background:0 0;border:none;border-radius:0;outline:none;width:100%;font-family:monospace;font-size:.875rem;line-height:1.125rem}.full-width-section.centered{flex-direction:column;justify-content:center;min-height:80vh;display:flex}.fingerprint{white-space:pre-line;font-weight:700;display:block}.pgp-image{width:150px;height:150px}.spacer{margin:2rem 0}.separator{margin:0 .5rem}.emoji{margin-right:8px}.headline{margin-bottom:4px;font-style:italic;font-weight:700;display:block}.label{font-family:inherit;font-weight:700}.description{font-family:inherit;font-style:normal;font-weight:400;display:inline}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.pgp-entry{flex-wrap:wrap;align-items:center;gap:2rem;margin-bottom:2rem;display:flex}.pgp-text{flex:2;min-width:250px}.pgp-qr{flex:1;min-width:150px}.obtainium-direct-label{margin:.25rem 0 .75rem;font-weight:700}.obtainium-manual-label{margin-top:.75rem;font-weight:700}.obtainium-img{width:185px;height:55px;margin-bottom:.25rem}.obtainium-margin{margin-left:4px}.obtainium-fa-down{color:#ffc627;margin-left:4px}.obtainium-icon{width:50px;height:50px}.proton-img{width:168px;height:24px}.redirect-text{text-align:center;margin-top:4rem}.redirect-content{text-align:center;margin-top:2rem;font-family:system-ui,sans-serif}.loading-spinner{border:4px solid #ddd;border-top-color:#ffc627;border-radius:50%;width:48px;height:48px;margin:2rem auto;animation:1s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.cc-link{text-decoration:none}.cc-img{vertical-align:text-bottom;margin-left:3px;display:inline-block;height:18px!important}
@@ -9,4 +9,3 @@ This file is part of Network Pro.
9
9
  // Import transformed and minified stylesheets
10
10
  import "./global.min.css";
11
11
  import "./fa-global.css";
12
-
@@ -0,0 +1,50 @@
1
+ <!-- =====================================================================
2
+ src/lib/types/README.md
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
+ # Typing Policy
10
+
11
+ This directory contains JSDoc-based type definitions for reusable modules
12
+ within the Network Pro codebase. The goal is to provide meaningful IntelliSense,
13
+ editor documentation, and lightweight type safety without requiring TypeScript
14
+ conversion.
15
+
16
+ ## Scope and Philosophy
17
+
18
+ - **Structured Data Only** – Typing is focused on objects that benefit from
19
+ explicit schemas (e.g., configuration, constants, utilities).
20
+ - **Svelte Components** – Components are intentionally _not_ fully typed at this
21
+ stage. Component auto-completion is already handled by the Svelte language
22
+ server, and explicit typedefs would add unnecessary complexity.
23
+ - **Scalability** – Typing is modular. New typedefs can be added under
24
+ `/src/lib/types/` as the codebase grows.
25
+ - **Documentation-Driven** – JSDoc comments serve both as type definitions and
26
+ developer documentation. This minimizes friction while improving clarity.
27
+
28
+ ## Example
29
+
30
+ ```js
31
+ /** @typedef {import('./types/appConstants.js').AppConstants} AppConstants */
32
+ /** @type {AppConstants} */
33
+ export const CONSTANTS = { ... };
34
+ ```
35
+
36
+ This approach balances clarity and maintainability without introducing a
37
+ TypeScript build requirement.
38
+
39
+ ---
40
+
41
+ <span style="font-size: 12px; text-align: center;">
42
+
43
+ Copyright &copy; 2025
44
+ **[Network Pro Strategies](https://netwk.pro) (Network Pro&trade;)**
45
+
46
+ Network Pro&trade;, the shield logo, and the "Locking Down Networks...&trade;" slogan are [trademarks](https://netwk.pro/license#trademark) of Network Pro Strategies.
47
+
48
+ Licensed under **[CC BY 4.0](https://netwk.pro/license#cc-by)** and the **[GNU GPL](https://netwk.pro/license#gnu-gpl)**, as published by the [Free Software Foundation](https://www.fsf.org), either version 3 of the License, or (at your option) any later version.
49
+
50
+ </span>
@@ -14,21 +14,15 @@ This file is part of Network Pro.
14
14
  import { initPostHog, showReminder, capture } from '$lib/stores/posthog';
15
15
  import { registerServiceWorker } from '$lib/registerServiceWorker.js';
16
16
  import { browser } from '$app/environment';
17
+ import { logoPng, logoWbp, faviconSvg, appleTouchIcon } from '$lib';
18
+ import { ContainerSection, PWAInstallButton } from '$lib/components';
19
+ import { Footer, HeaderDefault, HeaderHome } from '$lib/components/layout';
17
20
 
18
- import ContainerSection from '$lib/components/ContainerSection.svelte';
19
- import Footer from '$lib/components/layout/Footer.svelte';
20
- import HeaderDefault from '$lib/components/layout/HeaderDefault.svelte';
21
- import HeaderHome from '$lib/components/layout/HeaderHome.svelte';
22
- import PWAInstallButton from '$lib/components/PWAInstallButton.svelte';
21
+ //import PWAInstallButton from '$lib/components/PWAInstallButton.svelte';
23
22
 
24
23
  import '$lib/styles/global.min.css';
25
24
  import '$lib/styles/fa-global.css';
26
25
 
27
- import logoPng from '$lib/img/logo-web.png';
28
- import logoWbp from '$lib/img/logo-web.webp';
29
- import faviconSvg from '$lib/img/favicon.svg';
30
- import appleTouchIcon from '$lib/img/icon-180x180.png';
31
-
32
26
  $: shouldShowReminder = $showReminder;
33
27
 
34
28
  onMount(() => {
@@ -7,13 +7,15 @@ This file is part of Network Pro.
7
7
  ========================================================================== -->
8
8
 
9
9
  <script>
10
- import Badges from '$lib/components/Badges.svelte';
11
- import FullWidthSection from '$lib/components/FullWidthSection.svelte';
12
- import HomeContent from '$lib/pages/HomeContent.svelte';
13
- import LegalNav from '$lib/components/LegalNav.svelte';
14
- import Logo from '$lib/components/Logo.svelte';
15
- import SocialMedia from '$lib/components/SocialMedia.svelte';
16
- import MetaTags from '$lib/components/MetaTags.svelte';
10
+ import {
11
+ Badges,
12
+ FullWidthSection,
13
+ LegalNav,
14
+ Logo,
15
+ SocialMedia,
16
+ MetaTags,
17
+ } from '$lib/components';
18
+ import { HomeContent } from '$lib/pages';
17
19
 
18
20
  /**
19
21
  * @type {string}
@@ -7,16 +7,17 @@ This file is part of Network Pro.
7
7
  ========================================================================== -->
8
8
 
9
9
  <script>
10
- import RedirectPage from '$lib/components/RedirectPage.svelte';
11
10
  import { appendUTM } from '$lib/utils/utm.js';
12
11
  import { getUTMParams } from '$lib/utils/getUTMParams.js';
13
12
  import { trackingEnabled } from '$lib/stores/trackingPreferences';
14
- import posthog from 'posthog-js';
13
+ import { RedirectPage } from '$lib/components';
15
14
  import { get } from 'svelte/store';
16
15
  import { onMount } from 'svelte';
17
16
  import { browser } from '$app/environment';
18
17
  import { CONSTANTS } from '$lib';
19
18
 
19
+ import posthog from 'posthog-js';
20
+
20
21
  //console.log(CONSTANTS.COMPANY_INFO.APP_NAME);
21
22
 
22
23
  const { PAGE } = CONSTANTS;
@@ -9,9 +9,9 @@ This file is part of Network Pro.
9
9
  /**
10
10
  * @file disableSw.js
11
11
  * @description Allows for Service Worker to be disabled for debugging by appending ?nosw to the path.
12
- * @module src/lib/utils/
12
+ * @module static
13
13
  * @author SunDevil311
14
- * @updated 2025-05-29
14
+ * @updated 2025-10-05
15
15
  */
16
16
 
17
17
  if (location.search.includes('nosw')) {
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <!-- Sitemap last updated 2025-09-27 -->
2
+ <!-- Sitemap last updated 2025-10-06 -->
3
3
 
4
4
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
5
5
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  <loc>https://netwk.pro</loc>
9
9
 
10
- <lastmod>2025-09-27</lastmod>
10
+ <lastmod>2025-10-06</lastmod>
11
11
 
12
12
  <changefreq>weekly</changefreq>
13
13
 
@@ -31,7 +31,7 @@
31
31
 
32
32
  <loc>https://netwk.pro/about</loc>
33
33
 
34
- <lastmod>2025-06-10</lastmod>
34
+ <lastmod>2025-10-06</lastmod>
35
35
 
36
36
  <changefreq>monthly</changefreq>
37
37
 
@@ -0,0 +1,80 @@
1
+ /* ==========================================================================
2
+ tests/unit/client/lib/PWAInstallButton.test.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 redirect.test.js
11
+ * @description Unit test for PWA install component
12
+ * @module tests/unit/lib
13
+ * @author SunDevil311
14
+ * @updated 2025-10-05
15
+ */
16
+
17
+ import PWAInstallButton from '$lib/components/PWAInstallButton.svelte';
18
+ import { fireEvent, render, waitFor } from '@testing-library/svelte';
19
+ import { describe, expect, it, vi } from 'vitest';
20
+
21
+ /* --------------------------------------------------------------------------
22
+ Fake BeforeInstallPromptEvent Mock
23
+ --------------------------------------------------------------------------
24
+ */
25
+ class FakeBeforeInstallPromptEvent {
26
+ constructor() {
27
+ this.prompt = vi.fn();
28
+ this.userChoice = Promise.resolve({
29
+ outcome: 'accepted',
30
+ platform: 'test',
31
+ });
32
+ }
33
+ }
34
+
35
+ /* --------------------------------------------------------------------------
36
+ Tests
37
+ -------------------------------------------------------------------------- */
38
+ describe('PWAInstallButton', () => {
39
+ it('shows button when pwa-install-available event is fired', async () => {
40
+ const { getByRole, queryByRole } = render(PWAInstallButton);
41
+
42
+ // Initially, the install button should not be in the DOM
43
+ expect(queryByRole('button')).toBeNull();
44
+
45
+ // Dispatch the custom event that makes the button appear
46
+ const fakeEvent = new FakeBeforeInstallPromptEvent();
47
+ window.dispatchEvent(
48
+ new CustomEvent('pwa-install-available', { detail: fakeEvent }),
49
+ );
50
+
51
+ // Verify that the button now appears
52
+ const button = await waitFor(() =>
53
+ getByRole('button', { name: /install app/i }),
54
+ );
55
+ expect(button).toBeInTheDocument();
56
+ });
57
+
58
+ it('calls prompt() when install button is clicked', async () => {
59
+ const { getByRole } = render(PWAInstallButton);
60
+
61
+ // Fire the event that makes the button visible
62
+ const fakeEvent = new FakeBeforeInstallPromptEvent();
63
+ window.dispatchEvent(
64
+ new CustomEvent('pwa-install-available', { detail: fakeEvent }),
65
+ );
66
+
67
+ // Wait until the button appears
68
+ const button = await waitFor(() =>
69
+ getByRole('button', { name: /install app/i }),
70
+ );
71
+
72
+ // Simulate a user clicking the install button
73
+ await fireEvent.click(button);
74
+
75
+ // Verify that prompt() was called — the core behavior we care about
76
+ expect(fakeEvent.prompt).toHaveBeenCalled();
77
+
78
+ // (Removed: button disappearance check, since it depends on async animation timing)
79
+ });
80
+ });
@@ -25,6 +25,15 @@ Object.defineProperty(window, 'matchMedia', {
25
25
  })),
26
26
  });
27
27
 
28
+ // Mock Web Animations API (jsdom doesn't implement element.animate)
29
+ if (!Element.prototype.animate) {
30
+ Element.prototype.animate = () => ({
31
+ onfinish: null,
32
+ cancel: () => {},
33
+ finished: Promise.resolve(),
34
+ });
35
+ }
36
+
28
37
  // Automatically clean up the DOM after each test
29
38
  afterEach(() => {
30
39
  cleanup();
@@ -1,84 +0,0 @@
1
- /* ==========================================================================
2
- scripts/testRedirects.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 testRedirects.js
11
- * @description Tests Netlify redirects against actual endpoints to verify
12
- * trailing-slash behavior.
13
- *
14
- * @module scripts/
15
- * @author SunDevil311
16
- * @updated 2025-07-01
17
- */
18
-
19
- import https from 'https';
20
- import { URL } from 'url';
21
-
22
- /**
23
- * @typedef {object} RedirectTest
24
- * @property {string} from - The source URL to test.
25
- * @property {string} to - The expected destination URL.
26
- */
27
-
28
- /** @type {RedirectTest[]} */
29
- const urls = [
30
- { from: 'https://netwk.pro/privacy-policy', to: 'https://netwk.pro/privacy' },
31
- {
32
- from: 'https://netwk.pro/privacy-policy/',
33
- to: 'https://netwk.pro/privacy',
34
- },
35
- { from: 'https://netwk.pro/foss', to: 'https://netwk.pro/foss-spotlight' },
36
- { from: 'https://netwk.pro/foss/', to: 'https://netwk.pro/foss-spotlight' },
37
- {
38
- from: 'https://www.netwk.pro/foss',
39
- to: 'https://netwk.pro/foss-spotlight',
40
- },
41
- ];
42
-
43
- /**
44
- * Tests a single redirect by making a GET request and checking the status code and location header.
45
- * @param {RedirectTest} redirect - The redirect configuration to test.
46
- * @returns {Promise<boolean>} - Resolves to true if the redirect is correct, false otherwise.
47
- */
48
- function testRedirect({ from, to }) {
49
- return new Promise((resolve) => {
50
- const req = https.request(new URL(from), { method: 'GET' }, (res) => {
51
- const location = res.headers.location;
52
- const expectedPath = new URL(to).pathname;
53
-
54
- if (res.statusCode === 301 && location === expectedPath) {
55
- console.log(`✅ ${from} → ${location}`);
56
- resolve(true);
57
- } else {
58
- console.error(
59
- `❌ ${from} → Expected 301 to ${expectedPath}, got ${res.statusCode} to ${location}`,
60
- );
61
- resolve(false);
62
- }
63
- });
64
-
65
- req.on('error', (err) => {
66
- console.error(`❌ ${from} → Network error: ${err.message}`);
67
- resolve(false);
68
- });
69
-
70
- req.end();
71
- });
72
- }
73
-
74
- /**
75
- * Runs all redirect tests and exits the process with a status code reflecting success or failure.
76
- * @returns {Promise<void>}
77
- */
78
- const runTests = async () => {
79
- const results = await Promise.all(urls.map(testRedirect));
80
- const failed = results.filter((r) => !r).length;
81
- process.exit(failed > 0 ? 1 : 0);
82
- };
83
-
84
- runTests();