Basic filter, timeline links
Этот коммит содержится в:
		
							родитель
							
								
									b77aa33417
								
							
						
					
					
						Коммит
						dac693845f
					
				
							
								
								
									
										45
									
								
								package-lock.json
									
									
									
										сгенерированный
									
									
									
								
							
							
						
						
									
										45
									
								
								package-lock.json
									
									
									
										сгенерированный
									
									
									
								
							| @ -25,6 +25,7 @@ | |||||||
| 				"prettier": "^3.1.1", | 				"prettier": "^3.1.1", | ||||||
| 				"prettier-plugin-svelte": "^3.1.2", | 				"prettier-plugin-svelte": "^3.1.2", | ||||||
| 				"svelte": "^4.2.7", | 				"svelte": "^4.2.7", | ||||||
|  | 				"svelte-select": "^5.8.3", | ||||||
| 				"vite": "^5.0.3" | 				"vite": "^5.0.3" | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| @ -524,6 +525,31 @@ | |||||||
| 				"node": "^18.18.0 || ^20.9.0 || >=21.1.0" | 				"node": "^18.18.0 || ^20.9.0 || >=21.1.0" | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"node_modules/@floating-ui/core": { | ||||||
|  | 			"version": "1.6.8", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", | ||||||
|  | 			"integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", | ||||||
|  | 			"dev": true, | ||||||
|  | 			"dependencies": { | ||||||
|  | 				"@floating-ui/utils": "^0.2.8" | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		"node_modules/@floating-ui/dom": { | ||||||
|  | 			"version": "1.6.11", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", | ||||||
|  | 			"integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", | ||||||
|  | 			"dev": true, | ||||||
|  | 			"dependencies": { | ||||||
|  | 				"@floating-ui/core": "^1.6.0", | ||||||
|  | 				"@floating-ui/utils": "^0.2.8" | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		"node_modules/@floating-ui/utils": { | ||||||
|  | 			"version": "0.2.8", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", | ||||||
|  | 			"integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", | ||||||
|  | 			"dev": true | ||||||
|  | 		}, | ||||||
| 		"node_modules/@humanwhocodes/module-importer": { | 		"node_modules/@humanwhocodes/module-importer": { | ||||||
| 			"version": "1.0.1", | 			"version": "1.0.1", | ||||||
| 			"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", | 			"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", | ||||||
| @ -2673,6 +2699,16 @@ | |||||||
| 				"url": "https://opencollective.com/eslint" | 				"url": "https://opencollective.com/eslint" | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"node_modules/svelte-floating-ui": { | ||||||
|  | 			"version": "1.5.8", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.5.8.tgz", | ||||||
|  | 			"integrity": "sha512-dVvJhZ2bT+kQDHlE4Lep8t+sgEc0XD96fXLzAi2DDI2bsaegBbClxXVNMma0C2WsG+n9GJSYx292dTvA8CYRtw==", | ||||||
|  | 			"dev": true, | ||||||
|  | 			"dependencies": { | ||||||
|  | 				"@floating-ui/core": "^1.5.0", | ||||||
|  | 				"@floating-ui/dom": "^1.5.3" | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
| 		"node_modules/svelte-hmr": { | 		"node_modules/svelte-hmr": { | ||||||
| 			"version": "0.16.0", | 			"version": "0.16.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", | 			"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", | ||||||
| @ -2685,6 +2721,15 @@ | |||||||
| 				"svelte": "^3.19.0 || ^4.0.0" | 				"svelte": "^3.19.0 || ^4.0.0" | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"node_modules/svelte-select": { | ||||||
|  | 			"version": "5.8.3", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.8.3.tgz", | ||||||
|  | 			"integrity": "sha512-nQsvflWmTCOZjssdrNptzfD1Ok45hHVMTL5IHay5DINk7dfu5Er+8KsVJnZMJdSircqtR0YlT4YkCFlxOUhVPA==", | ||||||
|  | 			"dev": true, | ||||||
|  | 			"dependencies": { | ||||||
|  | 				"svelte-floating-ui": "1.5.8" | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
| 		"node_modules/text-table": { | 		"node_modules/text-table": { | ||||||
| 			"version": "0.2.0", | 			"version": "0.2.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", | 			"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ | |||||||
| 		"prettier": "^3.1.1", | 		"prettier": "^3.1.1", | ||||||
| 		"prettier-plugin-svelte": "^3.1.2", | 		"prettier-plugin-svelte": "^3.1.2", | ||||||
| 		"svelte": "^4.2.7", | 		"svelte": "^4.2.7", | ||||||
|  | 		"svelte-select": "^5.8.3", | ||||||
| 		"vite": "^5.0.3" | 		"vite": "^5.0.3" | ||||||
| 	}, | 	}, | ||||||
| 	"type": "module" | 	"type": "module" | ||||||
|  | |||||||
| @ -1,13 +1,14 @@ | |||||||
| <script> | <script> | ||||||
|  |     import { fade } from 'svelte/transition' | ||||||
| 	export let cardData; | 	export let cardData; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <div class="card"> | <div class="card" transition:fade id={"case-" + cardData.attribution_id}> | ||||||
| 	<div class="card-header"> | 	<!--div class="card-header"> | ||||||
| 		<div class="card-header-title"> | 		<div class="card-header-title"> | ||||||
| 			<h2 class="is-size-3">Don't cases have titles?</h2> | 			<h2 class="is-size-3">Don't cases have titles?</h2> | ||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div--> | ||||||
| 	<div class="card-image"> | 	<div class="card-image"> | ||||||
| 		<figure class="image"> | 		<figure class="image"> | ||||||
| 			<img src={cardData.image_url} alt={cardData.image_credit} /> | 			<img src={cardData.image_url} alt={cardData.image_credit} /> | ||||||
| @ -25,3 +26,9 @@ | |||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
| </div> | </div> | ||||||
|  | 
 | ||||||
|  | <style> | ||||||
|  |     div.card { | ||||||
|  |         max-width: 780px; | ||||||
|  |     } | ||||||
|  | </style> | ||||||
|  | |||||||
| @ -1,40 +1,31 @@ | |||||||
| <script> | <script> | ||||||
|     import { scaleUtc } from "d3-scale" | 	import { scaleUtc } from 'd3-scale'; | ||||||
|     import { extent } from "d3-array" | 	import { extent } from 'd3-array'; | ||||||
|     import { utcFormat } from "d3-time-format" | 	import { utcFormat } from 'd3-time-format'; | ||||||
| 
 | 
 | ||||||
|     export let cases | 	export let cases; | ||||||
| 
 | 
 | ||||||
| 	const margins = { | 	const margins = { | ||||||
| 		top: 24, | 		top: 24, | ||||||
| 		right: 24, | 		right: 24, | ||||||
| 		bottom: 24, | 		bottom: 24, | ||||||
| 		left: 24 | 		left: 24 | ||||||
|     } | 	}; | ||||||
| 
 | 
 | ||||||
|     let width | 	let width; | ||||||
|     let height = 120 | 	let height = 120; | ||||||
| 
 |  | ||||||
|     $: dateExtent = extent(cases.map(d => new Date(d.attribution_date))) |  | ||||||
| 
 |  | ||||||
|     $: xScale = scaleUtc(dateExtent, [0, width - margins.right - margins.left]) |  | ||||||
|     $: ticks = xScale.ticks(5) |  | ||||||
| 
 | 
 | ||||||
|  | 	$: dateExtent = extent(cases.map((d) => new Date(d.attribution_date))); | ||||||
| 
 | 
 | ||||||
|  | 	$: xScale = scaleUtc(dateExtent, [0, width - margins.right - margins.left]); | ||||||
|  | 	$: ticks = xScale.ticks(5); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <div class="timeline-container" bind:clientWidth={width}> | <div class="timeline-container" bind:clientWidth={width}> | ||||||
| 	<svg {width} {height}> | 	<svg {width} {height}> | ||||||
| 		{#if xScale} | 		{#if xScale} | ||||||
| 			<g transform={`translate(${margins.left},${margins.top})`}> | 			<g transform={`translate(${margins.left},${margins.top})`}> | ||||||
|             <line | 				<line x1={0} x2={width} y1={0} y2={0} stroke={'#000000'} stroke-width={2}></line> | ||||||
|                 x1={0} |  | ||||||
|                 x2={width} |  | ||||||
|                 y1={0} |  | ||||||
|                 y2={0} |  | ||||||
|                 stroke={'#000000'} |  | ||||||
|                 stroke-width={2} |  | ||||||
|                 ></line> |  | ||||||
| 				{#each ticks as tick} | 				{#each ticks as tick} | ||||||
| 					<line | 					<line | ||||||
| 						x1={xScale(tick)} | 						x1={xScale(tick)} | ||||||
| @ -44,13 +35,10 @@ | |||||||
| 						stroke={'#000000'} | 						stroke={'#000000'} | ||||||
| 						stroke-width={2} | 						stroke-width={2} | ||||||
| 					></line> | 					></line> | ||||||
|                 <text | 					<text x={xScale(tick)} y={32} text-anchor={'middle'}>{utcFormat('%b %d')(tick)}</text> | ||||||
|                     x={xScale(tick)} |  | ||||||
|                     y={32} |  | ||||||
|                     text-anchor={'middle'} |  | ||||||
|                 >{utcFormat("%b")(tick)}</text> |  | ||||||
| 				{/each} | 				{/each} | ||||||
| 				{#each cases as attrCase} | 				{#each cases as attrCase} | ||||||
|  | 					<a href={'#case-' + attrCase.attribution_id}> | ||||||
| 						<circle | 						<circle | ||||||
| 							cx={xScale(new Date(attrCase.attribution_date))} | 							cx={xScale(new Date(attrCase.attribution_date))} | ||||||
| 							cy={0} | 							cy={0} | ||||||
| @ -59,8 +47,8 @@ | |||||||
| 							stroke={'#ffffff'} | 							stroke={'#ffffff'} | ||||||
| 							stroke-width={2} | 							stroke-width={2} | ||||||
| 						></circle> | 						></circle> | ||||||
|  | 					</a> | ||||||
| 				{/each} | 				{/each} | ||||||
| 
 |  | ||||||
| 			</g> | 			</g> | ||||||
| 		{/if} | 		{/if} | ||||||
| 	</svg> | 	</svg> | ||||||
|  | |||||||
| @ -1,26 +1,36 @@ | |||||||
| <script> | <script> | ||||||
|     import copy from "../data/copy.json" | 	import copy from '../data/copy.json'; | ||||||
|     import { onMount } from "svelte"; | 	import { onMount } from 'svelte'; | ||||||
|     import { csv } from "d3-fetch" | 	import { csv } from 'd3-fetch'; | ||||||
| 	import { base } from '$app/paths'; | 	import { base } from '$app/paths'; | ||||||
|     import CaseCard from "$lib/components/CaseCard.svelte"; | 	import CaseCard from '$lib/components/CaseCard.svelte'; | ||||||
|     import CaseTable from "$lib/components/CaseTable.svelte"; | 	import CaseTable from '$lib/components/CaseTable.svelte'; | ||||||
|     import Timeline from "$lib/components/Timeline.svelte"; | 	import Timeline from '$lib/components/Timeline.svelte'; | ||||||
|  | 	import Select from 'svelte-select'; | ||||||
| 
 | 
 | ||||||
|     let cases = [] | 	let cases = []; | ||||||
| 
 | 
 | ||||||
| 	onMount(async function () { | 	onMount(async function () { | ||||||
| 		//const response = await csv(`https://fiat-2024-processed-data.s3.us-west-2.amazonaws.com/Demo_Attribution_Data.csv`); | 		//const response = await csv(`https://fiat-2024-processed-data.s3.us-west-2.amazonaws.com/Demo_Attribution_Data.csv`); | ||||||
| 		const response = await csv(`${base}/Demo_Attribution_Data.csv`); | 		const response = await csv(`${base}/Demo_Attribution_Data.csv`); | ||||||
|         cases = response | 		cases = response; | ||||||
|     }) | 	}); | ||||||
|  | 
 | ||||||
|  | 	$: actorNations = | ||||||
|  | 		cases.length > 0 ? [...new Set(cases.map((d) => d.actor_nation.split(', ')).flat())] : []; | ||||||
|  | 	$: actorNationsUnique = [...new Set(actorNations)]; | ||||||
|  | 	let selectedActorNations = null; | ||||||
|  | 
 | ||||||
|  | 	$: filteredCases = selectedActorNations | ||||||
|  | 		? cases.filter((d) => d.actor_nation.includes(selectedActorNations[0].value)) | ||||||
|  | 		: cases; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <section class="section"> | <section class="section"> | ||||||
| 	<div class="container has-text-centered"> | 	<div class="container has-text-centered"> | ||||||
| 		<h1 class="is-size-1">{copy.meta.title}</h1> | 		<h1 class="is-size-1">{copy.meta.title}</h1> | ||||||
| 		{#each copy.content as block} | 		{#each copy.content as block} | ||||||
|             {#if block.type == "text"} | 			{#if block.type == 'text'} | ||||||
| 				<p>{block.text}</p> | 				<p>{block.text}</p> | ||||||
| 			{/if} | 			{/if} | ||||||
| 		{/each} | 		{/each} | ||||||
| @ -28,26 +38,42 @@ | |||||||
| </section> | </section> | ||||||
| 
 | 
 | ||||||
| <section class="section"> | <section class="section"> | ||||||
|     <div> | 	<div class="select-container"> | ||||||
| <Timeline {cases}></Timeline> | 		<Select | ||||||
| </div> | 			items={actorNationsUnique} | ||||||
|  | 			multiple={true} | ||||||
|  | 			bind:value={selectedActorNations} | ||||||
|  | 			placeholder={'Select 1 or more actor countries'} | ||||||
|  | 		></Select> | ||||||
|  | 	</div> | ||||||
| </section> | </section> | ||||||
| 
 | 
 | ||||||
| <section> | <section class="section"> | ||||||
|     <div class="container"> | 	<div> | ||||||
|         <div class="grid is-col-min-16"> | 		<Timeline cases={filteredCases}></Timeline> | ||||||
|         {#each cases as attrCase} | 	</div> | ||||||
|             <div class="cell"> | </section> | ||||||
|                 <CaseCard cardData={attrCase}> |  | ||||||
| 
 | 
 | ||||||
|                 </CaseCard> | <section class="section"> | ||||||
|  | 	<div class="container"> | ||||||
|  | 		<div class="grid is-col-min-12"> | ||||||
|  | 			{#each filteredCases as attrCase} | ||||||
|  | 				<div class="cell"> | ||||||
|  | 					<CaseCard cardData={attrCase}></CaseCard> | ||||||
| 				</div> | 				</div> | ||||||
| 			{/each} | 			{/each} | ||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
| </section> | </section> | ||||||
| <section> | 
 | ||||||
|  | <section class="section"> | ||||||
| 	<div class="container"> | 	<div class="container"> | ||||||
|         <CaseTable {cases}></CaseTable> | 		<CaseTable cases={filteredCases}></CaseTable> | ||||||
| 	</div> | 	</div> | ||||||
| </section> | </section> | ||||||
|  | 
 | ||||||
|  | <style> | ||||||
|  | 	.select-container { | ||||||
|  | 		width: 360px; | ||||||
|  | 	} | ||||||
|  | </style> | ||||||
|  | |||||||
		Загрузка…
	
	
			
			x
			
			
		
	
		Ссылка в новой задаче
	
	Block a user
	 Maarten
						Maarten