Mobile timeline, styling
Этот коммит содержится в:
		
							родитель
							
								
									193948142e
								
							
						
					
					
						Коммит
						947d5f184d
					
				| @ -8,7 +8,7 @@ | ||||
| <div class="card" transition:fade id={'case-' + cardData.Attribution_ID}> | ||||
| 	<div class="card-header"> | ||||
| 		<div class="card-header-title"> | ||||
| 			<h2 class="is-size-3">{cardData.Short_Title}</h2> | ||||
| 			<h2 class="is-size-5">{cardData.Short_Title}</h2> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	<div class="card-image"> | ||||
|  | ||||
| @ -104,6 +104,7 @@ | ||||
| 					> | ||||
| 				{/each} | ||||
| 				{#each cases as attrCase} | ||||
| 					{console.log(attrCase.Attribution_ID)} | ||||
| 					{#if attrCase.show} | ||||
| 						<a href={'#case-' + attrCase.Attribution_ID} transition:fade> | ||||
| 							<Bubble | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <script> | ||||
| 	import { scaleUtc, scalePoint, scaleOrdinal } from 'd3-scale'; | ||||
| 	import { extent } from 'd3-array'; | ||||
| 	import { scaleUtc, scalePoint, scaleOrdinal, scaleLinear } from 'd3-scale'; | ||||
| 	import { max, extent } from 'd3-array'; | ||||
| 	import { utcFormat } from 'd3-time-format'; | ||||
| 	import { fade } from 'svelte/transition' | ||||
| 
 | ||||
| @ -14,17 +14,20 @@ | ||||
| 	}; | ||||
| 
 | ||||
| 	let width; | ||||
| 	let height = 400; | ||||
| 	let height = 500; | ||||
| 
 | ||||
| 	$: dateExtent = extent(cases.map((d) => new Date(d.attribution_date))); | ||||
| 
 | ||||
| 	$: yScale = scaleUtc(dateExtent, [0, height - margins.top - margins.bottom]); | ||||
| 	$: opacityScale = scaleLinear() | ||||
| 		.domain([0, max(cases.map(d => d.attribution_total_score))]) | ||||
| 		.range([0.2, 1]) | ||||
| 	$: ticks = yScale.ticks(5); | ||||
| 
 | ||||
| 	const actorNations = ['China', 'Iran', 'North Korea', 'Russia']; | ||||
| 	const colors = ['#0f4c8a', '#8a0f8a', '#8a4d0f', '#0f8a0f']; | ||||
| 
 | ||||
| 	$: xScale = scalePoint(actorNations, [0, width - margins.left - margins.right]).padding(1); | ||||
| 	$: xScale = scalePoint(actorNations, [0, width - margins.left - margins.right]).padding(0.5); | ||||
| 	let colorScale = scaleOrdinal(actorNations, colors); | ||||
| </script> | ||||
| 
 | ||||
| @ -39,7 +42,7 @@ | ||||
|                         y1={0} | ||||
| 						y2={height - margins.bottom - margins.top} | ||||
| 						style:stroke={colorScale(nation)} | ||||
| 						stroke-width={2} | ||||
| 						stroke-width={xScale.step()*0.9} | ||||
| 						opacity={0.3} | ||||
| 					></line> | ||||
| 					<text | ||||
| @ -68,14 +71,15 @@ | ||||
| 				{/each} | ||||
| 				{#each cases as attrCase} | ||||
| 					{#if attrCase.show} | ||||
| 						<a href={'#case-' + attrCase.attribution_id} transition:fade> | ||||
| 						<a href={'#case-' + attrCase.Attribution_ID} transition:fade> | ||||
| 							<circle | ||||
| 								cy={yScale(new Date(attrCase.attribution_date))} | ||||
| 								cx={xScale(attrCase.actor_nation[0])} | ||||
| 								r={6} | ||||
| 								style:fill={colorScale(attrCase.actor_nation[0])} | ||||
| 								stroke={'#ffffff'} | ||||
| 								stroke-width={2} | ||||
| 								stroke-width={1} | ||||
| 								opacity={opacityScale(attrCase.attribution_total_score)} | ||||
| 							></circle> | ||||
| 						</a> | ||||
| 					{/if} | ||||
|  | ||||
| @ -3,7 +3,6 @@ | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { csv } from 'd3-fetch'; | ||||
| 	import { max, extent } from 'd3-array'; | ||||
| 	import { base } from '$app/paths'; | ||||
| 	import CaseCard from '$lib/components/CaseCard.svelte'; | ||||
| 	import CaseTable from '$lib/components/CaseTable.svelte'; | ||||
| 	import Timeline from '$lib/components/Timeline.svelte'; | ||||
| @ -59,7 +58,8 @@ | ||||
| 				d.Source, | ||||
| 				d.Source_Nation, | ||||
| 				d.Source_Category | ||||
| 			].flat() | ||||
| 			] | ||||
| 				.flat() | ||||
| 				.join('__') | ||||
| 				.toLowerCase(); | ||||
| 
 | ||||
| @ -112,30 +112,29 @@ | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
|     const sortFunction = (option) => function(a, b){ | ||||
|         if(option.type == 'string' || option.type == 'date' || option.type == 'number'){ | ||||
|             if(a[option.id] < b[option.id]){ | ||||
|                 return -1 | ||||
|             } | ||||
|             if(b[option.id] < a[option.id]){ | ||||
|                 return 1 | ||||
|             } | ||||
|             else { | ||||
|                 return 0 | ||||
|             } | ||||
|         } | ||||
|         if(option.type == 'array'){ | ||||
|             if(a[option.id][0] < b[option.id][0]){ | ||||
|                 return -1 | ||||
|             } | ||||
|             if(b[option.id][0] < a[option.id][0]){ | ||||
|                 return 1 | ||||
|             } | ||||
|             else { | ||||
|                 return 0 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 	const sortFunction = (option) => | ||||
| 		function (a, b) { | ||||
| 			if (option.type == 'string' || option.type == 'date' || option.type == 'number') { | ||||
| 				if (a[option.id] < b[option.id]) { | ||||
| 					return -1; | ||||
| 				} | ||||
| 				if (b[option.id] < a[option.id]) { | ||||
| 					return 1; | ||||
| 				} else { | ||||
| 					return 0; | ||||
| 				} | ||||
| 			} | ||||
| 			if (option.type == 'array') { | ||||
| 				if (a[option.id][0] < b[option.id][0]) { | ||||
| 					return -1; | ||||
| 				} | ||||
| 				if (b[option.id][0] < a[option.id][0]) { | ||||
| 					return 1; | ||||
| 				} else { | ||||
| 					return 0; | ||||
| 				} | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 	$: if (cases) { | ||||
| 		cases = cases.map((d) => ({ | ||||
| @ -151,8 +150,7 @@ | ||||
| 				includesTextSearch($textSearchFilter, d.search) | ||||
| 		})); | ||||
| 	} | ||||
|     $: sortedCases = [...cases].sort(sortFunction(selectedSorting)) | ||||
|     $: console.log(sortedCases.map(d => d[selectedSorting.id])) | ||||
| 	$: sortedCases = [...cases].sort(sortFunction(selectedSorting)); | ||||
| 
 | ||||
| 	let width = 1200; | ||||
| 	let margin = { | ||||
| @ -171,16 +169,16 @@ | ||||
| 		sidebarOpen = !sidebarOpen; | ||||
| 	}; | ||||
| 
 | ||||
|     const sortOptions = [ | ||||
|             {id: 'attribution_date', label: 'Attribution Date', type: 'date'}, | ||||
|             {id: 'attribution_total_score', label: 'Attribution Score', type: 'number'}, | ||||
|             {id: 'actor_nation', label: 'Actor Nation', type: 'array'}, | ||||
|             {id: 'platform', label: 'Platform', type: 'array'}, | ||||
|             {id: 'source', label: 'Source', type: 'array'}, | ||||
|             {id: 'Source_Category', label: 'Source Category', type: 'string'}, | ||||
|         ] | ||||
| 	const sortOptions = [ | ||||
| 		{ id: 'attribution_date', label: 'Attribution Date', type: 'date' }, | ||||
| 		{ id: 'attribution_total_score', label: 'Attribution Score', type: 'number' }, | ||||
| 		{ id: 'actor_nation', label: 'Actor Nation', type: 'array' }, | ||||
| 		{ id: 'platform', label: 'Platform', type: 'array' }, | ||||
| 		{ id: 'source', label: 'Source', type: 'array' }, | ||||
| 		{ id: 'Source_Category', label: 'Source Category', type: 'string' } | ||||
| 	]; | ||||
| 
 | ||||
|     let selectedSorting = {id: 'attribution_date', label: 'Attribution Date', type: 'date'} | ||||
| 	let selectedSorting = { id: 'attribution_date', label: 'Attribution Date', type: 'date' }; | ||||
| </script> | ||||
| 
 | ||||
| <svelte:window bind:innerWidth /> | ||||
| @ -225,8 +223,8 @@ | ||||
| </section> | ||||
| 
 | ||||
| <section class="section"> | ||||
| 	<div class="container grid is-col-min-12"> | ||||
| 		<div class="field has-addons"> | ||||
| 	<div class="container cases-controls"> | ||||
| 		<div class="field has-addons cases-control"> | ||||
| 			<div class="buttons has-addons"> | ||||
| 				<button | ||||
| 					class={displayDataAs == 'Table' | ||||
| @ -246,15 +244,18 @@ | ||||
| 				> | ||||
| 			</div> | ||||
| 		</div> | ||||
|         <div class="select is-small"> | ||||
|             <select bind:value={selectedSorting}> | ||||
|                 {#each sortOptions as sortOpt} | ||||
|                 <option value={sortOpt}> | ||||
|                     {sortOpt.label} | ||||
|                 </option> | ||||
|             {/each} | ||||
|             </select> | ||||
|           </div> | ||||
| 		<div class="cases-control"> | ||||
|             <label for="sort-select">Sort cases by </label> | ||||
| 			<div class="select is-small"> | ||||
| 				<select bind:value={selectedSorting} id="sort-select"> | ||||
| 					{#each sortOptions as sortOpt} | ||||
| 						<option value={sortOpt}> | ||||
| 							{sortOpt.label} | ||||
| 						</option> | ||||
| 					{/each} | ||||
| 				</select> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </section> | ||||
| 
 | ||||
| @ -262,7 +263,7 @@ | ||||
| 	<section class="section"> | ||||
| 		<div class="container"> | ||||
| 			<div class="grid is-col-min-12"> | ||||
| 				{#each cases as attrCase} | ||||
| 				{#each sortedCases as attrCase} | ||||
| 					{#if attrCase.show} | ||||
| 						<div class="cell"> | ||||
| 							<CaseCard cardData={attrCase}></CaseCard> | ||||
| @ -315,4 +316,11 @@ | ||||
| 		padding: 1rem; | ||||
| 		z-index: 750; | ||||
| 	} | ||||
| 	.cases-controls { | ||||
| 		text-align: center; | ||||
| 	} | ||||
| 	.cases-control { | ||||
| 		display: inline-block; | ||||
|         margin-left: 3rem; | ||||
| 	} | ||||
| </style> | ||||
|  | ||||
| @ -6,4 +6,8 @@ | ||||
| 
 | ||||
|     --usa-red: #b22234; | ||||
|     --usa-lightred: #c5888f; | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|     overflow-x: hidden; | ||||
| } | ||||
		Загрузка…
	
	
			
			x
			
			
		
	
		Ссылка в новой задаче
	
	Block a user
	 Maarten
						Maarten