@dirsigler/techradar 1.0.4

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Dennis Irsigler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # Tech Radar
2
+
3
+ [![Built with Astro](https://img.shields.io/badge/Built%20with-Astro-BC52EE?logo=astro&logoColor=white)](https://astro.build)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+ [![Deploy](https://img.shields.io/badge/Deployed%20on-Cloudflare%20Workers-F38020?logo=cloudflare&logoColor=white)](https://demo.techradar.irsigler.dev)
6
+
7
+ An interactive, fully static technology radar built with [Astro](https://astro.build). Track technology adoption decisions across your organization with a visual radar chart, categorized segments, and detailed technology pages — all driven by simple Markdown files.
8
+
9
+ **[View Live Demo](https://demo.techradar.irsigler.dev)**
10
+
11
+ ---
12
+
13
+ ## Preview
14
+
15
+ | Radar Overview | Technology Detail |
16
+ | :----------------------------------------------: | :--------------------------------------------------------: |
17
+ | ![Radar Light](docs/screenshots/radar-light.png) | ![Technology Page](docs/screenshots/technology-detail.png) |
18
+ | ![Radar Dark](docs/screenshots/radar-dark.png) | ![Segment Page](docs/screenshots/segment-page.png) |
19
+
20
+ ---
21
+
22
+ ## Key Features
23
+
24
+ <table>
25
+ <tr>
26
+ <td width="50%">
27
+
28
+ ### Interactive SVG Radar
29
+
30
+ Technologies plotted across four rings — **Adopt**, **Trial**, **Assess**, **Hold** — with hover tooltips and click-through to detail pages.
31
+
32
+ </td>
33
+ <td width="50%">
34
+
35
+ ### Markdown-Driven Content
36
+
37
+ Add technologies by dropping `.md` files into `segments/`. No code changes needed — just write frontmatter and prose.
38
+
39
+ </td>
40
+ </tr>
41
+ <tr>
42
+ <td width="50%">
43
+
44
+ ### Theming & Dark Mode
45
+
46
+ Swappable CSS themes with automatic light/dark mode support. Ships with a default theme and [Catppuccin Mocha](https://catppuccin.com). Create your own by defining CSS custom properties.
47
+
48
+ </td>
49
+ <td width="50%">
50
+
51
+ ### Fully Static & Fast
52
+
53
+ Builds to plain HTML/CSS/JS — 60+ pages in ~1 second. Deploy anywhere: Cloudflare Workers, Netlify, Vercel, S3, or any static host.
54
+
55
+ </td>
56
+ </tr>
57
+ <tr>
58
+ <td width="50%">
59
+
60
+ ### Segments & Movement
61
+
62
+ Group technologies into color-coded categories. Mark technologies as moved in/out to highlight recent adoption changes.
63
+
64
+ </td>
65
+ <td width="50%">
66
+
67
+ ### SEO & Production Ready
68
+
69
+ Sitemap, robots.txt, Open Graph, Twitter Cards, canonical URLs, custom 404 page — all out of the box.
70
+
71
+ </td>
72
+ </tr>
73
+ </table>
74
+
75
+ ---
76
+
77
+ ## Quick Start
78
+
79
+ ```bash
80
+ git clone https://github.com/dirsigler/techradar.git
81
+ cd techradar
82
+ npm install
83
+ npm run dev
84
+ ```
85
+
86
+ Open [http://localhost:4321](http://localhost:4321) to see the radar.
87
+
88
+ ## Adding Technologies
89
+
90
+ Create a Markdown file in the appropriate segment directory under `segments/`:
91
+
92
+ ```text
93
+ segments/
94
+ ├── cloud/
95
+ │ ├── index.md # Segment metadata (title, color, order)
96
+ │ ├── kubernetes.md
97
+ │ └── terraform.md
98
+ ├── frameworks/
99
+ │ ├── index.md
100
+ │ ├── astro.md
101
+ │ └── react.md
102
+ └── ...
103
+ ```
104
+
105
+ Each technology file uses this frontmatter:
106
+
107
+ ```markdown
108
+ ---
109
+ title: Kubernetes
110
+ ring: adopt # adopt | trial | assess | hold
111
+ moved: 0 # 1 = moved in, -1 = moved out, 0 = unchanged
112
+ ---
113
+
114
+ Your description in Markdown. Explain why this technology is in this ring,
115
+ what your experience has been, and any recommendations.
116
+ ```
117
+
118
+ Each segment needs an `index.md`:
119
+
120
+ ```markdown
121
+ ---
122
+ title: Cloud
123
+ color: "#3b82f6"
124
+ order: 1 # Determines quadrant position (1-4)
125
+ ---
126
+ ```
127
+
128
+ ## Configuration
129
+
130
+ Edit [`src/config.ts`](src/config.ts) to customize:
131
+
132
+ ```typescript
133
+ const config: SiteConfig = {
134
+ title: "Tech Radar", // Navbar title
135
+ // logo: '/logo.svg', // Optional logo in public/
136
+ footerText: "Built with Astro", // Footer text (supports HTML)
137
+ editBaseUrl: "https://github.com/...", // "Edit on GitHub" link base
138
+ // theme: 'catppuccin-mocha', // Theme name (see below)
139
+ socialLinks: [{ label: "GitHub", href: "...", icon: "..." }],
140
+ };
141
+ ```
142
+
143
+ ## Theming
144
+
145
+ Themes live in `src/themes/` as CSS files defining `--radar-*` custom properties.
146
+
147
+ | Theme | Description |
148
+ | :----------------- | :---------------------------------------------------- |
149
+ | `default` | Clean light/dark theme (follows system preference) |
150
+ | `catppuccin-mocha` | [Catppuccin Mocha](https://catppuccin.com) dark theme |
151
+
152
+ To create a custom theme, copy `src/themes/default.css`, rename it, adjust the CSS variables, and set `theme: 'your-theme'` in `src/config.ts`.
153
+
154
+ ## Project Structure
155
+
156
+ ```text
157
+ ├── segments/ # Technology content (Markdown)
158
+ │ ├── cloud/
159
+ │ ├── dev-languages/
160
+ │ ├── frameworks/
161
+ │ └── processes/
162
+ ├── src/
163
+ │ ├── components/ # Astro components (Radar, Legend, Cards, ...)
164
+ │ ├── layouts/ # Base HTML layout
165
+ │ ├── lib/ # Radar positioning algorithm
166
+ │ ├── pages/ # Route pages (index, segments, technology)
167
+ │ ├── styles/ # Global styles
168
+ │ ├── themes/ # Swappable CSS themes
169
+ │ └── config.ts # Site configuration
170
+ ├── public/ # Static assets (favicon, robots.txt)
171
+ ├── wrangler.json # Cloudflare Workers configuration
172
+ └── astro.config.mjs # Astro configuration
173
+ ```
174
+
175
+ ## Commands
176
+
177
+ | Command | Action |
178
+ | :---------------- | :----------------------------------- |
179
+ | `npm install` | Install dependencies |
180
+ | `npm run dev` | Start dev server at `localhost:4321` |
181
+ | `npm run build` | Build production site to `./dist/` |
182
+ | `npm run preview` | Preview the production build locally |
183
+
184
+ ## Adopt This Radar
185
+
186
+ This project is designed to be forked and customized for your own team or organization.
187
+
188
+ ### 1. Fork & Clone
189
+
190
+ ```bash
191
+ # GitLab or other hosts
192
+ git clone https://github.com/dirsigler/techradar.git my-techradar
193
+ cd my-techradar
194
+ git remote set-url origin https://gitlab.example.com/your-group/techradar.git
195
+ ```
196
+
197
+ ### 2. Replace Technologies
198
+
199
+ Delete the example content and add your own:
200
+
201
+ ```bash
202
+ # Remove example technologies (keep index.md files — they define segments)
203
+ find segments -name "*.md" ! -name "index.md" -delete
204
+ ```
205
+
206
+ Create technology files with this frontmatter:
207
+
208
+ ```markdown
209
+ ---
210
+ title: Your Technology
211
+ ring: adopt # adopt | trial | assess | hold
212
+ moved: 0 # 1 = moved in, -1 = moved out, 0 = unchanged
213
+ ---
214
+
215
+ Why this technology is in this ring and what your team's experience has been.
216
+ ```
217
+
218
+ ### 3. Customize Segments
219
+
220
+ Edit the `index.md` in each segment directory. You can rename, recolor, or replace segments entirely — just keep up to 4 directories under `segments/`:
221
+
222
+ ```markdown
223
+ ---
224
+ title: Infrastructure
225
+ color: "#3b82f6"
226
+ order: 1
227
+ ---
228
+ ```
229
+
230
+ ### 4. Configure
231
+
232
+ Update `src/config.ts` — all GitHub-specific values are in this single file:
233
+
234
+ ```typescript
235
+ const config: SiteConfig = {
236
+ title: "ACME Tech Radar",
237
+ footerText: "Built by the ACME Platform Team",
238
+ repositoryUrl: "https://gitlab.example.com/your-group/techradar",
239
+ editBaseUrl:
240
+ "https://gitlab.example.com/your-group/techradar/-/edit/main/segments",
241
+ socialLinks: [
242
+ {
243
+ label: "GitLab",
244
+ href: "https://gitlab.example.com/your-group/techradar",
245
+ // GitLab SVG icon path (24x24 viewBox)
246
+ icon: "M23.955 13.587l-1.342-4.135-2.664-8.189a.455.455 0 00-.867 0L16.418 9.45H7.582L4.918 1.263a.455.455 0 00-.867 0L1.387 9.452.045 13.587a.924.924 0 00.331 1.023L12 23.054l11.624-8.443a.92.92 0 00.331-1.024",
247
+ },
248
+ ],
249
+ };
250
+ ```
251
+
252
+ > **Note:** The `repositoryUrl` is used for the license link in the footer. The `editBaseUrl` powers the "Edit this page" links on technology pages. Both are optional.
253
+
254
+ ### 5. Deploy
255
+
256
+ The radar builds to fully static HTML — deploy it anywhere:
257
+
258
+ | Platform | Setup |
259
+ | :--------------------- | :------------------------------------------------------------------------------------------- |
260
+ | **Cloudflare Workers** | Connect your repo in the Cloudflare dashboard, build command `npm run build`, output `dist/` |
261
+ | **GitLab Pages** | Add a `.gitlab-ci.yml` with `npm run build` and publish the `dist/` directory |
262
+ | **Netlify / Vercel** | Connect your repo, build command `npm run build`, publish directory `dist/` |
263
+ | **GitHub Pages** | Use `actions/upload-pages-artifact` with `path: dist/` in a workflow |
264
+ | **Any static host** | Run `npm run build` and upload the `dist/` folder |
265
+
266
+ ## Commands
267
+
268
+ | Command | Action |
269
+ | :---------------- | :----------------------------------- |
270
+ | `npm install` | Install dependencies |
271
+ | `npm run dev` | Start dev server at `localhost:4321` |
272
+ | `npm run build` | Build production site to `./dist/` |
273
+ | `npm run preview` | Preview the production build locally |
274
+
275
+ ## License
276
+
277
+ [MIT](LICENSE) — Dennis Irsigler
package/config.ts ADDED
@@ -0,0 +1,54 @@
1
+ export interface SocialLink {
2
+ label: string;
3
+ href: string;
4
+ icon?: string; // optional SVG path data (24x24 viewBox)
5
+ }
6
+
7
+ export interface TechRadarUserConfig {
8
+ /** Navbar title text */
9
+ title: string;
10
+
11
+ /** Path to a logo image in the public/ directory (e.g. "/logo.svg"). Omit to show title only. */
12
+ logo?: string;
13
+
14
+ /** Footer text. Supports simple HTML. */
15
+ footerText?: string;
16
+
17
+ /** Base URL of the repository. Used for license link and edit URLs. */
18
+ repositoryUrl?: string;
19
+
20
+ /** Base URL for "Edit" links on technology pages. If omitted, derived from repositoryUrl. */
21
+ editBaseUrl?: string;
22
+
23
+ /** Social links shown in the footer. */
24
+ socialLinks?: SocialLink[];
25
+
26
+ /** Theme name — matches a built-in CSS file ('default' | 'catppuccin-mocha') or a path to a custom CSS file. Default: 'default' */
27
+ theme?: string;
28
+ }
29
+
30
+ export interface ResolvedConfig {
31
+ title: string;
32
+ logo?: string;
33
+ footerText: string;
34
+ repositoryUrl?: string;
35
+ editBaseUrl?: string;
36
+ socialLinks: SocialLink[];
37
+ theme: string;
38
+ }
39
+
40
+ export function resolveConfig(user: TechRadarUserConfig): ResolvedConfig {
41
+ return {
42
+ title: user.title,
43
+ logo: user.logo,
44
+ footerText: user.footerText ?? '',
45
+ repositoryUrl: user.repositoryUrl,
46
+ editBaseUrl:
47
+ user.editBaseUrl ??
48
+ (user.repositoryUrl
49
+ ? `${user.repositoryUrl}/edit/main/segments`
50
+ : undefined),
51
+ socialLinks: user.socialLinks ?? [],
52
+ theme: user.theme ?? 'default',
53
+ };
54
+ }
package/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { AstroIntegration } from 'astro';
2
+ import type { TechRadarUserConfig } from './config';
3
+ import { createIntegration } from './integration';
4
+
5
+ export default function techradar(
6
+ userConfig: TechRadarUserConfig,
7
+ ): AstroIntegration {
8
+ return createIntegration(userConfig);
9
+ }
10
+
11
+ export type { TechRadarUserConfig, ResolvedConfig, SocialLink } from './config';
package/integration.ts ADDED
@@ -0,0 +1,85 @@
1
+ import type { AstroIntegration } from 'astro';
2
+ import type { TechRadarUserConfig } from './config';
3
+ import { resolveConfig } from './config';
4
+ import tailwindcss from '@tailwindcss/vite';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { readFileSync, existsSync } from 'node:fs';
7
+ import path from 'node:path';
8
+
9
+ const PKG_DIR = path.dirname(fileURLToPath(import.meta.url));
10
+
11
+ export function createIntegration(
12
+ userConfig: TechRadarUserConfig,
13
+ ): AstroIntegration {
14
+ const config = resolveConfig(userConfig);
15
+
16
+ return {
17
+ name: '@dirsigler/techradar',
18
+ hooks: {
19
+ 'astro:config:setup'({ injectRoute, updateConfig }) {
20
+ // Inject all routes
21
+ injectRoute({
22
+ pattern: '/',
23
+ entrypoint: path.join(PKG_DIR, 'src/pages/index.astro'),
24
+ });
25
+ injectRoute({
26
+ pattern: '/404',
27
+ entrypoint: path.join(PKG_DIR, 'src/pages/404.astro'),
28
+ });
29
+ injectRoute({
30
+ pattern: '/segments/[segment]',
31
+ entrypoint: path.join(PKG_DIR, 'src/pages/segments/[segment].astro'),
32
+ });
33
+ injectRoute({
34
+ pattern: '/technology/[...slug]',
35
+ entrypoint: path.join(
36
+ PKG_DIR,
37
+ 'src/pages/technology/[...slug].astro',
38
+ ),
39
+ });
40
+
41
+ // Resolve theme CSS
42
+ let themeCSS = '';
43
+ const builtinPath = path.join(
44
+ PKG_DIR,
45
+ `src/themes/${config.theme}.css`,
46
+ );
47
+ if (existsSync(builtinPath)) {
48
+ themeCSS = readFileSync(builtinPath, 'utf-8');
49
+ } else if (existsSync(config.theme)) {
50
+ // User provided an absolute or relative path to a custom theme
51
+ themeCSS = readFileSync(config.theme, 'utf-8');
52
+ }
53
+
54
+ // Virtual modules for config and theme
55
+ const VIRTUAL_CONFIG = 'virtual:techradar/config';
56
+ const RESOLVED_CONFIG = '\0' + VIRTUAL_CONFIG;
57
+ const VIRTUAL_THEME = 'virtual:techradar/theme';
58
+ const RESOLVED_THEME = '\0' + VIRTUAL_THEME;
59
+
60
+ updateConfig({
61
+ vite: {
62
+ plugins: [
63
+ tailwindcss(),
64
+ {
65
+ name: 'techradar-virtual-modules',
66
+ resolveId(id: string) {
67
+ if (id === VIRTUAL_CONFIG) return RESOLVED_CONFIG;
68
+ if (id === VIRTUAL_THEME) return RESOLVED_THEME;
69
+ },
70
+ load(id: string) {
71
+ if (id === RESOLVED_CONFIG) {
72
+ return `export default ${JSON.stringify(config)}`;
73
+ }
74
+ if (id === RESOLVED_THEME) {
75
+ return `export default ${JSON.stringify(themeCSS)}`;
76
+ }
77
+ },
78
+ },
79
+ ],
80
+ },
81
+ });
82
+ },
83
+ },
84
+ };
85
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@dirsigler/techradar",
3
+ "version": "1.0.4",
4
+ "type": "module",
5
+ "description": "An interactive technology radar Astro integration — track technology adoption across your organization",
6
+ "license": "MIT",
7
+ "author": "Dennis Irsigler <dennis@irsigler.dev>",
8
+ "homepage": "https://github.com/dirsigler/techradar",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/dirsigler/techradar.git"
12
+ },
13
+ "keywords": [
14
+ "astro-integration",
15
+ "techradar",
16
+ "technology-radar",
17
+ "radar",
18
+ "engineering"
19
+ ],
20
+ "exports": {
21
+ ".": "./index.ts",
22
+ "./schemas": "./schemas.ts"
23
+ },
24
+ "files": [
25
+ "index.ts",
26
+ "integration.ts",
27
+ "config.ts",
28
+ "schemas.ts",
29
+ "virtual.d.ts",
30
+ "src/**/*"
31
+ ],
32
+ "engines": {
33
+ "node": ">=22.12.0"
34
+ },
35
+ "peerDependencies": {
36
+ "astro": "^6.0.0"
37
+ },
38
+ "dependencies": {
39
+ "@tailwindcss/typography": "^0.5.19",
40
+ "@tailwindcss/vite": "^4.2.1",
41
+ "tailwindcss": "^4.2.1"
42
+ }
43
+ }
package/schemas.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { z } from 'astro:content';
2
+
3
+ export const segmentSchema = z.object({
4
+ title: z.string(),
5
+ order: z.number().int().min(1).max(4),
6
+ color: z.string().regex(/^#[0-9a-fA-F]{6}$/),
7
+ });
8
+
9
+ export const technologySchema = z.object({
10
+ title: z.string(),
11
+ ring: z.enum(['adopt', 'trial', 'assess', 'hold']),
12
+ moved: z.number().int().min(-1).max(1).default(0),
13
+ });
@@ -0,0 +1,10 @@
1
+ ---
2
+ interface Props {
3
+ moved: number;
4
+ }
5
+
6
+ const { moved } = Astro.props;
7
+ ---
8
+
9
+ {moved === 1 && <span style="color: var(--radar-moved-in);" title="Moved in">&#9650;</span>}
10
+ {moved === -1 && <span style="color: var(--radar-moved-out);" title="Moved out">&#9660;</span>}