diff --git a/src/common/constants.js b/src/common/constants.js index d70ef22..58aeb54 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -11,7 +11,7 @@ export const DEFAULT_TAB_ICONS = { NARRATIVE: "timeline", FILTER: "filter_list", SHAPE: "change_history", - DOWNLOAD: "download" + DOWNLOAD: "download", }; export const AVAILABLE_SHAPES = { @@ -25,8 +25,7 @@ export const AVAILABLE_SHAPES = { }; export const POLYGON_CLIP_PATH = { - STAR: - "polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)", + STAR: "polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)", DIAMOND: "polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)", PENTAGON: "polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%)", TRIANGLE: "polygon(50% 0%, 0% 100%, 100% 100%)", diff --git a/src/common/data/copy.json b/src/common/data/copy.json index 781d3e1..6557577 100644 --- a/src/common/data/copy.json +++ b/src/common/data/copy.json @@ -161,8 +161,8 @@ "fullscreen_enter": "Fullscreen", "fullscreen_exit": "Exit Fullscreen", "download": { - "button": "Download", - "panel":{ + "button": "Download", + "panel": { "title": "Download events", "description": "Export the most recent available events in different formats.", "formats": { @@ -175,7 +175,7 @@ "description": "JSON file where each event is a structured object containing nested arrays of sources and filters." } } - } + } } }, "timeline": { diff --git a/src/common/utilities.js b/src/common/utilities.js index 0a1e775..578ea19 100644 --- a/src/common/utilities.js +++ b/src/common/utilities.js @@ -577,11 +577,14 @@ export function getFilterIdx( } export function downloadAsFile(filename, content) { - let element = document.createElement('a'); - element.setAttribute('href', `data:application/octet-stream;charset=utf-8,${encodeURIComponent(content)}`); - element.setAttribute('download', filename); + let element = document.createElement("a"); + element.setAttribute( + "href", + `data:application/octet-stream;charset=utf-8,${encodeURIComponent(content)}` + ); + element.setAttribute("download", filename); - element.style.display = 'none'; + element.style.display = "none"; document.body.appendChild(element); element.click(); diff --git a/src/components/Toolbar.js b/src/components/Toolbar.js index 42ac804..dfbbf84 100644 --- a/src/components/Toolbar.js +++ b/src/components/Toolbar.js @@ -296,34 +296,34 @@ class Toolbar extends React.Component { {narrativesExist ? this.renderToolbarTab( - narrativesIdx, - panels.narratives.label, - panels.narratives.icon - ) + narrativesIdx, + panels.narratives.label, + panels.narratives.icon + ) : null} {features.USE_CATEGORIES ? this.renderToolbarCategoryTabs(categoryIdxs) : null} {features.USE_ASSOCIATIONS ? this.renderToolbarTab( - filtersIdx, - panels.filters.label, - panels.filters.icon - ) + filtersIdx, + panels.filters.label, + panels.filters.icon + ) : null} {features.USE_SHAPES ? this.renderToolbarTab( - shapesIdx, - panels.shapes.label, - panels.shapes.icon - ) + shapesIdx, + panels.shapes.label, + panels.shapes.icon + ) : null} {features.USE_DOWNLOAD ? this.renderToolbarTab( - downloadIdx, - panels.download.label, - panels.download.icon - ) + downloadIdx, + panels.download.label, + panels.download.icon + ) : null} {features.USE_FULLSCREEN && ( diff --git a/src/components/controls/BottomActions.js b/src/components/controls/BottomActions.js index abb3241..b6f78b9 100644 --- a/src/components/controls/BottomActions.js +++ b/src/components/controls/BottomActions.js @@ -29,7 +29,13 @@ function BottomActions(props) { ) : null} -
Made with TimeMap
Free software from
Forensic Architecture
+
+ Made with{" "} + TimeMap +
+ Free software from
{" "} + Forensic Architecture +
); } diff --git a/src/components/controls/DownloadButton.js b/src/components/controls/DownloadButton.js index 27ba045..4ac6a0d 100644 --- a/src/components/controls/DownloadButton.js +++ b/src/components/controls/DownloadButton.js @@ -1,84 +1,86 @@ import React from "react"; import copy from "../../common/data/copy.json"; -import { parse } from 'json2csv' -import { downloadAsFile } from "../../common/utilities" +import { parse } from "json2csv"; +import { downloadAsFile } from "../../common/utilities"; export class DownloadButton extends React.Component { - onDownload(format, domain) { - let filename = `ukr-civharm-${this.datetimeToDateString(new Date())}`; - if (format === "csv") { - let outputData = this.getCsvData(domain) - downloadAsFile(`${filename}.csv`, outputData); - } else if (format === "json") { - let outputData = this.getJsonData(domain) - downloadAsFile(`${filename}.json`, outputData); - } - } - getCsvData(domain) { - const { events, sources } = domain; - const exportEvents = events.map(e => { - return { - id: e.civId, - date: this.datetimeToDateString(e.datetime), - latitude: e.latitude, - longitude: e.longitude, - location: e.location, - description: e.description, - sources: e.sources.map(s => sources[s].paths[0]).join(","), - associations: e.associations.map(a => a.filter_paths.join("=")).join(",") - } - }) - return parse(exportEvents, { flatten: true }) - } - getJsonData(domain) { - const { events, sources } = domain; - const exportEvents = events.map(e => { - return { - id: e.civId, - date: this.datetimeToDateString(e.datetime), - latitude: e.latitude, - longitude: e.longitude, - location: e.location, - description: e.description, - sources: e.sources.map(id => { - const s = sources[id] - return { - id, - path: s.paths[0], - description: s.description - } - }), - filters: e.associations.map(a => { - return { - key: a.filter_paths[0], - value: a.filter_paths[1] - } - }) - } - }); - return JSON.stringify(exportEvents); - } - datetimeToDateString(datetime) { - try { - return datetime.toISOString().split("T")[0] - } catch (_) { } - return ""; - } - render() { - const { language, domain, format } = this.props; - const textByFormat = copy[language].toolbar.download.panel.formats[format] - return ( -
- this.onDownload(format, domain)} - > - {"download"} - {textByFormat.label} - - {textByFormat.description} -
- ); - } + onDownload(format, domain) { + let filename = `ukr-civharm-${this.datetimeToDateString(new Date())}`; + if (format === "csv") { + let outputData = this.getCsvData(domain); + downloadAsFile(`${filename}.csv`, outputData); + } else if (format === "json") { + let outputData = this.getJsonData(domain); + downloadAsFile(`${filename}.json`, outputData); + } + } + getCsvData(domain) { + const { events, sources } = domain; + const exportEvents = events.map((e) => { + return { + id: e.civId, + date: this.datetimeToDateString(e.datetime), + latitude: e.latitude, + longitude: e.longitude, + location: e.location, + description: e.description, + sources: e.sources.map((s) => sources[s].paths[0]).join(","), + associations: e.associations + .map((a) => a.filter_paths.join("=")) + .join(","), + }; + }); + return parse(exportEvents, { flatten: true }); + } + getJsonData(domain) { + const { events, sources } = domain; + const exportEvents = events.map((e) => { + return { + id: e.civId, + date: this.datetimeToDateString(e.datetime), + latitude: e.latitude, + longitude: e.longitude, + location: e.location, + description: e.description, + sources: e.sources.map((id) => { + const s = sources[id]; + return { + id, + path: s.paths[0], + description: s.description, + }; + }), + filters: e.associations.map((a) => { + return { + key: a.filter_paths[0], + value: a.filter_paths[1], + }; + }), + }; + }); + return JSON.stringify(exportEvents); + } + datetimeToDateString(datetime) { + try { + return datetime.toISOString().split("T")[0]; + } catch (_) {} + return ""; + } + render() { + const { language, domain, format } = this.props; + const textByFormat = copy[language].toolbar.download.panel.formats[format]; + return ( +
+ this.onDownload(format, domain)} + > + {"download"} + {textByFormat.label} + + {textByFormat.description} +
+ ); + } } diff --git a/src/components/controls/DownloadPanel.js b/src/components/controls/DownloadPanel.js index 57aab67..e68f3d4 100644 --- a/src/components/controls/DownloadPanel.js +++ b/src/components/controls/DownloadPanel.js @@ -1,17 +1,12 @@ import React from "react"; import { DownloadButton } from "./DownloadButton"; -const DownloadPanel = ({ - language, - title, - description, - domain -}) => { +const DownloadPanel = ({ language, title, description, domain }) => { return (

{title}

{description}

-
+
diff --git a/src/components/controls/atoms/Media.js b/src/components/controls/atoms/Media.js index 55f694e..bfbf9a6 100644 --- a/src/components/controls/atoms/Media.js +++ b/src/components/controls/atoms/Media.js @@ -74,7 +74,10 @@ const Media = ({ src, title }) => { return (
- +
); default: diff --git a/src/scss/cover.scss b/src/scss/cover.scss index f00cf91..7670b93 100644 --- a/src/scss/cover.scss +++ b/src/scss/cover.scss @@ -1,343 +1,344 @@ .cover-container { - position: absolute; - top: -100%; - left: 0; - height: 100vh; - background-color: black; - width: 100%; - opacity: 1; - transition: top 0.4s ease; - z-index: $loading-overlay + 1; - overflow-y: auto; - overflow-x: hidden; - color: $offwhite; + position: absolute; + top: -100%; + left: 0; + height: 100vh; + background-color: black; + width: 100%; + opacity: 1; + transition: top 0.4s ease; + z-index: $loading-overlay + 1; + overflow-y: auto; + overflow-x: hidden; + color: $offwhite; - &.showing { - top: 0; - left: 0; - } + &.showing { + top: 0; + left: 0; + } } .cover-header { - position: fixed; - bottom: 20px; - left: 0; + position: fixed; + bottom: 20px; + left: 0; + display: flex; + width: 100vw; + + @media only screen and (max-width: 1200px) { + position: inherit; + } + + .cover-logo-container { + padding: 20px 0 0 20px; display: flex; - width: 100vw; - - @media only screen and (max-width: 1200px) { - position: inherit; - } - - .cover-logo-container { - padding: 20px 0 0 20px; - display: flex; - - &.minimized {} - - .cover-logo { - transition: all 1s; - width: 60px; - height: 60px; - } - } &.minimized { - bottom: 150px; - max-width: $toolbar-width; - max-height: 30px; - justify-content: center; - align-items: center; - flex-direction: column; - - .cover-logo-container { - padding: 5px; - } - - .cover-logo { - width: 60px; - height: 60px; - } } + + .cover-logo { + transition: all 1s; + width: 60px; + height: 60px; + } + } + + &.minimized { + bottom: 150px; + max-width: $toolbar-width; + max-height: 30px; + justify-content: center; + align-items: center; + flex-direction: column; + + .cover-logo-container { + padding: 5px; + } + + .cover-logo { + width: 60px; + height: 60px; + } + } } .fullscreen-bg { - &.hidden { - top: -100%; - } + &.hidden { + top: -100%; + } - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - // overflow: hidden; - z-index: -100; - background: #000000; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + // overflow: hidden; + z-index: -100; + background: #000000; } .fullscreen-bg__video { - position: relative; - top: 0; - left: -25vw; - width: 150vw; - height: 100vh; - -webkit-filter: contrast(70%) brightness(70%) grayscale(100%); - filter: contrast(70%) brightness(70%) grayscale(100%); + position: relative; + top: 0; + left: -25vw; + width: 150vw; + height: 100vh; + -webkit-filter: contrast(70%) brightness(70%) grayscale(100%); + filter: contrast(70%) brightness(70%) grayscale(100%); - @media only screen and (max-width: 992px) { - display: none; - } + @media only screen and (max-width: 992px) { + display: none; + } } .default-cover-container { - display: flex; - justify-content: center; - flex-direction: column; - align-items: center; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; } .cover-container { - font-size: 12pt; + font-size: 12pt; + display: flex; + flex-direction: column; + max-height: 100%; + + hr, + br { + width: 100%; + } + + .sidebar { display: flex; flex-direction: column; - max-height: 100%; - - hr, - br { - width: 100%; - } - - .sidebar { - display: flex; - flex-direction: column; - justify-content: space-around; - align-items: space-around; - position: fixed; - left: 0; - background-color: $offwhite; - margin-top: 60px; - min-height: calc(100% - 280px); - max-height: calc(100% - 280px); - min-width: 19%; - max-width: 19%; - color: black; - - .il-video-pill { - display: flex; - justify-content: center; - align-items: center; - text-align: center; - flex: 1; - background-color: transparent; - border-bottom: 5px solid black; - transition: all 0.4s ease; - - &.explore { - background-color: $yellow; - } - - &.videos { - background-color: blue; - } - - &:hover { - cursor: pointer; - background-color: $darkwhite; - color: white; - } - } - } - - .hero { - min-width: 100%; - min-height: 80px; - margin: auto; - display: flex; - flex-direction: column; - margin-bottom: 20px; - margin-top: 60px; - - @media only screen and (max-width: 1200px) { - min-height: 250px; - } - - .row { - display: flex; - flex: 1; - flex-direction: row; - - @media only screen and (max-width: 1200px) { - flex-direction: column; - } - - justify-content: space-around; - - &.vertical { - flex-direction: column; - } - - .cell { - border: 1px solid white; - display: flex; - justify-content: center; - align-items: center; - text-align: center; - flex: 1; - background-color: $darkgrey; - padding: 10px 0; - transition: all 0.4s ease; - letter-spacing: 2px; - min-height: 40px; - - &.small { - letter-spacing: inherit; - font-size: 10pt; - } - - &.plain { - min-height: 10px; - background-color: black; - letter-spacing: 1px; - - @media only screen and (max-width: 1200px) { - min-height: 100px; - } - } - - &.yellow { - color: black !important; - background-color: $yellow; - } - - &:hover { - cursor: pointer; - background-color: $darkwhite; - color: white; - } - - @media only screen and (max-width: 1200px) { - min-height: 100px; - } - } - } - } - - .cover-content { - display: flex; - flex-direction: column; - max-width: 600px; - overflow-y: auto; - overflow-x: hidden; - padding-bottom: 10em; - - h1, - h2, - h3, - h4, - h5 { - text-align: center; - } - - h1 { - margin-bottom: -15px; - margin-top: 30px; - } - - h5 { - margin-top: -15px; - } - - .md-container { - width: 100%; - overflow-wrap: break-word; - // white-space: pre-line; - - ul { - list-style: none; - } - - li::before { - content: "* "; - } - - p { - text-align: justify; - } - } - - // mobile styles, remove overlay buttons - @media only screen and (max-width: 1200px) { - font-size: 22pt !important; - max-width: 100vw; - padding: 0 40px 80px 40px; - margin-bottom: 0; - } - - .verify-tabs { - background-color: $yellow; - color: black; - display: flex; - flex-direction: column; - - .v-tab { - display: flex; - margin: auto; - justify-content: center; - align-content: center; - flex: 1; - } - } - - .il-cover-verification-container { - display: flex; - flex-direction: column; - - .il-cover-verification { - .il-video { - border-radius: 1em; - background-color: rgba(240, 240, 240, 0.5); - } - } - } - } - - _::-webkit-full-page-media, - _:future, - :root .cover-content { - max-width: auto; - } -} - -.cover-footer { - &.disabled { - display: none; - } - + justify-content: space-around; + align-items: space-around; position: fixed; - bottom: 0; - min-height: 150px; - min-width: 100%; - padding: 10px; - background-color: black; - display: flex; - justify-content: center; + left: 0; + background-color: $offwhite; + margin-top: 60px; + min-height: calc(100% - 280px); + max-height: calc(100% - 280px); + min-width: 19%; + max-width: 19%; + color: black; - .il-cover-button { + .il-video-pill { + display: flex; + justify-content: center; + align-items: center; + text-align: center; + flex: 1; + background-color: transparent; + border-bottom: 5px solid black; + transition: all 0.4s ease; + + &.explore { + background-color: $yellow; + } + + &.videos { + background-color: blue; + } + + &:hover { + cursor: pointer; + background-color: $darkwhite; + color: white; + } + } + } + + .hero { + min-width: 100%; + min-height: 80px; + margin: auto; + display: flex; + flex-direction: column; + margin-bottom: 20px; + margin-top: 60px; + + @media only screen and (max-width: 1200px) { + min-height: 250px; + } + + .row { + display: flex; + flex: 1; + flex-direction: row; + + @media only screen and (max-width: 1200px) { + flex-direction: column; + } + + justify-content: space-around; + + &.vertical { + flex-direction: column; + } + + .cell { + border: 1px solid white; display: flex; justify-content: center; align-items: center; - min-width: 300px; - max-height: 80px; - margin-top: 30px; - background-color: $offwhite; - color: black; - transition: all 0.3s ease; + text-align: center; + flex: 1; + background-color: $darkgrey; + padding: 10px 0; + transition: all 0.4s ease; + letter-spacing: 2px; + min-height: 40px; + + &.small { + letter-spacing: inherit; + font-size: 10pt; + } + + &.plain { + min-height: 10px; + background-color: black; + letter-spacing: 1px; + + @media only screen and (max-width: 1200px) { + min-height: 100px; + } + } + + &.yellow { + color: black !important; + background-color: $yellow; + } &:hover { - cursor: pointer; - background-color: darken($offwhite, 30%); - color: black; + cursor: pointer; + background-color: $darkwhite; + color: white; } + + @media only screen and (max-width: 1200px) { + min-height: 100px; + } + } } -} \ No newline at end of file + } + + .cover-content { + display: flex; + flex-direction: column; + max-width: 600px; + overflow-y: auto; + overflow-x: hidden; + padding-bottom: 10em; + + h1, + h2, + h3, + h4, + h5 { + text-align: center; + } + + h1 { + margin-bottom: -15px; + margin-top: 30px; + } + + h5 { + margin-top: -15px; + } + + .md-container { + width: 100%; + overflow-wrap: break-word; + // white-space: pre-line; + + ul { + list-style: none; + } + + li::before { + content: "* "; + } + + p { + text-align: justify; + } + } + + // mobile styles, remove overlay buttons + @media only screen and (max-width: 1200px) { + font-size: 22pt !important; + max-width: 100vw; + padding: 0 40px 80px 40px; + margin-bottom: 0; + } + + .verify-tabs { + background-color: $yellow; + color: black; + display: flex; + flex-direction: column; + + .v-tab { + display: flex; + margin: auto; + justify-content: center; + align-content: center; + flex: 1; + } + } + + .il-cover-verification-container { + display: flex; + flex-direction: column; + + .il-cover-verification { + .il-video { + border-radius: 1em; + background-color: rgba(240, 240, 240, 0.5); + } + } + } + } + + _::-webkit-full-page-media, + _:future, + :root .cover-content { + max-width: auto; + } +} + +.cover-footer { + &.disabled { + display: none; + } + + position: fixed; + bottom: 0; + min-height: 150px; + min-width: 100%; + padding: 10px; + background-color: black; + display: flex; + justify-content: center; + + .il-cover-button { + display: flex; + justify-content: center; + align-items: center; + min-width: 300px; + max-height: 80px; + margin-top: 30px; + background-color: $offwhite; + color: black; + transition: all 0.3s ease; + + &:hover { + cursor: pointer; + background-color: darken($offwhite, 30%); + color: black; + } + } +} diff --git a/src/scss/toolbar.scss b/src/scss/toolbar.scss index 5dca37e..79405e2 100644 --- a/src/scss/toolbar.scss +++ b/src/scss/toolbar.scss @@ -186,20 +186,21 @@ } } - .download-row{ + .download-row { display: flex; flex-direction: row; } - .download-button{ + .download-button { flex: 1 1 auto; } - .download-description{ + .download-description { flex: 1 5 auto; text-align: justify; margin: auto; } - .toolbar-tab, .download-button { + .toolbar-tab, + .download-button { display: flex; align-items: center; justify-content: center;