@dirsigler/astro-techradar 0.2.2 → 0.4.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/README.md CHANGED
@@ -109,12 +109,29 @@ Each technology file:
109
109
  title: Kubernetes
110
110
  ring: adopt
111
111
  moved: 0
112
+ history:
113
+ - date: "2025-03"
114
+ ring: adopt
115
+ description: "Promoted after 2 years of successful production use."
116
+ - date: "2023-01"
117
+ ring: trial
118
+ description: "Started evaluating for container orchestration."
119
+ - date: "2022-06"
120
+ ring: assess
112
121
  ---
113
122
 
114
123
  Your description in Markdown. Explain why this technology is in this ring
115
124
  and what your experience has been.
116
125
  ```
117
126
 
127
+ The `history` field is optional. When present, a timeline is rendered on the technology detail page showing how its ring classification changed over time. Each entry has:
128
+
129
+ | Field | Required | Description |
130
+ | ----- | -------- | ----------- |
131
+ | `date` | yes | Free-text date string (e.g. `"2025-03"`, `"Q1 2025"`) |
132
+ | `ring` | yes | The ring at that point in time (`adopt`, `trial`, `assess`, `hold`) |
133
+ | `description` | no | Short rationale for the change |
134
+
118
135
  ### 5. Run
119
136
 
120
137
  ```bash
package/config.ts CHANGED
@@ -18,11 +18,14 @@ export interface ResolvedColorMode {
18
18
  }
19
19
 
