Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions svelte/core-v2/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,24 @@
import Footer from "./lib/Footer.svelte";

import DORAlogo from "./assets/dora-icon-color-alt.svg";

let selected_entity = "unspecified";

let view_mode = "summary";
</script>

<!-- Popover shows summaries of entities -->
<Popover {selected_entity} />
<Popover />

<div class="header">
<div class="title"><img src="{DORAlogo}" alt="DORA"><h1>Core Model</h1></div>
<div class="view-control"><ViewControl bind:view_mode /></div>
<div class="view-control"><ViewControl /></div>
</div>

<div class="coremodel">
<Column column="capabilities" {view_mode} bind:selected_entity />
<Arrow text="predict" {view_mode} />
<Column column="performance" {view_mode} bind:selected_entity />
<Arrow text="predicts" {view_mode} />
<Column column="outcomes" {view_mode} bind:selected_entity />
<Column column="capabilities" />
<Arrow text="predict" />
<Column column="performance" />
<Arrow text="predicts" />
<Column column="outcomes" />
</div>
<Footer {view_mode} />
<Footer />

<style lang="scss">
.header {
Expand Down
9 changes: 6 additions & 3 deletions svelte/core-v2/src/lib/Arrow.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<script>
export let text = "predicts";
export let view_mode = "summary";
import { appState } from "./state.svelte.js";

let {
text = "predicts"
} = $props();
</script>

<div class={view_mode}>
<div class={appState.view_mode}>
<span class="text">{text}</span> <span>→</span>
</div>

Expand Down
9 changes: 3 additions & 6 deletions svelte/core-v2/src/lib/Column.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,19 @@
import EntityGroup from "./EntityGroup.svelte";

import core_data from "./core_data.json";
import { appState } from "./state.svelte.js";

export let column;
export let selected_entity;
export let view_mode = "summary";
let { column } = $props();
</script>

<section class="{column} {view_mode}">
<section class="{column} {appState.view_mode}">
<div class="heading">{sentenceCase(column)}</div>
<div class="entities">
{#each Object.entries(core_data[column]) as [entity_group_id, entity_group]}
<EntityGroup
{column}
{entity_group_id}
{entity_group}
{view_mode}
bind:selected_entity
/>
{/each}
</div>
Expand Down
18 changes: 8 additions & 10 deletions svelte/core-v2/src/lib/Entity.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
<script>
export let entity;
export let details;
export let view_mode;
export let selected_entity;
import { appState } from "./state.svelte.js";

let {
entity,
details
} = $props();

function openPopover(entity) {
selected_entity = entity;
document.getElementById("entityPopover").showPopover();
}
</script>

<div
class={view_mode}
on:click={() => openPopover(entity)}
class={appState.view_mode}
onclick={() => appState.selected_entity = entity}
role="link"
tabindex="-1"
>
Expand Down
23 changes: 10 additions & 13 deletions svelte/core-v2/src/lib/EntityGroup.svelte
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
<script>
import Entity from "./Entity.svelte";
import { appState } from "./state.svelte.js";

export let column; // column containing this group (e.g. "capabilities")
export let entity_group_id;
export let entity_group;
export let view_mode;
export let selected_entity;
let {
column,
entity_group_id,
entity_group
} = $props();

function openPopover(entity) {
selected_entity = entity;
document.getElementById("entityPopover").showPopover();
}
</script>

<div class="entity-group {view_mode} {column}">
<div class="entity-group {appState.view_mode} {column}">
<div
class="group-name"
on:click={() => openPopover(entity_group_id)}
onclick={() => appState.selected_entity = entity_group_id}
role="link"
tabindex="-1"
>
<span class="entity-group-name">{entity_group["name"]}</span>
{#if entity_group["measured_by"]}
<small>measured by</small>
<h5>
{entity_group["measured_by"]}{#if view_mode === "detail"}:{/if}
{entity_group["measured_by"]}{#if appState.view_mode === "detail"}:{/if}
</h5>
{/if}
</div>
<div class="entities-wrapper" id={entity_group_id}>
<div class="entities">
{#each Object.entries(entity_group["entities"]) as [entity, details]}
<Entity {entity} {details} {view_mode} bind:selected_entity />
<Entity {entity} {details} />
{/each}
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions svelte/core-v2/src/lib/Footer.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>
export let view_mode = "summary";
import { appState } from "./state.svelte.js";
import png_url_summary from "../assets/png/dora-core-v2.1.0-summary.png";
import png_url_detail from "../assets/png/dora-core-v2.1.0-detail.png";
import pdf_url_summary from "../assets/pdf/dora-core-v2.1.0-summary.pdf";
Expand All @@ -21,8 +21,8 @@
<div class="version">DORA Core model v2.1.0</div>
<div>
download:
<a href={download_urls["png"][view_mode]} target="_blank">PNG</a>
<a href={download_urls["pdf"][view_mode]} target="_blank">PDF</a>
<a href={download_urls["png"][appState.view_mode]} target="_blank">PNG</a>
<a href={download_urls["pdf"][appState.view_mode]} target="_blank">PDF</a>
</div>
</div>

Expand Down
88 changes: 41 additions & 47 deletions svelte/core-v2/src/lib/Popover.svelte
Original file line number Diff line number Diff line change
@@ -1,70 +1,64 @@
<script>
import core_data from "./core_data.json";

export let selected_entity = "unspecified";

let name = "";
let summary = "";
let link = "";

// TODO: this can probably be made more spiffy/functional
function populateDetails(entity) {
for (const column in core_data) {
for (const entity_group in core_data[column]) {
if (entity_group === selected_entity) {
// user has clicked on a group title
name = core_data[column][entity_group]["name"];
summary = core_data[column][entity_group]["summary"];
link = core_data[column][entity_group]["link"];
} else {
// user has clicked on an entity title
for (const entity in core_data[column][entity_group][
"entities"
]) {
if (entity === selected_entity) {
name =
core_data[column][entity_group]["entities"][
entity
]["name"];
summary =
core_data[column][entity_group]["entities"][
entity
]["summary"];
link =
core_data[column][entity_group]["entities"][
entity
]["link"];
}
}
}
import { appState } from "./state.svelte.js";

// Create a flat dictionary once on load
const entityLookup = {};
for (const column in core_data) {
for (const group in core_data[column]) {
entityLookup[group] = core_data[column][group];
for (const entity in core_data[column][group].entities) {
entityLookup[entity] = core_data[column][group].entities[entity];
}
}
}

// when the selected entity changes, find its associated info
$: populateDetails(selected_entity);
let details = $derived(
entityLookup[appState.selected_entity] || { name: "", summary: "", link: "" }
);

let popoverElement;

$effect(() => {
const entity = appState.selected_entity;
if (entity !== "unspecified") {
if (popoverElement && !popoverElement.matches(':popover-open')) {
popoverElement.showPopover();
}
} else {
if (popoverElement && popoverElement.matches(':popover-open')) {
popoverElement.hidePopover();
}
}
});

function handleToggle(event) {
if (event.newState === "closed") {
appState.selected_entity = "unspecified";
}
}
</script>

<div id="entityPopover" popover="auto">
<div bind:this={popoverElement} id="entityPopover" popover="auto" ontoggle={handleToggle}>
<div class="header">
<h1>{name}</h1>
<h1>{details.name}</h1>
<div>
<a
href="."
on:click={(e) => {
onclick={(e) => {
e.preventDefault();
document.getElementById("entityPopover").hidePopover();
appState.selected_entity = "unspecified";
}}>&times;</a
>
</div>
</div>

<p>{@html summary}</p>
<p>{@html details.summary}</p>
<div class="footer">
<!-- TODO: Remove this conditional check. To permanently remove the "Learn more" links for these items, remove the "link" property from the corresponding entries in src/core_data.json -->
{#if link && !["Climate for learning", "Fast flow", "Fast feedback"].includes(name)}
<a href={link} target="_blank"
>Learn more about {name.toLowerCase()}</a
{#if details.link && !["Climate for learning", "Fast flow", "Fast feedback"].includes(details.name)}
<a href={details.link} target="_blank"
>Learn more about {details.name.toLowerCase()}</a
>
{/if}
</div>
Expand Down
25 changes: 11 additions & 14 deletions svelte/core-v2/src/lib/ViewControl.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
<script>
import { onMount } from "svelte";

export let view_mode = "summary";
import { appState } from "./state.svelte.js";

// Function to update view_mode based on URL query parameter
const updateViewModeFromQuery = () => {
const urlParams = new URLSearchParams(window.location.search);
const mode = urlParams.get("view");
view_mode = mode === "detail" ? "detail" : "summary";
appState.view_mode = mode === "detail" ? "detail" : "summary";
};

// Function to update URL query parameter based on view_mode
const updateUrlQuery = () => {
const urlParams = new URLSearchParams(window.location.search);
urlParams.set("view", view_mode);
urlParams.set("view", appState.view_mode);
window.history.replaceState(
{},
"",
Expand All @@ -23,33 +22,31 @@

onMount(() => {
updateViewModeFromQuery();
window.addEventListener("popstate", updateViewModeFromQuery); // Handle back/forward
return () => {
window.removeEventListener("popstate", updateViewModeFromQuery);
};
});
</script>

<svelte:window onpopstate={updateViewModeFromQuery} />

<div class="viewcontrol">
View mode:
<label for="summary" class:active={view_mode === "summary"}>
<label for="summary" class:active={appState.view_mode === "summary"}>
<input
type="radio"
name="view_mode"
bind:group={view_mode}
bind:group={appState.view_mode}
value="summary"
id="summary"
on:change={updateUrlQuery}
onchange={updateUrlQuery}
/>summary
</label>
<label for="detail" class:active={view_mode === "detail"}>
<label for="detail" class:active={appState.view_mode === "detail"}>
<input
type="radio"
name="view_mode"
bind:group={view_mode}
bind:group={appState.view_mode}
value="detail"
id="detail"
on:change={updateUrlQuery}
onchange={updateUrlQuery}
/>detail
</label>
</div>
Expand Down
4 changes: 4 additions & 0 deletions svelte/core-v2/src/lib/state.svelte.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const appState = $state({
selected_entity: "unspecified",
view_mode: "summary"
});
Loading