Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
|
2cea5f44fb | ||
|
37cd4fd17a | ||
|
b5cdfa0a09 | ||
|
0052c00f03 | ||
|
26869a837b | ||
|
3068f5980d |
8 changed files with 644 additions and 501 deletions
22
Plans.md
22
Plans.md
|
@ -1,8 +1,24 @@
|
||||||
# Plans for Webservices App
|
# Plans for Webservices App
|
||||||
|
|
||||||
High priority:
|
I've got quite a few plans for this app... here's a rough sketch of what I'm planning.
|
||||||
|
|
||||||
|
First release:
|
||||||
|
|
||||||
* filtering of all properties like Categories, Analogues, Licenses, Statuses, Hosts, and Affiliations.
|
* filtering of all properties like Categories, Analogues, Licenses, Statuses, Hosts, and Affiliations.
|
||||||
|
* modal showing each technology in more detail. DONE
|
||||||
|
* split out all constants (arrays) into separate files. ~DONE
|
||||||
|
* split out functions into svelte components.
|
||||||
|
|
||||||
|
Future versions:
|
||||||
|
|
||||||
|
* upgrade to Svelte 5
|
||||||
* a 'Technology' view (overlay), addressable by URL (i.e. going to, say, http://localhost:5173/ServiceName brings up the site with ServiceName shown in 'Technology' view, allowing people to reference a specific technology of interest to others).
|
* a 'Technology' view (overlay), addressable by URL (i.e. going to, say, http://localhost:5173/ServiceName brings up the site with ServiceName shown in 'Technology' view, allowing people to reference a specific technology of interest to others).
|
||||||
* split out all constants (arrays) into separate files.
|
* ability to go 'prev' or 'next' in modals within filtered set of technologies.
|
||||||
* split out functions into svelte modules.
|
* ability to select a Hosts and view all Technologies with instances on that Host
|
||||||
|
* ability to see the status (via UptimeKuma API) of each instance.
|
||||||
|
|
||||||
|
Possibly, eventually:
|
||||||
|
|
||||||
|
* move data into a database (rather than a fragile hand-crafted JSON file) with integrity checking.
|
||||||
|
* Authentication for administration
|
||||||
|
* CRUD interface for Technologies, Licenses, Hosts, and Affiliations.
|
||||||
|
|
687
package-lock.json
generated
687
package-lock.json
generated
File diff suppressed because it is too large
Load diff
60
src/app.css
60
src/app.css
|
@ -10,7 +10,7 @@ body {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 1.2em;
|
font-size: 1.15em;
|
||||||
border: double 3px #ddd;
|
border: double 3px #ddd;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
|
@ -28,7 +28,7 @@ a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
a:visited {
|
a:visited {
|
||||||
color: #437fad;
|
color: #325f81;
|
||||||
}
|
}
|
||||||
.y-accordions,
|
.y-accordions,
|
||||||
.y-accordion-header-button {
|
.y-accordion-header-button {
|
||||||
|
@ -37,3 +37,59 @@ a:visited {
|
||||||
.yaccordion .y-accordians .y-accordion-header-button {
|
.yaccordion .y-accordians .y-accordion-header-button {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
/* modal styles */
|
||||||
|
.y-modal .y-modal-container {
|
||||||
|
background-color: #eee;
|
||||||
|
border: solid 3px #3a8ea5;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 5px 5px 3px #6a6d6a;
|
||||||
|
width: 90%;
|
||||||
|
margin: 1em auto;
|
||||||
|
max-width: 40em;
|
||||||
|
height: auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.y-modal .y-modal-container .y-modal-content {
|
||||||
|
width: 100%;
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
.y-modal .y-modal-container .y-modal-header {
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #999;
|
||||||
|
}
|
||||||
|
.y-modal .y-modal-container .y-modal-header .y-modal-title {
|
||||||
|
font-size: 1.5em;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.y-modal .y-modal-container .y-modal-body {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
.y-modal .y-modal-container div.instances {
|
||||||
|
background-color: #ddd;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.y-modal .y-modal-container p.instances,
|
||||||
|
.y-modal .y-modal-container li p {
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end modals */
|
||||||
|
/* popover styles */
|
||||||
|
.y-popover {
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
.y-popover a {
|
||||||
|
font-size: 110%;
|
||||||
|
}
|
||||||
|
.y-popover a:hover {
|
||||||
|
color: #000;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.y-popover a:visited {
|
||||||
|
color: #325f81;
|
||||||
|
}
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
<script>
|
|
||||||
// Ref: https://svelte.dev/repl/a5f4d395b15a44d48a6b2239ef705fc4?version=3.35.0
|
|
||||||
// based on suggestions from:
|
|
||||||
// Inclusive Components by Heydon Pickering https://inclusive-components.design/collapsible-sections/
|
|
||||||
export let headerText;
|
|
||||||
|
|
||||||
let expanded = false;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="collapsible">
|
|
||||||
<h3>
|
|
||||||
<button aria-expanded={expanded} on:click={() => expanded = !expanded}>{headerText}
|
|
||||||
<svg class="indicator" viewBox="0 0 20 20" fill="none" >
|
|
||||||
<path class="vert" d="M10 1V19" stroke="black" stroke-width="2"/>
|
|
||||||
<path d="M1 10L19 10" stroke="black" stroke-width="2"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</h3>
|
|
||||||
<!-- <div class='tree' hidden={!expanded}>
|
|
||||||
<svg viewBox="0 0 60 60" fill="#ccc">
|
|
||||||
<path class="open" d="M40 1 V69" stroke="#444" stroke-width="4" />
|
|
||||||
</svg>
|
|
||||||
</div> -->
|
|
||||||
<div class='contents' hidden={!expanded}>
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.collapsible {
|
|
||||||
margin: 8px 0 4px 0;
|
|
||||||
}
|
|
||||||
.collapsible .collapsible h3 button {
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
.tree { float: left; }
|
|
||||||
.contents {
|
|
||||||
float: left;
|
|
||||||
clear: both;
|
|
||||||
width: 100%;
|
|
||||||
border-bottom: dashed #aaa 1px;
|
|
||||||
padding-bottom: 1em;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background-color: var(--background, #fff);
|
|
||||||
color: var(--gray-darkest, #282828);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
border: 1px #aaa solid;
|
|
||||||
margin-left: 0px;
|
|
||||||
padding: 0.7em 0.7em;
|
|
||||||
}
|
|
||||||
button[aria-expanded="true"] { border-bottom: 2px solid var(--gray-light, #eee); }
|
|
||||||
button[aria-expanded="true"] .vert { display: none; }
|
|
||||||
button:focus svg { outline: 1firtpx solid; }
|
|
||||||
button[aria-expanded="true"] rect { fill: currentColor; }
|
|
||||||
svg.indicator {
|
|
||||||
height: 1.0em;
|
|
||||||
width: 1.0em;
|
|
||||||
margin-left: 6px;
|
|
||||||
margin-right: 6px;
|
|
||||||
margin-top: 4px;;
|
|
||||||
}
|
|
||||||
.tree:hover svg { outline: 1firtpx solid; }
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -152,7 +152,7 @@
|
||||||
|
|
||||||
/* instance-specific styles */
|
/* instance-specific styles */
|
||||||
.filter {
|
.filter {
|
||||||
font-size: 80%;
|
font-size: 0.8em;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
line-height: 2.5;
|
line-height: 2.5;
|
||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
// a 'technology' object
|
// a 'technology' object
|
||||||
export let technology;
|
export let technology;
|
||||||
|
export let licenses;
|
||||||
export let affiliate_colours;
|
export let affiliate_colours;
|
||||||
import { Button, Modal, ModalBody, ModalFooter, Popover } from 'yesvelte';
|
import { Button, ButtonGroup, El, Modal, ModalBody, ModalFooter,
|
||||||
|
ModalHeader, ModalTitle, Popover, PopoverBody, PopoverHeader } from 'yesvelte';
|
||||||
|
|
||||||
let showModal = false;
|
export let showModal = false;
|
||||||
|
|
||||||
const formatter = new Intl.ListFormat('en', {
|
const formatter = new Intl.ListFormat('en', {
|
||||||
style: 'long',
|
style: 'long',
|
||||||
|
@ -31,58 +33,42 @@
|
||||||
tech.hasOwnProperty('instances') &&
|
tech.hasOwnProperty('instances') &&
|
||||||
tech.instances.constructor === Array &&
|
tech.instances.constructor === Array &&
|
||||||
tech.instances.length
|
tech.instances.length
|
||||||
) return true;
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClick() {
|
|
||||||
console.log('clicked!');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*document.addEventListener('keydown', (event) => {
|
|
||||||
const { activeElement } = document;
|
|
||||||
const hasButtonRole = activeElement?.getAttribute('role') === 'button';
|
|
||||||
|
|
||||||
if (hasButtonRole) {
|
|
||||||
// prevent default behaviour, including scrolling on spacebar
|
|
||||||
if (['Spacebar', ' ', 'Enter'].includes(event.key)) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === 'Enter') {
|
|
||||||
activeElement.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('keyup', (event) => {
|
|
||||||
const { activeElement } = document;
|
|
||||||
const hasButtonRole = activeElement?.getAttribute('role') === 'button';
|
|
||||||
|
|
||||||
if (hasButtonRole && ['Spacebar', ' '].includes(event.key)) {
|
|
||||||
event.preventDefault();
|
|
||||||
activeElement.click();
|
|
||||||
}
|
|
||||||
});*/
|
|
||||||
|
|
||||||
//onclick="handleClick()"
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- making a dive act like a button: https://kvack.dev/blog/make-that-div-behave-like-a-button -->
|
<!-- making a dive act like a button: https://kvack.dev/blog/make-that-div-behave-like-a-button -->
|
||||||
|
|
||||||
<div on:click={() => (showModal = !showModal)} onclick="handleClick()" role="button" tabindex=0 class="tile technology">
|
<button on:click={() => (showModal = !showModal)} tabindex=0 class="tile technology" col>
|
||||||
<div class="links">
|
|
||||||
<span class="website"><a href="{technology.website}" title="Project site for {technology.name}">P</a></span>
|
|
||||||
{#if technology.repository}<span class="repository"><a
|
|
||||||
href={technology.repository} title="The source code repository for {technology.name}">R</a></span>{/if}
|
|
||||||
{#if technology.wikipedia}<span class="wikipedia"><a
|
|
||||||
href={technology.wikipedia}
|
|
||||||
title="Wikipedia Page for {technology.name}">W</a></span>{/if}
|
|
||||||
</div>
|
|
||||||
<h2>{technology.name}</h2>
|
<h2>{technology.name}</h2>
|
||||||
|
<div class="links">
|
||||||
|
<span class="website">P</span>
|
||||||
|
<Popover trigger="hover">
|
||||||
|
<PopoverHeader><strong>Project website</strong> for {technology.name}</PopoverHeader>
|
||||||
|
<PopoverBody><a href="{technology.website}">{technology.website}</a></PopoverBody>
|
||||||
|
</Popover>
|
||||||
|
{#if technology.repository}<span class="repository">S</span>
|
||||||
|
<Popover trigger="hover">
|
||||||
|
<PopoverHeader><strong>Source code</strong> repository for {technology.name}</PopoverHeader>
|
||||||
|
<PopoverBody><a href={technology.repository}>{technology.repository}</a></PopoverBody>
|
||||||
|
</Popover>
|
||||||
|
{/if}
|
||||||
|
{#if technology.wikipedia}<span class="wikipedia">W</span>
|
||||||
|
<Popover trigger="hover">
|
||||||
|
<PopoverHeader><strong>Wikipedia entry</strong> for {technology.name}</PopoverHeader>
|
||||||
|
<PopoverBody><a href={technology.wikipedia}>{technology.wikipedia}</a></PopoverBody>
|
||||||
|
</Popover>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
<p class="description">{technology.description}{#if technology.extended_description}<span
|
<p class="description">{technology.description}{#if technology.extended_description}<span
|
||||||
title={technology.extended_description}>i</span>{/if}
|
title={technology.extended_description}>i</span>{/if}
|
||||||
</p>
|
</p>
|
||||||
|
<div class="details">
|
||||||
{#if technology.categories}<p class="property categories">{pluraliser('Category',
|
{#if technology.categories}<p class="property categories">{pluraliser('Category',
|
||||||
'Categories', technology.categories.length)}: <span class="value">{toOxfordCommaString(technology.categories)}</span></p>{/if}
|
'Categories', technology.categories.length)}: <span class="value">{toOxfordCommaString(technology.categories)}</span></p>{/if}
|
||||||
{#if technology.analogues}<p class="property analogues">Alternative to <span
|
{#if technology.analogues}<p class="property analogues">Alternative to <span
|
||||||
|
@ -90,114 +76,171 @@
|
||||||
{#if technology.license}<p class="property license"
|
{#if technology.license}<p class="property license"
|
||||||
title="The libre license for this project is {technology.license}">License: <span
|
title="The libre license for this project is {technology.license}">License: <span
|
||||||
class="value">{technology.license}</span></p>{/if}
|
class="value">{technology.license}</span></p>{/if}
|
||||||
|
</div>
|
||||||
{#if hasInstances(technology)}
|
{#if hasInstances(technology)}
|
||||||
<div class="instances">
|
<div class="instances">
|
||||||
<p>{#each technology.instances as instance}<a
|
<p>
|
||||||
href="https://{instance.domain}"
|
{#each technology.instances as instance}
|
||||||
title="{technology.name} instance {instance.domain} hosted on '{instance.host}' by {instance.affiliation}"><span class="marker circle"
|
<span class="marker circle"
|
||||||
style="background-color: {affiliate_colours[instance.affiliation].colour}"
|
style="background-color: {affiliate_colours[instance.affiliation].colour}"
|
||||||
></span></a>{/each}
|
></span>
|
||||||
|
<Popover trigger="hover">
|
||||||
|
<PopoverHeader>{technology.name} Instance</PopoverHeader>
|
||||||
|
<PopoverBody><a href="https://{instance.domain}">https://{instance.domain}</a> hosted on '{instance.host}' by {instance.affiliation}</PopoverBody>
|
||||||
|
</Popover>
|
||||||
|
{/each}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="instances">Nothing here yet...</div>
|
<div class="instances">Nothing here yet...</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<Modal title="{technology.name}" bind:showModal>
|
<Modal scrollable bind:show={showModal} autoClose dismissible>
|
||||||
|
<ModalHeader>
|
||||||
|
<ModalTitle>{technology.name}</ModalTitle>
|
||||||
|
</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
Modal stuff...
|
<p class="description">{technology.description}{#if technology.extended_description}{technology.extended_description}{/if}
|
||||||
|
</p>
|
||||||
|
<div class="links">
|
||||||
|
<p class="link"><span class="label">Project website</span>: <span class="website"><a href="{technology.website}" title="Project site for {technology.name}">{technology.website}</a></span></p>
|
||||||
|
{#if technology.repository}<p class="link"><span class="label">Source code repository</span>: <span class="repository"><a
|
||||||
|
href={technology.repository} title="The source code repository for {technology.name}">{technology.repository}</a></span></p>{/if}
|
||||||
|
{#if technology.wikipedia}<p class="link"><span class="label">Wikipedia entry</span>: <span class="wikipedia"><a
|
||||||
|
href={technology.wikipedia}
|
||||||
|
title="Wikipedia Page for {technology.name}">{technology.wikipedia}</a></span></p>{/if}
|
||||||
|
</div>
|
||||||
|
<div class="details">
|
||||||
|
{#if technology.categories}<p class="property categories">{pluraliser('Category',
|
||||||
|
'Categories', technology.categories.length)}: <span class="value">{toOxfordCommaString(technology.categories)}</span></p>{/if}
|
||||||
|
{#if technology.analogues}<p class="property analogues">Alternative to <span
|
||||||
|
class="value">{toOxfordCommaString(technology.analogues)}</span></p>{/if}
|
||||||
|
{#if technology.license}<p class="property license"
|
||||||
|
title="The libre license for this project is {technology.license}">License: <span
|
||||||
|
class="value"><a href="{licenses[technology.license].url}">{licenses[technology.license].name}</a></span></p>{/if}
|
||||||
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
{#if hasInstances(technology)}
|
||||||
|
<div class="instances">
|
||||||
|
<p class="instances">Instances of {technology.name}:</p>
|
||||||
|
<ol>
|
||||||
|
{#each technology.instances as instance}
|
||||||
|
<li>
|
||||||
|
<p class="instance"><a href="https://{instance.domain}">{instance.domain}</a> hosted on '{instance.host}' <span class="marker circle" style="background-color: {affiliate_colours[instance.affiliation].colour}"/> by {instance.affiliation}".
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="instances">Nothing here yet...</div>
|
||||||
|
{/if}
|
||||||
|
<!--<ModalFooter>
|
||||||
|
Previous and Next buttons to go here.
|
||||||
|
</ModalFooter>-->
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.tile {
|
.tile.technology {
|
||||||
display: inline-block;
|
|
||||||
height: 515px;
|
background-color: #eee;
|
||||||
/*min-width: 240px;
|
|
||||||
max-width: 300px;*/
|
|
||||||
width: 290px;
|
|
||||||
overflow: hidden;
|
|
||||||
box-sizing: border-box;
|
|
||||||
box-shadow: 5px 5px 3px #6a6d6a;
|
|
||||||
border: solid 3px #3a8ea5;
|
border: solid 3px #3a8ea5;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
text-overflow: ellipsis;
|
box-shadow: 5px 5px 3px #6a6d6a;
|
||||||
overflow: hidden;
|
box-sizing: border-box;
|
||||||
position: relative;
|
display: inline-block;
|
||||||
background-color: #eee;
|
height: 515px;
|
||||||
margin-top: 8px;
|
line-height: 1.2;
|
||||||
margin-right: 18px;
|
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
margin-right: 18px;
|
||||||
|
margin-top: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
vertical-align: top !important;
|
||||||
|
width: 290px;
|
||||||
}
|
}
|
||||||
.tile .links {
|
.tile.technology .links {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
}
|
}
|
||||||
.tile:hover {
|
.tile.technology:hover {
|
||||||
box-shadow: 10px 10px 6px #727372;
|
box-shadow: 6px 6px 5px #727372;
|
||||||
}
|
}
|
||||||
.tile:active {
|
.tile.technology:active {
|
||||||
box-shadow: 0 0 0;
|
box-shadow: 0 0 0;
|
||||||
border-color: #000;
|
border-color: #000;
|
||||||
}
|
}
|
||||||
.tile .links h2 a {
|
.tile.technology .links h2 a {
|
||||||
color: #e6c4fc;
|
color: #e6c4fc;
|
||||||
}
|
}
|
||||||
.tile .links a:visited {
|
.tile.technology .links a:visited {
|
||||||
color: #ced0ff;
|
color: #ced0ff;
|
||||||
}
|
}
|
||||||
.tile .links a:hover,
|
.tile.technology .links a:hover,
|
||||||
.tile:hover h2 a {
|
.tile.technology:hover h2 a {
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
.tile h2 {
|
.tile.technology h2 {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
background-color: #999;
|
background-color: #999;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.tile h2 a {
|
.tile.technology h2 a {
|
||||||
color: #e6c4fc;
|
color: #e6c4fc;
|
||||||
}
|
}
|
||||||
.tile h2 a:visited {
|
.tile.technology h2 a:visited {
|
||||||
color: #ced0ff;
|
color: #ced0ff;
|
||||||
}
|
}
|
||||||
.tile h2 a:hover {
|
.tile.technology h2 a:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.tile .description {
|
.tile.technology .description {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
|
line-height: 1.2em;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-top: 0.5em;
|
padding-top: 0.5em;
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
.tile p {
|
.tile.technology p {
|
||||||
padding: 0 0.7em 0.2em 0.7em;
|
padding: 0 0.7em 0.2em 0.7em;
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
color: #555;
|
color: #555;
|
||||||
}
|
}
|
||||||
.tile p.property {
|
.tile.technology p.property {
|
||||||
padding: 0.2em 0.7em;
|
padding: 0.2em 0.7em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.instances {
|
.tile.technology .details {
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
.tile.technology .instances {
|
||||||
background-color: #ddd;
|
background-color: #ddd;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 2.5em;
|
height: 2.5em;
|
||||||
width: 100%;
|
width: 100% !important;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.instances p { padding-top: 0.7em; vertical-align: middle; }
|
.tile.technology .instances p {
|
||||||
.instances .marker {
|
width: 100%;
|
||||||
margin-right: 3px;
|
padding-top: 0.7em;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.webservices li {
|
.tile.technology .instances .marker {
|
||||||
list-style-type: none;
|
margin-right: 3px;
|
||||||
}
|
}
|
||||||
.value {
|
.value {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -217,10 +260,4 @@
|
||||||
.circle:hover {
|
.circle:hover {
|
||||||
border: 1px solid #000;
|
border: 1px solid #000;
|
||||||
}
|
}
|
||||||
.square {
|
|
||||||
height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
background-color: #555;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
// for multiple async fetches: https://youtu.be/EQy-AYhZIlE?si=FwyAPUjbixSUlc9q&t=490
|
// for multiple async fetches: https://youtu.be/EQy-AYhZIlE?si=FwyAPUjbixSUlc9q&t=490
|
||||||
export const load = async ({ fetch }) => {
|
export const load = async ({ fetch }) => {
|
||||||
const webservicesResult = await fetch('https://static.magnificent.nz/webservices/webservices.json');
|
const webservicesResult = await fetch(
|
||||||
const webservicesData = await webservicesResult.json();
|
'https://static.magnificent.nz/webservices/webservices.json'
|
||||||
|
);
|
||||||
//console.log(webservicesData);
|
const webservicesData = await webservicesResult.json();
|
||||||
return {
|
|
||||||
webservices: {
|
|
||||||
technologies: webservicesData.technologies,
|
|
||||||
affiliates: webservicesData.affiliates,
|
|
||||||
hosts: webservicesData.hosts
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//console.log(webservicesData);
|
||||||
|
return {
|
||||||
|
webservices: {
|
||||||
|
technologies: webservicesData.technologies,
|
||||||
|
affiliates: webservicesData.affiliates,
|
||||||
|
hosts: webservicesData.hosts,
|
||||||
|
licenses: webservicesData.licenses
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -8,14 +8,16 @@
|
||||||
|
|
||||||
// the filters
|
// the filters
|
||||||
import { setFilter, getFilter } from '$lib/components/filter.js';
|
import { setFilter, getFilter } from '$lib/components/filter.js';
|
||||||
import { Accordions, Accordion, AccordionBody } from 'yesvelte';
|
import { Accordions, Accordion, AccordionBody, El } from 'yesvelte';
|
||||||
import Filterable from '$lib/components/Filterable.svelte';
|
import Filterable from '$lib/components/Filterable.svelte';
|
||||||
// collapsible sections
|
// collapsible sections
|
||||||
//import CollapsibleSection from '$lib/components/CollapsibleSection.svelte';
|
//import CollapsibleSection from '$lib/components/CollapsibleSection.svelte';
|
||||||
import TechnologyTile from '$lib/components/TechnologyTile.svelte';
|
import TechnologyTile from '$lib/components/TechnologyTile.svelte';
|
||||||
|
// URL-related stuff
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
let tabindex = 0; // a counter which facilitates keyboard navigation.
|
let tabindex = 0; // a counter which facilitates keyboard navigation.
|
||||||
|
let showModal = true; // use to make a technology modal show when rendered
|
||||||
|
|
||||||
// return the % a is of b
|
// return the % a is of b
|
||||||
function percent(a, b) {
|
function percent(a, b) {
|
||||||
|
@ -41,6 +43,7 @@
|
||||||
// actual objects
|
// actual objects
|
||||||
let hosts = [];
|
let hosts = [];
|
||||||
let affiliates = [];
|
let affiliates = [];
|
||||||
|
let licenses = [];
|
||||||
|
|
||||||
//
|
//
|
||||||
// just a trivial reassignment
|
// just a trivial reassignment
|
||||||
|
@ -117,6 +120,10 @@
|
||||||
let affiliate = webservices.affiliates[key];
|
let affiliate = webservices.affiliates[key];
|
||||||
affiliates[key] = affiliate;
|
affiliates[key] = affiliate;
|
||||||
}
|
}
|
||||||
|
for (let key in webservices.licenses) {
|
||||||
|
let license = webservices.licenses[key];
|
||||||
|
licenses[key] = license;
|
||||||
|
}
|
||||||
|
|
||||||
// assign stats based on gathered data...
|
// assign stats based on gathered data...
|
||||||
stats.current = current.length;
|
stats.current = current.length;
|
||||||
|
@ -148,7 +155,8 @@
|
||||||
host_list: host_list
|
host_list: host_list
|
||||||
},
|
},
|
||||||
hosts: hosts,
|
hosts: hosts,
|
||||||
affiliates: affiliates
|
affiliates: affiliates,
|
||||||
|
licenses: licenses
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +287,8 @@
|
||||||
return technologies.sort((a, b) => a.name.localeCompare(b.name));
|
return technologies.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set previous and next on each technology
|
||||||
|
|
||||||
// generic function to find the intersection of two arrays
|
// generic function to find the intersection of two arrays
|
||||||
// approach ref: https://bobbyhadz.com/blog/javascript-get-intersection-of-two-arrays
|
// approach ref: https://bobbyhadz.com/blog/javascript-get-intersection-of-two-arrays
|
||||||
function inCommon(a, b) {
|
function inCommon(a, b) {
|
||||||
|
@ -389,6 +399,7 @@
|
||||||
//
|
//
|
||||||
// process the data received by the web request!
|
// process the data received by the web request!
|
||||||
const results = processData(webservices);
|
const results = processData(webservices);
|
||||||
|
const licenses = results.licenses;
|
||||||
|
|
||||||
//const technologies = webservices.technologies;
|
//const technologies = webservices.technologies;
|
||||||
//console.log(technologies);
|
//console.log(technologies);
|
||||||
|
@ -422,10 +433,12 @@
|
||||||
const affiliates = results.affiliates;
|
const affiliates = results.affiliates;
|
||||||
//console.log('affiliate_data: ', results.affiliates);
|
//console.log('affiliate_data: ', results.affiliates);
|
||||||
const host_colours = hostColours($hostFilter, colours, hosts);
|
const host_colours = hostColours($hostFilter, colours, hosts);
|
||||||
console.log('host_colours:', host_colours);
|
//console.log('host_colours:', host_colours);
|
||||||
colours.sort();
|
colours.sort();
|
||||||
const affiliate_colours = affiliateColours($affiliateFilter, colours, affiliates);
|
const affiliate_colours = affiliateColours($affiliateFilter, colours, affiliates);
|
||||||
console.log('affiliate_colours:',affiliate_colours);
|
//console.log('affiliate_colours:',affiliate_colours);
|
||||||
|
|
||||||
|
//console.log('licenses:',licenses );
|
||||||
|
|
||||||
let filteredTechnologies;
|
let filteredTechnologies;
|
||||||
let technologies;
|
let technologies;
|
||||||
|
@ -464,16 +477,16 @@
|
||||||
'license',
|
'license',
|
||||||
flattenFilter($licenseFilter)
|
flattenFilter($licenseFilter)
|
||||||
);
|
);
|
||||||
/*console.log(
|
console.log(
|
||||||
'about to sort technologies alphabetically - starting with ' +
|
'about to filter technologies by instance status - starting with ' +
|
||||||
filteredTechnologies.length +
|
filteredTechnologies.length +
|
||||||
' technologies...'
|
' technologies...'
|
||||||
);*/
|
);
|
||||||
/*filteredTechnologies = filterTechnologiesByInstanceValue(
|
/*filteredTechnologies = filterTechnologiesByInstanceValue(
|
||||||
filteredTechnologies,
|
filteredTechnologies,
|
||||||
'status',
|
'status',
|
||||||
flattenFilter($statusFilter)
|
flattenFilter($statusFilter)
|
||||||
)*/
|
)
|
||||||
/*filteredTechnologies = filterTechnologiesByInstanceValue(
|
/*filteredTechnologies = filterTechnologiesByInstanceValue(
|
||||||
filteredTechnologies,
|
filteredTechnologies,
|
||||||
'affiliate',
|
'affiliate',
|
||||||
|
@ -486,8 +499,13 @@
|
||||||
)*/
|
)*/
|
||||||
|
|
||||||
//filteredTechnologies = filterTechnologiesByCategoryList(results.all_services, flattenFilter($categoryFilter));
|
//filteredTechnologies = filterTechnologiesByCategoryList(results.all_services, flattenFilter($categoryFilter));
|
||||||
|
console.log(
|
||||||
|
'about to sort technologies alphabetically - starting with ' +
|
||||||
|
filteredTechnologies.length +
|
||||||
|
' technologies...'
|
||||||
|
);
|
||||||
const technologies = sortTechnologies(filteredTechnologies);
|
const technologies = sortTechnologies(filteredTechnologies);
|
||||||
console.log('finally have ' + technologies.length + ' technologies left to show...');
|
//console.log('finally have ' + technologies.length + ' technologies left to show...');
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -595,9 +613,7 @@
|
||||||
context={'categories'}>
|
context={'categories'}>
|
||||||
<h2 slot="title">Categories</h2>
|
<h2 slot="title">Categories</h2>
|
||||||
<p slot="description">
|
<p slot="description">
|
||||||
You can These are general categories of software which help you understand the
|
These are general categories of software which help you understand the sort of software you're looking at, as well as identifying functionally similar software for comparison.
|
||||||
sort of software you're looking at, as well as identifying functionally similar
|
|
||||||
software for comparison.
|
|
||||||
</p>
|
</p>
|
||||||
</Filterable>
|
</Filterable>
|
||||||
</div>
|
</div>
|
||||||
|
@ -689,9 +705,16 @@
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Accordions>
|
</Accordions>
|
||||||
<p>Showing {filteredTechnologies.length} technology tiles.</p>
|
<p>Showing {filteredTechnologies.length} technology tiles.</p>
|
||||||
|
<!--<p>Current URL: {$page.url}...</p>-->
|
||||||
<div class="tiles">
|
<div class="tiles">
|
||||||
{#each filteredTechnologies as technology}
|
{#each filteredTechnologies as technology, index}
|
||||||
<TechnologyTile {technology} {affiliate_colours} />
|
<!--{#if (index != 1) }-->
|
||||||
|
<TechnologyTile {technology} {affiliate_colours} {licenses}/>
|
||||||
|
<!--{:else}
|
||||||
|
<TechnologyTile {technology} {affiliate_colours} {licenses} {showModal}/>
|
||||||
|
{/if}-->
|
||||||
|
{:else}
|
||||||
|
<p class='no-tiles'>No technologies are selected</p>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -724,7 +747,7 @@
|
||||||
min-width: 30em;
|
min-width: 30em;
|
||||||
border: 2px #aaa solid;
|
border: 2px #aaa solid;
|
||||||
margin: 0 15px 20px 6px;
|
margin: 0 15px 20px 6px;
|
||||||
padding: 0 20px;
|
padding: 10px 20px;
|
||||||
box-shadow: 6px 6px 20px #999;
|
box-shadow: 6px 6px 20px #999;
|
||||||
}
|
}
|
||||||
.summary .label {
|
.summary .label {
|
||||||
|
|
Loading…
Reference in a new issue