20
20
  export interface TechRadarUserConfig {
21
- /** Navbar title text */
22
- title: string;
21
+ /** Brand name shown in the navbar. */
22
+ name: string;
23
+
24
+ /** Main page title shown as the h1 heading. Falls back to name if not set. */
25
+ title?: string;
23
26
 
24
- /** Main page headline. Falls back to title if not set. */
25
- headline?: string;
27
+ /** Subtitle shown below the title on the main page. */
28
+ subtitle?: string;
26
29
 
27
30
  /**
28
31
  * URL path prefix where the tech radar is mounted (e.g. "/techradar").
@@ -54,8 +57,9 @@ export interface TechRadarUserConfig {
54
57
  }
55
58
 
56
59
  export interface ResolvedConfig {
60
+ name: string;
57
61
  title: string;
58
- headline: string;
62
+ subtitle?: string;
59
63
  /** Normalized base path with leading slash, no trailing slash. Empty string when mounted at root. */
60
64
  basePath: string;
61
65
  logo?: string;
@@ -76,8 +80,9 @@ function normalizeBasePath(raw?: string): string {
76
80
 
77
81
  export function resolveConfig(user: TechRadarUserConfig): ResolvedConfig {
78
82
  return {
79
- title: user.title,
80
- headline: user.headline ?? user.title,
83
+ name: user.name,
84
+ title: user.title ?? user.name,
85
+ subtitle: user.subtitle,
81
86
  basePath: normalizeBasePath(user.basePath),
82
87
  logo: user.logo,
83
88
  footerText: user.footerText ?? '',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dirsigler/astro-techradar",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "An interactive technology radar Astro integration — track technology adoption across your organization",
6
6
  "license": "MIT",
package/schemas.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import { z } from 'astro/zod';
2
+ import { RINGS } from './src/lib/radar';
3
+
4
+ const ringEnum = z.enum(RINGS);
2
5
 
3
6
  export const segmentSchema = z.object({
4
7
  title: z.string(),
@@ -8,6 +11,15 @@ export const segmentSchema = z.object({
8
11
 
9
12
  export const technologySchema = z.object({
10
13
  title: z.string(),
11
- ring: z.enum(['adopt', 'trial', 'assess', 'hold']),
14
+ ring: ringEnum,
12
15
  moved: z.number().int().min(-1).max(1).default(0),
16
+ history: z
17
+ .array(
18
+ z.object({
19
+ date: z.string(),
20
+ ring: ringEnum,
21
+ description: z.string().optional(),
22
+ }),
23
+ )
24
+ .optional(),
13
25
  });
@@ -10,7 +10,7 @@ interface Props {
10
10
  description?: string;
11
11
  }
12
12
 
13
- const { title = config.title, description = 'Technology Radar — tracking technology adoption across our organization' } = Astro.props;
13
+ const { title = config.name, description = 'Technology Radar — tracking technology adoption across our organization' } = Astro.props;
14
14
  const siteBase = import.meta.env.BASE_URL.replace(/\/+$/, '');
15
15
  const base = `${siteBase}${config.basePath}/`;
16
16
  const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
@@ -61,11 +61,11 @@ const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
61
61
  {config.logo && (
62
62
  <img
63
63
  src={config.logo.startsWith('https://') ? config.logo : `${base}${config.logo.replace(/^\//, '')}`}
64
- alt={config.title}
64
+ alt={config.name}
65
65
  class="h-8 w-auto"
66
66
  />
67
67
  )}
68
- {config.title}
68
+ {config.name}
69
69
  </a>
70
70
  {config.color.toggle && <ThemeToggle />}
71
71
  </nav>
@@ -53,12 +53,14 @@ const legendSegments = segments.map((s) => ({
53
53
  const ringEntries = Object.entries(RING_LABELS) as [string, string][];
54
54
  ---
55
55
 
56
- <Base title={config.title}>
56
+ <Base title={config.name}>
57
57
  <div class="text-center mb-10">
58
- <h1 class="text-4xl font-bold" style="color: var(--radar-text);">{config.headline}</h1>
59
- <p class="mt-3 text-lg" style="color: var(--radar-text-muted);">
60
- An overview of the technologies, frameworks, processes, and languages we use and evaluate.
61
- </p>
58
+ <h1 class="text-4xl font-bold" style="color: var(--radar-text);">{config.title}</h1>
59
+ {config.subtitle && (
60
+ <p class="mt-3 text-lg" style="color: var(--radar-text-muted);">
61
+ {config.subtitle}
62
+ </p>
63
+ )}
62
64
  </div>
63
65
 
64
66
  <!-- Filter bar -->
@@ -70,6 +70,31 @@ const editUrl = config.editBaseUrl
70
70
  <Content />
71
71
  </div>
72
72
 
73
+ {entry.data.history && entry.data.history.length > 0 && (
74
+ <section class="mt-10">
75
+ <h2 class="text-xl font-semibold mb-4" style="color: var(--radar-text);">History</h2>
76
+ <ol class="history-timeline">
77
+ {[...entry.data.history].sort((a, b) => b.date.localeCompare(a.date)).map((h) => (
78
+ <li class="history-entry">
79
+ <div class="history-marker">
80
+ <span class={`history-dot ring-${h.ring}`} />
81
+ <span class="history-line" />
82
+ </div>
83
+ <div class="history-content">
84
+ <div class="flex items-center gap-2 flex-wrap">
85
+ <RingBadge ring={h.ring} />
86
+ <time class="text-sm" style="color: var(--radar-text-faint);">{h.date}</time>
87
+ </div>
88
+ {h.description && (
89
+ <p class="mt-1 text-sm" style="color: var(--radar-text-muted);">{h.description}</p>
90
+ )}
91
+ </div>
92
+ </li>
93
+ ))}
94
+ </ol>
95
+ </section>
96
+ )}
97
+
73
98
  {editUrl && (
74
99
  <div class="mt-8 pt-6" style="border-top: 1px solid var(--radar-border);">
75
100
  <a
@@ -110,4 +135,57 @@ const editUrl = config.editBaseUrl
110
135
  .edit-link:hover {
111
136
  color: var(--radar-link);
112
137
  }
138
+
139
+ .history-timeline {
140
+ list-style: none;
141
+ padding: 0;
142
+ margin: 0;
143
+ }
144
+
145
+ .history-entry {
146
+ display: flex;
147
+ gap: 0.75rem;
148
+ position: relative;
149
+ }
150
+
151
+ .history-marker {
152
+ display: flex;
153
+ flex-direction: column;
154
+ align-items: center;
155
+ flex-shrink: 0;
156
+ width: 1rem;
157
+ }
158
+
159
+ .history-dot {
160
+ width: 0.75rem;
161
+ height: 0.75rem;
162
+ border-radius: 9999px;
163
+ flex-shrink: 0;
164
+ margin-top: 0.375rem;
165
+ }
166
+
167
+ .history-dot.ring-adopt { background-color: var(--radar-ring-adopt); }
168
+ .history-dot.ring-trial { background-color: var(--radar-ring-trial); }
169
+ .history-dot.ring-assess { background-color: var(--radar-ring-assess); }
170
+ .history-dot.ring-hold { background-color: var(--radar-ring-hold); }
171
+
172
+ .history-line {
173
+ flex: 1;
174
+ width: 2px;
175
+ background-color: var(--radar-border, #e2e8f0);
176
+ margin-top: 0.25rem;
177
+ margin-bottom: 0.25rem;
178
+ }
179
+
180
+ .history-entry:last-child .history-line {
181
+ display: none;
182
+ }
183
+
184
+ .history-content {
185
+ padding-bottom: 1.25rem;
186
+ }
187
+
188
+ .history-entry:last-child .history-content {
189
+ padding-bottom: 0;
190
+ }
113
191
  </style>