Add base app version

This commit is contained in:
Joshua Creek
2024-09-26 17:34:32 +01:00
parent af9ff16b3b
commit d7f48d29ad
19 changed files with 2831 additions and 1 deletions
+24
View File
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+3
View File
@@ -0,0 +1,3 @@
{
"recommendations": ["svelte.svelte-vscode"]
}
+83 -1
View File
@@ -1,2 +1,84 @@
# Tech-Radar-Editor
# Tech Radar Editor
A web component that allows users to easily create and edit a Tech Radar.
## Who created the Tech Radar?
[ThoughtWorks](https://thoughtworks.com/radar) created the Tech Radar concept, and [Zalando created the visualization](https://opensource.zalando.com/tech-radar/) that is popular today.
## Building the Component
To build the component, you need to have Node.js installed. Clone the repository and run the following commands:
```bash
pnpm install
pnpm build
```
To get it ready to add to NPM or a CDN, run:
```bash
pnpm build
pnpm pack
```
To publish the component to NPM, run:
```bash
pnpm publish
```
## Consume the Component in Plain JavaScript
Include the component in an HTML file:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tech Radar Editor</title>
<script type="module" src="./tech-radar-editor.es.js"></script>
</head>
<body>
<tech-radar-editor></tech-radar-editor>
</body>
</html>
```
## Consume the Component in React
In a React project, you can use the web component as you would use any custom HTML element.
First, ensure that the component is imported or included:
```js
// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
// Import the component
import "tech-radar-editor";
function App() {
return (
<div className="App">
<tech-radar-editor></tech-radar-editor>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
```
Note: In React, you might need to instruct TypeScript about the custom element. Create a react-app-env.d.ts or a global.d.ts file:
```ts
// react-app-env.d.ts
declare namespace JSX {
interface IntrinsicElements {
"tech-radar-editor": any;
}
}
```
+13
View File
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tech Radar Editor</title>
<script type="module" src="/src/main.ts"></script>
</head>
<body>
<tech-radar-editor></tech-radar-editor>
</body>
</html>
+36
View File
@@ -0,0 +1,36 @@
{
"name": "tech-radar-editor",
"version": "1.0.0",
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/jcreek/Tech-Radar-Editor.git"
},
"main": "dist/tech-radar-editor.umd.js",
"module": "dist/tech-radar-editor.es.js",
"types": "dist/main.d.ts",
"files": [
"dist"
],
"scripts": {
"dev": "vite",
"build": "vite build && tsc -p tsconfig.build.json",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json && tsc -p tsconfig.node.json"
},
"dependencies": {
"svelte": "^4.2.18"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@tsconfig/svelte": "^5.0.4",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.47",
"postcss-load-config": "^6.0.1",
"svelte-check": "^3.8.5",
"tailwindcss": "^3.4.13",
"tslib": "^2.6.3",
"typescript": "^5.5.3",
"vite": "^5.4.1"
}
}
+1873
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+506
View File
@@ -0,0 +1,506 @@
<svelte:options customElement="tech-radar-editor" />
<style lang="postcss">
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
<script lang="ts">
interface TechRadarData {
title: string;
quadrants: Quadrant[];
rings: Ring[];
entries: Entry[];
}
interface Quadrant {
id: string;
name: string;
expanded?: boolean;
}
interface Ring {
id: string;
name: string;
color: string;
description?: string;
expanded?: boolean;
}
interface Entry {
id: string;
title: string;
description?: string;
key: string;
url?: string;
quadrant: string;
timeline: TimelineEntry[];
expanded?: boolean;
}
interface TimelineEntry {
id: string;
moved: number; // -1, 0, 1
ringId: string;
date: string; // format YYYY-MM-dd
description: string;
expanded?: boolean;
}
let techRadarData: TechRadarData = {
title: '',
quadrants: [],
rings: [],
entries: []
};
let jsonTextarea: HTMLTextAreaElement;
let showRings = false;
let showQuadrants = false;
let showEntries = false;
let idCounter = 0;
function generateId() {
return `id-${idCounter++}`;
}
function updateEntry(updatedEntry: Entry) {
techRadarData.entries = techRadarData.entries.map(entry =>
entry.id === updatedEntry.id ? updatedEntry : entry
);
}
function loadJson() {
try {
const parsedData = JSON.parse(jsonTextarea.value);
initializeData(parsedData);
techRadarData = parsedData;
showRings = false;
showQuadrants = false;
showEntries = false;
} catch (error) {
alert('Invalid JSON format');
console.error(error);
}
}
function initializeData(data: TechRadarData) {
data.entries.forEach((entry: Entry) => {
entry.expanded = false;
if (!entry.timeline) entry.timeline = [];
entry.timeline.forEach((timelineItem: TimelineEntry) => {
timelineItem.expanded = false;
timelineItem.moved = Number(timelineItem.moved);
if (!timelineItem.id) timelineItem.id = generateId();
});
if (!entry.id) entry.id = generateId();
});
data.rings.forEach((ring: Ring) => {
ring.expanded = false;
if (!ring.id) ring.id = generateId();
});
data.quadrants.forEach((quadrant: Quadrant) => {
quadrant.expanded = false;
if (!quadrant.id) quadrant.id = generateId();
});
}
function addRing() {
const newRing: Ring = {
id: generateId(),
name: 'New Ring',
color: '#000000',
description: '',
expanded: true
};
techRadarData.rings = [...techRadarData.rings, newRing];
}
function addQuadrant() {
const newQuadrant: Quadrant = {
id: generateId(),
name: 'New Quadrant',
expanded: true
};
techRadarData.quadrants = [...techRadarData.quadrants, newQuadrant];
}
function addEntry() {
const newEntry: Entry = {
id: generateId(),
title: 'New Entry',
description: '',
key: 'new-key',
url: '',
quadrant: techRadarData.quadrants.length > 0 ? techRadarData.quadrants[0].id : '',
timeline: [],
expanded: true
};
techRadarData.entries = [...techRadarData.entries, newEntry];
}
function addTimelineEntry(entryId: string) {
const entry = techRadarData.entries.find(e => e.id === entryId);
if (entry) {
const newTimelineEntry: TimelineEntry = {
id: generateId(),
moved: 0,
ringId: techRadarData.rings.length > 0 ? techRadarData.rings[0].id : '',
date: '',
description: '',
expanded: true
};
entry.timeline = [...entry.timeline, newTimelineEntry];
updateEntry({ ...entry });
}
}
function removeItem<T>(items: T[], itemId: string): T[] {
return items.filter((item: any) => item.id !== itemId);
}
function removeRing(ringId: string) {
if (confirm('Are you sure you want to remove this ring?')) {
techRadarData.rings = removeItem(techRadarData.rings, ringId);
}
}
function removeQuadrant(quadrantId: string) {
if (confirm('Are you sure you want to remove this quadrant?')) {
techRadarData.quadrants = removeItem(techRadarData.quadrants, quadrantId);
}
}
function removeEntry(entryId: string) {
if (confirm('Are you sure you want to remove this entry?')) {
techRadarData.entries = removeItem(techRadarData.entries, entryId);
}
}
function removeTimelineEntry(entryId: string, timelineItemId: string) {
const entry = techRadarData.entries.find(e => e.id === entryId);
if (entry) {
if (confirm('Are you sure you want to remove this timeline entry?')) {
entry.timeline = removeItem(entry.timeline, timelineItemId);
updateEntry({ ...entry });
}
}
}
function exportJson() {
// Perform validation
const validationErrors = validateTechRadarData(techRadarData);
if (validationErrors.length > 0) {
alert('Validation errors:\n' + validationErrors.join('\n'));
return;
}
const jsonString = JSON.stringify(techRadarData, null, 2);
navigator.clipboard.writeText(jsonString)
.then(() => alert('JSON data has been copied to the clipboard!'))
.catch(() => alert('Failed to copy JSON data.'));
}
function validateTechRadarData(data: TechRadarData): string[] {
const errors: string[] = [];
// Validate rings
data.rings.forEach((ring, index) => {
if (!ring.id) errors.push(`Ring ${index + 1}: ID is required.`);
if (!ring.name) errors.push(`Ring ${index + 1}: Name is required.`);
if (!ring.color) errors.push(`Ring ${index + 1}: Color is required.`);
});
// Validate quadrants
data.quadrants.forEach((quadrant, index) => {
if (!quadrant.id) errors.push(`Quadrant ${index + 1}: ID is required.`);
if (!quadrant.name) errors.push(`Quadrant ${index + 1}: Name is required.`);
});
// Validate entries
data.entries.forEach((entry, index) => {
if (!entry.id) errors.push(`Entry ${index + 1}: ID is required.`);
if (!entry.title) errors.push(`Entry ${index + 1}: Title is required.`);
if (!entry.key) errors.push(`Entry ${index + 1}: Key is required.`);
if (!entry.quadrant) errors.push(`Entry ${index + 1}: Quadrant is required.`);
if (!entry.timeline || entry.timeline.length === 0) {
errors.push(`Entry ${index + 1}: At least one timeline entry is required.`);
} else {
entry.timeline.forEach((timelineItem, timelineIndex) => {
if (typeof timelineItem.moved !== 'number') {
errors.push(`Entry ${index + 1}, Timeline ${timelineIndex + 1}: Moved must be a number.`);
}
if (!timelineItem.ringId) {
errors.push(`Entry ${index + 1}, Timeline ${timelineIndex + 1}: Ring ID is required.`);
}
if (!timelineItem.date) {
errors.push(`Entry ${index + 1}, Timeline ${timelineIndex + 1}: Date is required.`);
}
if (!timelineItem.description) {
errors.push(`Entry ${index + 1}, Timeline ${timelineIndex + 1}: Description is required.`);
}
});
}
});
return errors;
}
// Reactive statement to update JSON preview whenever techRadarData changes
$: jsonString = JSON.stringify(techRadarData, null, 2);
</script>
<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Tech Radar Editor</h1>
<div class="mb-4">
<textarea
bind:this={jsonTextarea}
class="w-full p-2 border rounded text-black"
placeholder="Paste your JSON here..."
></textarea>
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mt-2" on:click={loadJson}>
Load JSON
</button>
</div>
<!-- Rings Section -->
<h2 class="text-xl font-bold mb-2 flex items-center">
<button on:click={() => showRings = !showRings} type="button" class="mr-2">
{#if showRings}
[-]
{:else}
[+]
{/if}
</button>
Rings
</h2>
{#if showRings}
<button class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mb-4" on:click={addRing}>
Add Ring
</button>
{#each techRadarData.rings as ring, ringIndex (ring.id)}
<fieldset class="border p-2 mb-2">
<legend class="font-bold flex items-center">
<button on:click={() => ring.expanded = !ring.expanded} type="button" class="mr-2">
{#if ring.expanded}
[-]
{:else}
[+]
{/if}
</button>
Ring {ringIndex + 1}: {ring.name}
</legend>
{#if ring.expanded}
<label class="block mb-1">
ID:
<input type="text" bind:value={ring.id} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
Name:
<input type="text" bind:value={ring.name} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
Color:
<input type="color" bind:value={ring.color} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
Description:
<textarea bind:value={ring.description} class="border p-1 w-full text-black"></textarea>
</label>
<button class="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded" on:click={() => removeRing(ring.id)} type="button">Remove Ring</button>
{/if}
</fieldset>
{/each}
{/if}
<!-- Quadrants Section -->
<h2 class="text-xl font-bold mb-2 flex items-center">
<button on:click={() => showQuadrants = !showQuadrants} type="button" class="mr-2">
{#if showQuadrants}
[-]
{:else}
[+]
{/if}
</button>
Quadrants
</h2>
{#if showQuadrants}
<button class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mb-4" on:click={addQuadrant}>
Add Quadrant
</button>
{#each techRadarData.quadrants as quadrant, quadrantIndex (quadrant.id)}
<fieldset class="border p-2 mb-2">
<legend class="font-bold flex items-center">
<button on:click={() => quadrant.expanded = !quadrant.expanded} type="button" class="mr-2">
{#if quadrant.expanded}
[-]
{:else}
[+]
{/if}
</button>
Quadrant {quadrantIndex + 1}: {quadrant.name}
</legend>
{#if quadrant.expanded}
<label class="block mb-1">
ID:
<input type="text" bind:value={quadrant.id} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
Name:
<input type="text" bind:value={quadrant.name} class="border p-1 w-full text-black"/>
</label>
<button class="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded" on:click={() => removeQuadrant(quadrant.id)} type="button">Remove Quadrant</button>
{/if}
</fieldset>
{/each}
{/if}
<!-- Entries Section -->
<h2 class="text-xl font-bold mb-2 flex items-center">
<button on:click={() => showEntries = !showEntries} type="button" class="mr-2">
{#if showEntries}
[-]
{:else}
[+]
{/if}
</button>
Entries
</h2>
{#if showEntries}
<button class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mb-4" on:click={addEntry}>
Add Entry
</button>
{#each techRadarData.entries as entry, entryIndex (entry.id)}
<fieldset class="border p-2 mb-2">
<legend class="font-bold flex items-center">
<button on:click={() => entry.expanded = !entry.expanded} type="button" class="mr-2">
{#if entry.expanded}
[-]
{:else}
[+]
{/if}
</button>
Entry {entryIndex + 1}: {entry.title}
</legend>
{#if entry.expanded}
<label class="block mb-1">
ID:
<input type="text" bind:value={entry.id} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
Title:
<input type="text" bind:value={entry.title} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
Description:
<textarea bind:value={entry.description} class="border p-1 w-full text-black"></textarea>
</label>
<label class="block mb-1">
Key:
<input type="text" bind:value={entry.key} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
URL:
<input type="text" bind:value={entry.url} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
Quadrant:
<select bind:value={entry.quadrant} class="border p-1 w-full text-black">
{#each techRadarData.quadrants as quadrant}
<option value={quadrant.id}>{quadrant.name}</option>
{/each}
</select>
</label>
<button class="bg-green-500 hover:bg-green-700 text-white font-bold py-1 px-2 rounded mb-2" on:click={() => addTimelineEntry(entry.id)} type="button">Add Timeline Entry</button>
<button class="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded mb-2" on:click={() => removeEntry(entry.id)} type="button">Remove Entry</button>
<!-- Timeline entries -->
{#each entry.timeline as timelineItem, timelineIndex (timelineItem.id)}
<fieldset class="border p-2 mb-2">
<legend class="font-bold flex items-center">
<button on:click={() => timelineItem.expanded = !timelineItem.expanded} type="button" class="mr-2">
{#if timelineItem.expanded}
[-]
{:else}
[+]
{/if}
</button>
Timeline {timelineIndex + 1}
</legend>
{#if timelineItem.expanded}
<label class="block mb-1">
Moved:
<select bind:value={timelineItem.moved} class="border p-1 w-full text-black">
<option value={-1}>Moved Out (-1)</option>
<option value={0}>Stayed (0)</option>
<option value={1}>Moved In (1)</option>
</select>
</label>
<label class="block mb-1">
Ring ID:
<select bind:value={timelineItem.ringId} class="border p-1 w-full text-black">
{#each techRadarData.rings as ring}
<option value={ring.id}>{ring.name}</option>
{/each}
</select>
</label>
<label class="block mb-1">
Date:
<input type="date" bind:value={timelineItem.date} class="border p-1 w-full text-black"/>
</label>
<label class="block mb-1">
Description:
<textarea bind:value={timelineItem.description} class="border p-1 w-full text-black"></textarea>
</label>
<button class="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded" on:click={() => removeTimelineEntry(entry.id, timelineItem.id)} type="button">Remove Timeline Entry</button>
{/if}
</fieldset>
{/each}
{/if}
</fieldset>
{/each}
{/if}
<button class="bg-purple-500 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded mb-4 mt-4" on:click={exportJson}>
Export JSON
</button>
<h2 class="text-xl font-bold mb-2">JSON Preview:</h2>
<pre class="p-2 bg-gray-100 rounded text-black">{jsonString}</pre>
</div>
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="26.6" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 308"><path fill="#FF3E00" d="M239.682 40.707C211.113-.182 154.69-12.301 113.895 13.69L42.247 59.356a82.198 82.198 0 0 0-37.135 55.056a86.566 86.566 0 0 0 8.536 55.576a82.425 82.425 0 0 0-12.296 30.719a87.596 87.596 0 0 0 14.964 66.244c28.574 40.893 84.997 53.007 125.787 27.016l71.648-45.664a82.182 82.182 0 0 0 37.135-55.057a86.601 86.601 0 0 0-8.53-55.577a82.409 82.409 0 0 0 12.29-30.718a87.573 87.573 0 0 0-14.963-66.244"></path><path fill="#FFF" d="M106.889 270.841c-23.102 6.007-47.497-3.036-61.103-22.648a52.685 52.685 0 0 1-9.003-39.85a49.978 49.978 0 0 1 1.713-6.693l1.35-4.115l3.671 2.697a92.447 92.447 0 0 0 28.036 14.007l2.663.808l-.245 2.659a16.067 16.067 0 0 0 2.89 10.656a17.143 17.143 0 0 0 18.397 6.828a15.786 15.786 0 0 0 4.403-1.935l71.67-45.672a14.922 14.922 0 0 0 6.734-9.977a15.923 15.923 0 0 0-2.713-12.011a17.156 17.156 0 0 0-18.404-6.832a15.78 15.78 0 0 0-4.396 1.933l-27.35 17.434a52.298 52.298 0 0 1-14.553 6.391c-23.101 6.007-47.497-3.036-61.101-22.649a52.681 52.681 0 0 1-9.004-39.849a49.428 49.428 0 0 1 22.34-33.114l71.664-45.677a52.218 52.218 0 0 1 14.563-6.398c23.101-6.007 47.497 3.036 61.101 22.648a52.685 52.685 0 0 1 9.004 39.85a50.559 50.559 0 0 1-1.713 6.692l-1.35 4.116l-3.67-2.693a92.373 92.373 0 0 0-28.037-14.013l-2.664-.809l.246-2.658a16.099 16.099 0 0 0-2.89-10.656a17.143 17.143 0 0 0-18.398-6.828a15.786 15.786 0 0 0-4.402 1.935l-71.67 45.674a14.898 14.898 0 0 0-6.73 9.975a15.9 15.9 0 0 0 2.709 12.012a17.156 17.156 0 0 0 18.404 6.832a15.841 15.841 0 0 0 4.402-1.935l27.345-17.427a52.147 52.147 0 0 1 14.552-6.397c23.101-6.006 47.497 3.037 61.102 22.65a52.681 52.681 0 0 1 9.003 39.848a49.453 49.453 0 0 1-22.34 33.12l-71.664 45.673a52.218 52.218 0 0 1-14.563 6.398"></path></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

+1
View File
@@ -0,0 +1 @@
import TechRadarEditor from "./TechRadarEditor.svelte";
+2
View File
@@ -0,0 +1,2 @@
/// <reference types="svelte" />
/// <reference types="vite/client" />
+8
View File
@@ -0,0 +1,8 @@
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
export default {
compilerOptions: {
customElement: true,
},
preprocess: vitePreprocess(),
};
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
content: ["./src/**/*.{svelte,js,ts}", "./public/index.html"],
theme: {
extend: {},
},
plugins: [],
};
+203
View File
@@ -0,0 +1,203 @@
{
"title": "Tech Radar",
"quadrants": [
{
"id": "infrastructure",
"name": "Infrastructure"
},
{
"id": "frameworks",
"name": "Frameworks"
},
{
"id": "languages",
"name": "Languages"
},
{
"id": "process",
"name": "Process"
}
],
"rings": [
{
"id": "adopt",
"name": "ADOPT",
"color": "#5BA300",
"description": "Commodi accusantium culpa sed itaque excepturi rem eum nulla possimus."
},
{
"id": "trial",
"name": "TRIAL",
"color": "#009EB0",
"description": "Recusandae possimus ipsum dolores."
},
{
"id": "assess",
"name": "ASSESS",
"color": "#C7BA00",
"description": "In asperiores repellat error recusandae et adipisci laborum porro."
},
{
"id": "hold",
"name": "HOLD",
"color": "#E09B96",
"description": "Esse mollitia in."
}
],
"entries": [
{
"timeline": [
{
"moved": 0,
"ringId": "adopt",
"date": "2020-08-06",
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
}
],
"key": "javascript",
"id": "javascript",
"title": "JavaScript",
"quadrant": "languages",
"links": [
{
"url": "https://www.javascript.com/",
"title": "Learn more"
},
{
"url": "https://www.typescriptlang.org/",
"title": "TypeScript"
}
],
"description": "Excepteur **sint** occaecat *cupidatat* non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"timeline": [
{
"moved": -1,
"ringId": "adopt",
"date": "2020-08-06",
"description": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat"
}
],
"key": "typescript",
"id": "typescript",
"title": "TypeScript",
"quadrant": "languages",
"description": "Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat"
},
{
"timeline": [
{
"moved": 1,
"ringId": "adopt",
"date": "2020-08-06",
"description": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur"
}
],
"links": [
{
"url": "https://webpack.js.org/",
"title": "Learn more"
}
],
"key": "webpack",
"id": "webpack",
"title": "Webpack",
"quadrant": "frameworks"
},
{
"timeline": [
{
"moved": 0,
"ringId": "adopt",
"date": "2020-08-06"
}
],
"links": [
{
"url": "https://reactjs.org/",
"title": "Learn more"
}
],
"key": "react",
"id": "react",
"title": "React",
"quadrant": "frameworks"
},
{
"timeline": [
{
"moved": 0,
"ringId": "adopt",
"date": "2020-08-06"
}
],
"key": "code-reviews",
"id": "code-reviews",
"title": "Code Reviews",
"quadrant": "process"
},
{
"timeline": [
{
"moved": 0,
"ringId": "assess",
"date": "2020-08-06"
}
],
"key": "mob-programming",
"id": "mob-programming",
"title": "Mob Programming",
"quadrant": "process"
},
{
"timeline": [
{
"moved": 0,
"ringId": "adopt",
"date": "2020-08-06"
}
],
"key": "docs-like-code",
"id": "docs-like-code",
"title": "Docs-like-code",
"quadrant": "process"
},
{
"timeline": [
{
"ringId": "hold",
"date": "2020-08-06"
}
],
"key": "force-push",
"id": "force-push",
"title": "Force push to master",
"quadrant": "process"
},
{
"timeline": [
{
"ringId": "adopt",
"date": "2020-08-06",
"description": "long description"
},
{
"ringId": "trial",
"date": "2020-07-05",
"description": "long description"
}
],
"links": [
{
"url": "https://github.com",
"title": "Learn more"
}
],
"key": "github-actions",
"id": "github-actions",
"title": "GitHub Actions",
"quadrant": "infrastructure"
}
]
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"declaration": true,
"declarationDir": "dist",
"emitDeclarationOnly": true
},
"include": ["src/**/*"]
}
+21
View File
@@ -0,0 +1,21 @@
{
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"resolveJsonModule": true,
/**
* Typecheck JS in `.svelte` and `.js` files by default.
* Disable checkJs if you'd like to use dynamic types in JS.
* Note that setting allowJs false does not prevent the use
* of JS in `.svelte` files.
*/
"allowJs": true,
"checkJs": true,
"isolatedModules": true,
"moduleDetection": "force"
},
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
"references": [{ "path": "./tsconfig.node.json" }]
}
+12
View File
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true
},
"include": ["vite.config.ts"]
}
+22
View File
@@ -0,0 +1,22 @@
import { defineConfig } from "vite";
import { svelte, vitePreprocess } from "@sveltejs/vite-plugin-svelte";
export default defineConfig({
plugins: [
svelte({
preprocess: vitePreprocess(),
compilerOptions: {
customElement: true,
},
}),
],
build: {
lib: {
entry: "src/main.ts",
formats: ["es", "umd"],
name: "TechRadarEditor",
fileName: (format) => `tech-radar-editor.${format}.js`,
},
cssCodeSplit: false, // Ensure all CSS is bundled together
},
});