Skip to content

Commit b4cd6e1

Browse files
authored
Merge pull request #9 from Lissy93/feat/homepage-improvments
Add homepage customization options for user
2 parents c4a9eab + 3ae442f commit b4cd6e1

80 files changed

Lines changed: 6332 additions & 954 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CONTRIBUTING.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Contributing
2+
3+
Hey! Thanks for wanting to contribute to Networking Toolbox 🎉
4+
5+
## Getting Started
6+
7+
Checkout the [README](README.md) for setup instructions, it's all very standard (clone, cd, npm install, npm run dev).
8+
9+
## Code Style
10+
11+
The usual, just keep it reasonably clean and consistent. Like normal TypeScript + Svelte stuff.
12+
13+
## Before You Submit
14+
15+
Don't forget to ensure that all checks pass. If you just run `npm run hold-my-beer` then you should be good to go!
16+
17+
For all project commands, take a look at the [the readme](https://github.com/Lissy93/networking-toolbox?tab=readme-ov-file#project-commands) or just the [`package.json`](https://github.com/Lissy93/networking-toolbox/blob/main/package.json).
18+
19+
## Code of Conduct
20+
21+
Be respectful and constructive. See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for details.
22+
23+
If you mention .NET I might block you. Just kidding. Maybe.

.github/docs/app-customization.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Customization Guide
2+
3+
If you're self-hosting Networking Toolbox, you can customize the branding for your instance with a few env vars.
4+
5+
## Overview
6+
7+
Networking Toolbox supports customization through environment variables. This allows you to:
8+
- Brand the application with your organization's name
9+
- Use a custom logo/icon
10+
- Set default themes and layouts
11+
- Maintain consistency across your organization
12+
13+
**Important:** These customizations only affect the default values. Users can still customize their personal preferences through the settings menu, and those will be stored in their browser's localStorage.
14+
15+
## Getting Started
16+
17+
Download the [`.env.example`](https://gist.githubusercontent.com/Lissy93/3c5f85dc0e2263a4706d3e136f0a076e/raw/62a00f625c920ac9e1cafe60721213e2ea233581/.env.example) to `.env` in the root of your project.
18+
19+
1. Copy `.env.example` to `.env`:
20+
```bash
21+
curl -o .env https://gist.githubusercontent.com/Lissy93/3c5f85dc0e2263a4706d3e136f0a076e/raw/62a00f625c920ac9e1cafe60721213e2ea233581/.env.example
22+
```
23+
24+
2. Edit `.env` and uncomment/modify the variables you want to customize
25+
26+
3. Restart your application to apply changes
27+
28+
## Available Customizations
29+
30+
### Site Branding
31+
32+
```bash
33+
# Customize your site name and description
34+
NTB_SITE_NAME=My Network Tools
35+
NTB_SITE_TITLE=My Network Tools
36+
NTB_SITE_DESCRIPTION=Professional networking utilities for your team
37+
```
38+
39+
### Custom Logo
40+
41+
Use a custom logo image in the navbar:
42+
43+
```bash
44+
NTB_SITE_ICON=/logo.svg
45+
```
46+
47+
Place your logo image in the `static/` directory and reference it with a leading slash. Supported formats: SVG, PNG, JPG, WebP.
48+
49+
### Default Layout
50+
51+
Set the default homepage layout:
52+
53+
```bash
54+
# Options: categories, default, minimal, carousel, bookmarks, small-icons, list, search, empty
55+
NTB_HOMEPAGE_LAYOUT=categories
56+
```
57+
58+
### Default Navbar Display
59+
60+
Control what appears in the top navigation:
61+
62+
```bash
63+
# Options: default, bookmarked, frequent, none
64+
NTB_NAVBAR_DISPLAY=default
65+
```
66+
67+
### Default Theme
68+
69+
Set the default color theme:
70+
71+
```bash
72+
# Options: dark, light, midnight, arctic, ocean, purple, cyberpunk, terminal, lightpurple, muteddark, solarized
73+
NTB_DEFAULT_THEME=dark
74+
```
75+
76+
## Example Configurations
77+
78+
### Corporate Branding Example
79+
80+
```bash
81+
NTB_SITE_NAME=Acme Corp Network Tools
82+
NTB_SITE_TITLE=Acme Corp Network Tools
83+
NTB_SITE_DESCRIPTION=Internal networking utilities for Acme Corp IT team
84+
NTB_SITE_ICON=/acme-logo.svg
85+
NTB_DEFAULT_THEME=light
86+
NTB_HOMEPAGE_LAYOUT=list
87+
```
88+
89+
### Minimalist Setup Example
90+
91+
```bash
92+
NTB_SITE_NAME=NetUtils
93+
NTB_SITE_DESCRIPTION=Simple network utilities
94+
NTB_DEFAULT_THEME=muteddark
95+
NTB_HOMEPAGE_LAYOUT=search
96+
NTB_NAVBAR_DISPLAY=none
97+
```
98+
99+
## Docker Deployment
100+
101+
When using Docker, pass environment variables with the `-e` flag or use a `.env` file:
102+
103+
```bash
104+
docker run -p 5000:5000 \
105+
-e NTB_SITE_NAME="My Network Tools" \
106+
-e NTB_DEFAULT_THEME="light" \
107+
lissy93/networking-toolbox
108+
```
109+
110+
Or with docker-compose:
111+
112+
```yaml
113+
services:
114+
networking-toolbox:
115+
image: lissy93/networking-toolbox
116+
ports:
117+
- "5000:5000"
118+
environment:
119+
- NTB_SITE_NAME=My Network Tools
120+
- NTB_DEFAULT_THEME=light
121+
- NTB_SITE_ICON=/custom-logo.svg
122+
volumes:
123+
- ./static:/app/static # For custom logo
124+
```
125+
126+
## Notes
127+
128+
- All environment variables must be prefixed with `NTB_` to be accessible
129+
- Changes require an application restart to take effect
130+
- The managed instance at [networking-toolbox.as93.net](https://networking-toolbox.as93.net) uses the default values
131+
- User preferences set through the UI take precedence over these defaults
132+
- Invalid values will fallback to the default settings
133+
134+

.github/workflows/report-tests.yml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Runs after the test workflow is done, uses results to gen a report for the PR
2+
13
name: 📣 Report Tests
24

35
on:
@@ -10,6 +12,7 @@ permissions:
1012
contents: read
1113
checks: write # For test reporting
1214
pull-requests: write # For PR comments
15+
actions: read
1316

1417
jobs:
1518
report:
@@ -33,7 +36,7 @@ jobs:
3336
uses: dorny/test-reporter@v1
3437
if: always()
3538
with:
36-
name: Unit Tests
39+
name: ⚙️ Unit Tests
3740
path: test-results.xml
3841
reporter: java-junit
3942
fail-on-error: false
@@ -44,7 +47,7 @@ jobs:
4447
uses: dorny/test-reporter@v1
4548
if: always()
4649
with:
47-
name: API Contract Tests
50+
name: 📡 API Contract Tests
4851
path: api-test-results.xml
4952
reporter: java-junit
5053
fail-on-error: false
@@ -55,7 +58,7 @@ jobs:
5558
uses: dorny/test-reporter@v1
5659
if: always()
5760
with:
58-
name: E2E Tests
61+
name: 🧭 E2E Tests
5962
path: e2e-results.xml
6063
reporter: java-junit
6164
fail-on-error: false
@@ -109,13 +112,12 @@ jobs:
109112
{
110113
echo "## 📊 Detailed Test Report"
111114
echo ""
112-
echo "**Overall Status:** $(em "${{ github.event.workflow_run.conclusion }}")"
113-
echo ""
114-
115115
if [ "$failures" -eq 0 ]; then
116-
echo "🎉 **All test suites passed!**"
116+
echo "🎉 **All test suites passed!**<br>"
117+
echo "![niceee](https://media.tenor.com/5IWFYb4D1WMAAAAi/swan-hack-dab.gif)<br>"
117118
else
118-
echo "⚠️ **$failures test suite(s) failed**"
119+
echo "⚠️ **$failures test suite(s) failed**<br>"
120+
echo "![its not the end of the wold](https://media.tenor.com/37jOSZZvjQUAAAAi/pengu-pudgy.gif)<br>"
119121
fi
120122
121123
# Detailed Unit Test Report

eslint.config.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,28 @@ export default [
2929
'svelte/no-navigation-without-resolve': 'off'
3030
}
3131
},
32+
{
33+
files: ['**/*.svelte.ts'],
34+
languageOptions: {
35+
parser: tseslint.parser,
36+
parserOptions: {
37+
ecmaVersion: 'latest',
38+
sourceType: 'module',
39+
extraFileExtensions: ['.svelte']
40+
},
41+
globals: {
42+
...globals.browser,
43+
...globals.es2023,
44+
// Svelte 5 runes globals
45+
$state: 'readonly',
46+
$derived: 'readonly',
47+
$effect: 'readonly',
48+
$props: 'readonly',
49+
$bindable: 'readonly',
50+
$inspect: 'readonly'
51+
}
52+
}
53+
},
3254
{
3355
rules: {
3456
// Prefer TS version of unused-vars, and ignore _-prefixed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "networking-toolbox",
33
"private": true,
4-
"version": "1.1.0",
4+
"version": "1.2.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite dev",
@@ -15,10 +15,11 @@
1515
"build-check": "vite build --minify=false --sourcemap=false --logLevel error",
1616
"build:node": "DEPLOY_ENV='node' npm run build",
1717
"build:static": "DEPLOY_ENV='static' npm run build",
18-
"test": "vitest",
18+
"test": "vitest run",
1919
"test:coverage": "vitest run --coverage",
2020
"test:api": "vitest run --config tests/vitest.api.config.ts",
21-
"test:e2e": "playwright test"
21+
"test:e2e": "playwright test",
22+
"hold-my-beer": "npm run format && npm run lint && npm run types && npm run check && npm run build-check && npm run test"
2223
},
2324
"devDependencies": {
2425
"@axe-core/playwright": "^4.10.2",

src/app.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@
33
<head>
44
<meta charset="utf-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
7+
<!-- Prevent FOUC by applying theme before page renders -->
8+
<script>
9+
(function () {
10+
try {
11+
// Apply theme
12+
const theme = localStorage.getItem('theme') || 'dark';
13+
if (theme !== 'dark') {
14+
document.documentElement.classList.add('theme-' + theme);
15+
}
16+
} catch (e) {
17+
// Ignore localStorage errors (private browsing, etc.)
18+
}
19+
})();
20+
</script>
21+
622
%sveltekit.head%
723
</head>
824
<body data-sveltekit-preload-data="hover">
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<script lang="ts">
2+
import { formatShortcut } from '$lib/utils/keyboard';
3+
4+
interface Props {
5+
label: string;
6+
shortcut: string;
7+
onclick?: () => void;
8+
}
9+
10+
let { label, shortcut, onclick }: Props = $props();
11+
12+
const formattedShortcut = $derived(formatShortcut(shortcut));
13+
</script>
14+
15+
<button class="shortcut-chip" {onclick} aria-label="{label} - {formattedShortcut}">
16+
<span class="chip-label">{label}</span>
17+
<span class="chip-shortcut">{formattedShortcut}</span>
18+
</button>
19+
20+
<style lang="scss">
21+
.shortcut-chip {
22+
display: inline-flex;
23+
align-items: center;
24+
gap: var(--spacing-sm);
25+
padding: var(--spacing-xs) var(--spacing-sm);
26+
background-color: var(--bg-secondary);
27+
border: 1px solid var(--border-primary);
28+
border-radius: var(--radius-lg);
29+
cursor: pointer;
30+
transition: all var(--transition-fast);
31+
font-size: var(--font-size-xs);
32+
font-family: var(--font-mono);
33+
color: var(--text-primary);
34+
white-space: nowrap;
35+
box-shadow: var(--shadow-sm);
36+
animation: chipAppear 0.4s ease-out;
37+
justify-content: space-between;
38+
39+
&:hover {
40+
background-color: var(--surface-hover);
41+
border-color: var(--color-primary);
42+
transform: translateY(-1px) scale(1.02);
43+
box-shadow: var(--shadow-md);
44+
}
45+
46+
&:focus-visible {
47+
outline: 2px solid var(--color-primary);
48+
outline-offset: 2px;
49+
}
50+
51+
&:active {
52+
transform: scale(0.98) translateY(1px);
53+
box-shadow: var(--shadow-sm);
54+
}
55+
56+
.chip-label {
57+
font-weight: 500;
58+
color: var(--text-primary);
59+
}
60+
61+
.chip-shortcut {
62+
background-color: var(--bg-tertiary);
63+
border: 1px solid var(--border-secondary);
64+
border-radius: var(--radius-sm);
65+
padding: 2px var(--spacing-xs);
66+
font-size: var(--font-size-xs);
67+
color: var(--text-secondary);
68+
font-family: var(--font-mono);
69+
}
70+
}
71+
72+
@keyframes chipAppear {
73+
from {
74+
opacity: 0;
75+
transform: scale(0.95) translateY(4px);
76+
}
77+
to {
78+
opacity: 1;
79+
transform: scale(1) translateY(0);
80+
}
81+
}
82+
</style>

src/lib/components/common/OfflineIndicator.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { resolve } from '$app/paths';
55
import Icon from '$lib/components/global/Icon.svelte';
66
7-
$: currentPath = $page.url.pathname;
7+
$: currentPath = $page.url?.pathname ?? '/';
88
$: isOfflinePage = currentPath === '/offline';
99
$: isActualTool = isDownloadableTool(currentPath);
1010
$: worksOffline = isOfflineCapable(currentPath);

src/lib/components/furniture/BurgerMenu.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@
126126
127127
// Check if a link is currently active
128128
function isActiveLink(href: string): boolean {
129-
return $page.url.pathname === href || $page.url.pathname.startsWith(href + '/');
129+
const pathname = $page.url?.pathname ?? '/';
130+
return pathname === href || pathname.startsWith(href + '/');
130131
}
131132
132133
// Get nav groups for organized display

0 commit comments

Comments
 (0)