diff --git a/.github/workflows/npm_run_build b/.github/workflows/npm_run_build.yml similarity index 100% rename from .github/workflows/npm_run_build rename to .github/workflows/npm_run_build.yml diff --git a/astro.config.mjs b/astro.config.mjs new file mode 100644 index 0000000..ca6257a --- /dev/null +++ b/astro.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from 'astro/config' +import solid from '@astrojs/solid-js'; + +export default defineConfig({ + site: "https://vis.fairicube.eu", + integrations: [solid()], + output: "static", + publicDir: "static", + outDir: "public", +}) diff --git a/index.html b/index.html index 7021737..3d388f7 100644 --- a/index.html +++ b/index.html @@ -4,10 +4,11 @@ - Vite + Solid + TS + + FAIRiCUBE Visualization Service
- + diff --git a/package.json b/package.json index 4eae6c1..cfa66a1 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,15 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "preview": "vite preview" + "dev": "astro dev", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview" }, "dependencies": { + "@astrojs/check": "^0.9.4", + "@astrojs/solid-js": "^4.4.4", + "astro": "^4.16.14", "d3": "^7.9.0", "geotiff": "^2.1.3", "ol": "^10.2.1", diff --git a/src/App.css b/src-bad/App.css similarity index 100% rename from src/App.css rename to src-bad/App.css diff --git a/src/App.tsx b/src-bad/App.tsx similarity index 100% rename from src/App.tsx rename to src-bad/App.tsx diff --git a/src/components/App.module.css b/src-bad/components/App.module.css similarity index 100% rename from src/components/App.module.css rename to src-bad/components/App.module.css diff --git a/src/components/ChoosePalette.jsx b/src-bad/components/ChoosePalette.jsx similarity index 100% rename from src/components/ChoosePalette.jsx rename to src-bad/components/ChoosePalette.jsx diff --git a/src/components/ChooseRasterLayer.jsx b/src-bad/components/ChooseRasterLayer.jsx similarity index 100% rename from src/components/ChooseRasterLayer.jsx rename to src-bad/components/ChooseRasterLayer.jsx diff --git a/src/components/ChooseVectorLayer.jsx b/src-bad/components/ChooseVectorLayer.jsx similarity index 100% rename from src/components/ChooseVectorLayer.jsx rename to src-bad/components/ChooseVectorLayer.jsx diff --git a/src/components/Colorbar.jsx b/src-bad/components/Colorbar.jsx similarity index 100% rename from src/components/Colorbar.jsx rename to src-bad/components/Colorbar.jsx diff --git a/src/components/Colorbar.module.css b/src-bad/components/Colorbar.module.css similarity index 100% rename from src/components/Colorbar.module.css rename to src-bad/components/Colorbar.module.css diff --git a/src/components/LogoNILU.astro b/src-bad/components/LogoNILU.astro similarity index 74% rename from src/components/LogoNILU.astro rename to src-bad/components/LogoNILU.astro index 39c8f59..9254011 100644 --- a/src/components/LogoNILU.astro +++ b/src-bad/components/LogoNILU.astro @@ -19,4 +19,4 @@ - + diff --git a/src/components/LogoProject.astro b/src-bad/components/LogoProject.astro similarity index 84% rename from src/components/LogoProject.astro rename to src-bad/components/LogoProject.astro index 25a2f6e..30e93af 100644 --- a/src/components/LogoProject.astro +++ b/src-bad/components/LogoProject.astro @@ -11,7 +11,7 @@ z-index: 1000; width: 100px; height: 100px; - background-image: url('../images/fairicube_logo_400x297.jpg'); + background-image: url('/fairicube_logo_400x297.jpg'); background-size: contain; background-repeat: no-repeat; background-position: center; diff --git a/src/components/Map.js b/src-bad/components/Map.js similarity index 100% rename from src/components/Map.js rename to src-bad/components/Map.js diff --git a/src-bad/components/STACTreeView.jsx b/src-bad/components/STACTreeView.jsx new file mode 100644 index 0000000..70acb64 --- /dev/null +++ b/src-bad/components/STACTreeView.jsx @@ -0,0 +1,49 @@ +import { createResource, createSignal } from "solid-js"; +import { getAllSTACItems } from "../scripts/getAllItems"; +import { showWholeCollection } from "./utils/ShowWholeCollection"; + +export default function STACTreeView(props) { + + + //const [STACCatalogs, setSTACCatalogs] = createSignal(); + const [dummySignal, setDummySignal] = createSignal(); + + const [STACCatalogs] = createResource(dummySignal, getAllSTACItems); + + + setDummySignal(true); + + return Loading...}> + + {(collection, collectionIdx) => { + return + }} + +} + +function ViewCollection({collection}) { + + + return
{collection.title}: + + + + +
+} \ No newline at end of file diff --git a/src-bad/components/utils/ShowWholeCollection.js b/src-bad/components/utils/ShowWholeCollection.js new file mode 100644 index 0000000..583f45e --- /dev/null +++ b/src-bad/components/utils/ShowWholeCollection.js @@ -0,0 +1,48 @@ +import Map from 'ol/Map.js'; +import OSM from 'ol/source/OSM.js'; +import STAC from '../../ol/layer/STAC'; +import TileLayer from 'ol/layer/WebGLTile.js'; +import View from 'ol/View.js'; +import proj4 from 'proj4'; +import {getStacObjectsForEvent} from '../../ol/util.js'; +import {register} from 'ol/proj/proj4.js'; + +register(proj4); // required to support source reprojection + +export function showWholeCollection(collectionUrl){ + + const layer = new STAC({ + url: collectionUrl, + displayPreview: true, + collectionStyle: { + color: 'red', + }, + assets: ['data'], + + }); + + const background = new TileLayer({source: new OSM()}); + + const map = new Map({ + target: 'map-container', + layers: [background, layer], + view: new View({ + center: [0, 0], + zoom: 0, + }), + }); + map.on('singleclick', async (event) => { + const objects = await getStacObjectsForEvent(event); + if (objects.length > 0) { + objects.forEach((obj) => console.log(obj)); + } + }); + + layer.on('sourceready', () => { + const view = map.getView(); + view.fit(layer.getExtent()); + }); + + return false; + +} \ No newline at end of file diff --git a/src/components/utils/createBasemapLayer.js b/src-bad/components/utils/createBasemapLayer.js similarity index 100% rename from src/components/utils/createBasemapLayer.js rename to src-bad/components/utils/createBasemapLayer.js diff --git a/src/components/utils/createVectorLayer.js b/src-bad/components/utils/createVectorLayer.js similarity index 100% rename from src/components/utils/createVectorLayer.js rename to src-bad/components/utils/createVectorLayer.js diff --git a/src-bad/components/utils/getGeotiffMinmaxFromAuxXML.js b/src-bad/components/utils/getGeotiffMinmaxFromAuxXML.js new file mode 100644 index 0000000..3381335 --- /dev/null +++ b/src-bad/components/utils/getGeotiffMinmaxFromAuxXML.js @@ -0,0 +1,17 @@ +async function getGeotiffMinmaxFromAuxXML(geotiffSourceURL){ + try { + + const auxurl = geotiffSourceURL.replace('.tif','.tif.aux.xml'); + const aux = await fetch(auxurl); + const auxxml = await aux.text(); + const auxdoc = new DOMParser().parseFromString(auxxml, 'text/xml'); + const min = auxdoc.querySelector('[key="STATISTICS_MINIMUM"]').textContent; + const max = auxdoc.querySelector('[key="STATISTICS_MAXIMUM"]').textContent; + return [parseFloat(min), parseFloat(max)]; + } catch { + return null; + } +} + +export default getGeotiffMinmaxFromAuxXML; + diff --git a/src/components/utils/vectorFeatureStyle.js b/src-bad/components/utils/vectorFeatureStyle.js similarity index 100% rename from src/components/utils/vectorFeatureStyle.js rename to src-bad/components/utils/vectorFeatureStyle.js diff --git a/src/components/utils/zoomToFitData.js b/src-bad/components/utils/zoomToFitData.js similarity index 100% rename from src/components/utils/zoomToFitData.js rename to src-bad/components/utils/zoomToFitData.js diff --git a/src-bad/env.d.ts b/src-bad/env.d.ts new file mode 100644 index 0000000..9bc5cb4 --- /dev/null +++ b/src-bad/env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file diff --git a/src/index.css b/src-bad/index.css similarity index 100% rename from src/index.css rename to src-bad/index.css diff --git a/src/components/App.jsx b/src-bad/main.ts similarity index 90% rename from src/components/App.jsx rename to src-bad/main.ts index b675c21..83b72a9 100644 --- a/src/components/App.jsx +++ b/src-bad/main.ts @@ -1,10 +1,10 @@ import styles from "./App.module.css"; import { createSignal } from "solid-js"; -import Colorbar from "./Colorbar.jsx"; -import ChoosePalette from "./ChoosePalette.jsx"; -import ChooseVectorLayer from "./ChooseVectorLayer.jsx"; -import ChooseRasterLayer from "./ChooseRasterLayer.jsx"; +import Colorbar from "./components/Colorbar.jsx"; +import ChoosePalette from "./components/ChoosePalette.jsx"; +import ChooseVectorLayer from "./components/ChooseVectorLayer.jsx"; +import ChooseRasterLayer from "./components/ChooseRasterLayer.jsx"; import proj4 from 'proj4'; import {register} from 'ol/proj/proj4'; diff --git a/src/scripts/getAllItems.ts b/src-bad/scripts/getAllItems.ts similarity index 100% rename from src/scripts/getAllItems.ts rename to src-bad/scripts/getAllItems.ts diff --git a/src-bad/scripts/palette.js b/src-bad/scripts/palette.js new file mode 100644 index 0000000..45ee774 --- /dev/null +++ b/src-bad/scripts/palette.js @@ -0,0 +1,74 @@ +// import d3 scalechromatic +import * as d3 from 'd3'; +/* +import { palette } from '../components/App.js'; + + +export function getInterpolateBand1AsColor() { + + const pal = palette(); + + + if (pal.toLowerCase()=='rgb')return { color: ['array', ['band', 1], ['band', 2], ['band', 3], 1] }; + + let color = null; + if (pal=='A') color = d3.scaleSequential(d3.interpolateRainbow); + if (pal=='B') color = d3.scaleSequential(d3.interpolateViridis); + if (pal=='C') color = d3.scaleSequential(d3.interpolateWarm); + if (pal=='D') color = d3.scaleSequential(d3.interpolateGnBu); + + + const clr_arr = [ + 'interpolate', + ['linear'], + ['band', 1], + 0, + [255,0,0,0], + 0.001, + color(0.001), + 0.1, + color(0.1), + 0.1, + color(0.1), + 0.2, + color(0.2), + 0.4, + color(0.4), + 0.6, + color(0.6), + 1, + color(1) + ]; + interpolation_to_colorbar(clr_arr.slice(3)); + return {color: clr_arr}; + +} + + +// Given a MapLibre color interpolation array like [value, color, value, color, ...], create a +// colorbar elelement with a CSS background gradient +// that matches the color ramp +function interpolation_to_colorbar(interp){ + const colorbar = document.getElementById('colorbar'); + colorbar.innerHTML = ''; + for (let i = 0; i < interp.length; i+=2){ + let div = document.createElement('div'); + div.innerHTML = interp[i]; // Value + colorbar.appendChild(div); + } + const maxValue = interp[interp.length-2]; + let gradient = ''; + for (let i = 0; i < interp.length; i+=2){ + const value = interp[i]; + const percent = (value/maxValue)*100; + let clr = interp[i+1]; + // If the color is an array, convert it to a string + if (Array.isArray(clr)) clr = `rgba(${clr.join(',')})`; + gradient += clr + ' ' + percent + '%, '; + } + gradient = gradient.slice(0, -2); + colorbar.style.background = 'linear-gradient(to right, ' + gradient + ')'; + +} + +*/ \ No newline at end of file diff --git a/src/vite-env.d.ts b/src-bad/vite-env.d.ts similarity index 100% rename from src/vite-env.d.ts rename to src-bad/vite-env.d.ts diff --git a/src/components/ChoosePalette.astro b/src/components/ChoosePalette.astro new file mode 100644 index 0000000..59d5bb1 --- /dev/null +++ b/src/components/ChoosePalette.astro @@ -0,0 +1,65 @@ + +
+
+ + + + + +
+
+ + + + + + \ No newline at end of file diff --git a/src/components/Colorbar.astro b/src/components/Colorbar.astro new file mode 100644 index 0000000..4b33478 --- /dev/null +++ b/src/components/Colorbar.astro @@ -0,0 +1,53 @@ +
+ + + \ No newline at end of file diff --git a/src/components/Dataviewer.astro b/src/components/Dataviewer.astro new file mode 100644 index 0000000..96ffbc9 --- /dev/null +++ b/src/components/Dataviewer.astro @@ -0,0 +1,52 @@ + +
+
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/components/Logos.astro b/src/components/Logos.astro new file mode 100644 index 0000000..f20031f --- /dev/null +++ b/src/components/Logos.astro @@ -0,0 +1,38 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/components/Map.astro b/src/components/Map.astro new file mode 100644 index 0000000..3bf5658 --- /dev/null +++ b/src/components/Map.astro @@ -0,0 +1,243 @@ + + +
+ + + + \ No newline at end of file diff --git a/src/components/STACTreeView.jsx b/src/components/STACTreeView.jsx index 70acb64..53f71a0 100644 --- a/src/components/STACTreeView.jsx +++ b/src/components/STACTreeView.jsx @@ -1,6 +1,7 @@ import { createResource, createSignal } from "solid-js"; -import { getAllSTACItems } from "../scripts/getAllItems"; +import { getAllSTACItems } from "../scripts/getAllSTACItems"; import { showWholeCollection } from "./utils/ShowWholeCollection"; +import STAC from 'ol-stac'; export default function STACTreeView(props) { @@ -13,14 +14,19 @@ export default function STACTreeView(props) { setDummySignal(true); - return Loading...}> - - {(collection, collectionIdx) => { - return - }} - + return
+ Loading...
}> + + {(collection, collectionIdx) => { + return + }} + + } + + + function ViewCollection({collection}) { @@ -31,14 +37,19 @@ function ViewCollection({collection}) { -} \ No newline at end of file +} + +function STACItem({entry}) { + + const [key, val] = entry; + + // If val.rolesdoes not contain "data", skip + if (!val.roles.includes("data")) { + return null; + return <>No asset with "data" role (only {val.roles.join(", ")}) + } + + + const urlInput = document.getElementById('url-input'); + if (urlInput) urlInput.onchange = () => document.dispatchEvent(new Event('newsource')); + + const urlInputButton = document.getElementById('url-input-button'); + if (urlInputButton) urlInputButton.onclick = () => document.dispatchEvent(new Event('newsource')); + + function handleClick(e) { + e.preventDefault(); + + localStorage.setItem('url', e.target.href); + + document.dispatchEvent(new Event('newsource')); + } + + return {val?.description ?? val.id ?? key} + +} + diff --git a/src/components/Toaster.astro b/src/components/Toaster.astro new file mode 100644 index 0000000..37f394d --- /dev/null +++ b/src/components/Toaster.astro @@ -0,0 +1,56 @@ +
+ + + + \ No newline at end of file diff --git a/src/components/utils/ShowWholeCollection.js b/src/components/utils/ShowWholeCollection.js index 3fe8f20..c5c38a8 100644 --- a/src/components/utils/ShowWholeCollection.js +++ b/src/components/utils/ShowWholeCollection.js @@ -1,10 +1,11 @@ -import Map from 'ol/Map.js'; -import OSM from 'ol/source/OSM.js'; +import Map from 'ol/Map'; +import OSM from 'ol/source/OSM'; import STAC from 'ol-stac'; import TileLayer from 'ol/layer/WebGLTile.js'; import View from 'ol/View.js'; import proj4 from 'proj4'; -import {getStacObjectsForEvent} from 'ol-stac/util.js'; +import * as olSTACUtil from 'ol-stac/util'; +//import {getStacObjectsForEvent} from 'ol/util'; import {register} from 'ol/proj/proj4.js'; register(proj4); // required to support source reprojection @@ -32,7 +33,7 @@ export function showWholeCollection(collectionUrl){ }), }); map.on('singleclick', async (event) => { - const objects = await getStacObjectsForEvent(event); + const objects = await olSTACUtil.getStacObjectsForEvent(event); if (objects.length > 0) { objects.forEach((obj) => console.log(obj)); } diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..9bc5cb4 --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx deleted file mode 100644 index 425abdb..0000000 --- a/src/index.tsx +++ /dev/null @@ -1,9 +0,0 @@ -/* @refresh reload */ -import { render } from 'solid-js/web'; -import './index.css'; -import App from './App.tsx'; - - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/src/pages/index.astro b/src/pages/index.astro new file mode 100644 index 0000000..4444b33 --- /dev/null +++ b/src/pages/index.astro @@ -0,0 +1,51 @@ +--- +import Colorbar from "../components/Colorbar.astro"; +import Logos from "../components/Logos.astro"; +import Map from "../components/Map.astro"; +import Dataviewer from "../components/Dataviewer.astro"; +import STACTreeView from "../components/STACTreeView.jsx"; +import Toaster from "../components/Toaster.astro"; +import ChoosePalette from "../components/ChoosePalette.astro"; + +export const prerender = true; +--- + + + + + + + + FAIRiCUBE Visualization + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/scripts/getAllSTACItems.ts b/src/scripts/getAllSTACItems.ts new file mode 100644 index 0000000..a7903cf --- /dev/null +++ b/src/scripts/getAllSTACItems.ts @@ -0,0 +1,96 @@ + + +const baseUrl = 'https://stacapi.eoxhub.fairicube.eu'; + +export type Collections = Collection[]; +export type Collection = any; +export type Item = any; +export type Items = Item[]; + +/** + * This function will get all the STAC items from the STAC API for the catalog at: + * https://stacapi.eoxhub.fairicube.eu + * + * The function queries all collections, then queries each collection to get all items in the collection. It returns a JSON object. + * + */ +export async function getAllSTACItems(){ + console.log("Getting all STAC items"); + return await getCollections(); + +} + + +async function getCollections(){ + + const response = await fetch(`${baseUrl}/collections`); + const data = await response.json(); + const collections = data.collections as Collections; + // If there is a link with rel="next" in the collections, + // follow that to fetch the next page of collections + let nextLink = data.links.find((link: any) => link.rel === 'next'); + if (nextLink){ + const response = await fetch(nextLink.href); + const data = await response.json(); + collections.push(...data.collections as Collections); + nextLink = data.links.find((link: any) => link.rel === 'next'); + } + + for (const [i, collection] of collections.entries()){ + collections[i].items = await getItems(collection); + } + + return collections; +} + +/** + * This function will get all the items for each collection + * It contintually calls the links:next + * to get another page of items + * until there are no more links:next + * + * @param {*} collections + * @returns + */ +async function getItems(collection: Collection): Promise{ + let items : Items = []; + const response = await fetch(`${baseUrl}/collections/${collection.id}/items`); + const data = await response.json(); + items.push(...data.features); + + // get the next link + let nextLink = data.links.find((link: any) => link.rel === 'next'); + while (nextLink){ + const response = await fetch(nextLink.href); + const data = await response.json(); + items.push(...data.features); + nextLink = data.links.find((link: any) => link.rel === 'next'); + } + + const count = items.length; + items.forEach((item) => { + // convert item.assets to an array, and add the key as ".id"to each item + //@ts-ignore + item.assets = Object.entries(item.assets).map(([key, val]) => ({...val, id: key})); + + // Remove assets that do not contain "data" or "thumbnail" in the .roles array + item.assets = item.assets.filter((asset: any) => asset.roles.includes("data") || asset.roles.includes("thumbnail")); + + // Remove assets that do not have a .href + item.assets = item.assets.filter((asset: any) => asset.href); + + // Remove assets where href does not end with .tif,.png,.jpg,.jpeg,.gif,.bmp,.webp, or .geojson + item.assets = item.assets.filter((asset: any) => asset.href.endsWith(".tif") || asset.href.endsWith(".png") || asset.href.endsWith(".jpg") || asset.href.endsWith(".jpeg") || asset.href.endsWith(".gif") || asset.href.endsWith(".bmp") || asset.href.endsWith(".webp") || asset.href.endsWith(".geojson")); + }); + + + + // Remove items that do not contain any assets + items = items.filter((item) => item.assets.length > 0); + + if (count != items.length){ + console.log(`Removed ${count - items.length} items from collection ${collection.id} (kept only items with a 'data' or 'thumbnail' role, and where the .href ends with .tif,.png,.jpg,.jpeg,.gif,.bmp,.webp, or .geojson)`); + } + + return items; +} \ No newline at end of file diff --git a/src/scripts/getGeotiffMinmaxFromAuxXML.js b/src/scripts/getGeotiffMinmaxFromAuxXML.js new file mode 100644 index 0000000..bf1f9ff --- /dev/null +++ b/src/scripts/getGeotiffMinmaxFromAuxXML.js @@ -0,0 +1,17 @@ +export async function getGeotiffMinmaxFromAuxXML(geotiffSourceURL){ + try { + + const auxurl = geotiffSourceURL.replace('.tif','.tif.aux.xml'); + const aux = await fetch(auxurl); + const auxxml = await aux.text(); + const auxdoc = new DOMParser().parseFromString(auxxml, 'text/xml'); + const min = auxdoc.querySelector('[key="STATISTICS_MINIMUM"]').textContent; + const max = auxdoc.querySelector('[key="STATISTICS_MAXIMUM"]').textContent; + return [parseFloat(min), parseFloat(max)]; + } catch { + return null; + } +} + +export default getGeotiffMinmaxFromAuxXML; + diff --git a/src/scripts/palette.js b/src/scripts/palette.js index 45ee774..2217d8a 100644 --- a/src/scripts/palette.js +++ b/src/scripts/palette.js @@ -1,16 +1,23 @@ // import d3 scalechromatic import * as d3 from 'd3'; -/* -import { palette } from '../components/App.js'; -export function getInterpolateBand1AsColor() { - const pal = palette(); +export function getInterpolateBand1AsColor(pal) { + // If pal is not specified, use 'rgb' if palette-rgb is checked, otherwise use 'A' + if (!pal) { + if (document.getElementById('palette-rgb').checked) pal='rgb'; + else pal = document.querySelector('input[name="palette"]:checked').value; + } + + // Hide #colorbar element + document.getElementById('colorbar').style.display = 'none'; if (pal.toLowerCase()=='rgb')return { color: ['array', ['band', 1], ['band', 2], ['band', 3], 1] }; + document.getElementById('colorbar').style.display = 'block'; + let color = null; if (pal=='A') color = d3.scaleSequential(d3.interpolateRainbow); if (pal=='B') color = d3.scaleSequential(d3.interpolateViridis); @@ -42,6 +49,7 @@ export function getInterpolateBand1AsColor() { interpolation_to_colorbar(clr_arr.slice(3)); return {color: clr_arr}; + } @@ -71,4 +79,3 @@ function interpolation_to_colorbar(interp){ } -*/ \ No newline at end of file diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..9fd909c --- /dev/null +++ b/src/style.css @@ -0,0 +1,46 @@ +:root { + --nilu-dark-blue: rgb(5, 63, 83); + --nilu-med-blue: rgb(159, 210, 254); + --nilu-light-blue: rgb(233, 254, 255); + --nilu-soft-accent: rgb(84, 254, 219); + --nilu-soft-accent-dark: rgb(58, 177, 153); + --nilu-bright-accent: rgb(233, 60, 172); + --nilu-gray: rgb(176, 184, 194); + --nilu-dark-gray: rgba(6, 58, 75, 0.715); + --iconSize: 1.5rem; + } + +.stactreeview { + background-color: var(--nilu-light-blue); + + max-height: 80vh; + width: 20vw; + padding: 1rem; + overflow: auto; + position: absolute; + top: 0.5vh; + left: 0.5vw; + + ul { + list-style-type: none; + padding: 0; + margin: 0; + li { + list-style-type: none; + padding: 0; + margin: 0; + a.stacitemasset { + color: var(--nilu-dark-blue); + &::before { + content: 'Data Asset:'; + margin-right: 0.5rem; + } + margin-left: 1rem; + } + } + } + a { + display: block; + } +} + \ No newline at end of file diff --git a/static/NILU_Logo_Seagreen_RGB_small.svg b/static/NILU_Logo_Seagreen_RGB_small.svg new file mode 100644 index 0000000..4f1219f --- /dev/null +++ b/static/NILU_Logo_Seagreen_RGB_small.svg @@ -0,0 +1,26 @@ + + + + + + diff --git a/static/fairicube_logo_400x297.jpg b/static/fairicube_logo_400x297.jpg new file mode 100644 index 0000000..46274f3 Binary files /dev/null and b/static/fairicube_logo_400x297.jpg differ diff --git a/tsconfig.app.json b/tsconfig.app.json index c811fcb..bd076e9 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -23,5 +23,5 @@ "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true }, - "include": ["src"] + "include": ["src-bad"] }