webservices-app/src/routes/+page.svelte

382 lines
14 KiB
Svelte
Raw Normal View History

<script>
export let data;
const { webservices } = data;
//console.log('orig:', webservices);
//console.log('orig affiliates:', webservices.affiliates);
//console.log('orig hosts:', webservices.hosts);
2024-08-18 22:56:20 +12:00
// source: https://mokole.com/palette.html 20 colors with default settings otherwise
const colours30 = [ "#808080", "#7f0000", "#006400", "#808000", "#483d8b", "#008b8b", "#cd853f", "#00008b", "#7f007f", "#8fbc8f", "#b03060", "#ff0000", "#ff8c00", "#00ff00", "#9400d3", "#00ff7f", "#dc143c", "#00ffff", "#00bfff", "#0000ff", "#f08080", "#adff2f", "#1e90ff", "#ffff54", "#90ee90", "#add8e6", "#ff1493", "#7b68ee", "#ee82ee", "#ffe4b5" ];
function processData(webservices) {
let instances = 0;
2024-08-18 22:56:20 +12:00
let current = [];
let future = [];
// properties of technologies
let category_list = [];
let analogue_list = [];
let license_list = [];
// properties of instances
let status_list = [];
let affiliate_list = [];
let host_list = [];
// actual objects
let hosts = [];
let affiliates = [];
//
// just a trivial reassignment
//let hosts = webservices.hosts;
//
// pull out relevant info in useful chunks.
2024-08-18 22:56:20 +12:00
for (let key in webservices.technologies) {
let tech = webservices.technologies[key];
if (tech.hasOwnProperty('categories') && tech.categories.constructor === Array ) {
tech.categories.forEach(function(category, index) {
if (category_list.hasOwnProperty(category)) category_list[category]++;
else category_list[category] = 1;
});
}
if (tech.hasOwnProperty('analogues') && tech.analogues.constructor === Array ) {
tech.analogues.forEach(function(analogue, index) {
if (analogue_list.hasOwnProperty(analogue)) analogue_list[analogue]++;
else analogue_list[analogue] = 1;
});
}
if (tech.hasOwnProperty('license')) {
let license = tech.license;
if (license_list.hasOwnProperty(license)) license_list[license]++;
else license_list[license] = 1;
}
if (hasInstances(tech)) {
2024-08-18 22:56:20 +12:00
tech['name'] = key;
current.push(tech);
//console.log(tech.name + ': ' + tech.instances.length + ' instances...');
tech.instances.forEach(function(instance, i) {
2024-08-17 10:55:55 +12:00
instances++;
if (instance.hasOwnProperty('status')) {
let tag = instance.status;
if (status_list.hasOwnProperty(tag)) status_list[tag]++;
else status_list[tag] = 1;
}
if (instance.hasOwnProperty('affiliation')) {
let tag = instance.affiliation;
if (affiliate_list.hasOwnProperty(tag)) affiliate_list[tag]++;
else affiliate_list[tag] = 1;
}
if (instance.hasOwnProperty('host')) {
let tag = instance.host;
if (host_list.hasOwnProperty(tag)) host_list[tag]++;
else host_list[tag] = 1;
}
});
2024-08-18 22:56:20 +12:00
} else {
future[key] = tech;
}
2024-08-18 22:56:20 +12:00
};
for (let key in webservices.hosts) {
//console.log('key: ', key);
let host = webservices.hosts[key];
host['name'] = key;
//console.log('host: ', host);
if (host.hasOwnProperty('domain') && !(host.hasOwnProperty('status') && host.status == 'retired')) {
hosts[key] = host;
2024-08-18 22:56:20 +12:00
}
}
//console.log('webservices.affiliates: ', webservices.affiliates);
2024-08-18 22:56:20 +12:00
for (let key in webservices.affiliates) {
//console.log('key: ', key);
2024-08-18 22:56:20 +12:00
let affiliate = webservices.affiliates[key];
//console.log('affiliate assignment: ', affiliate);
affiliates[key] = affiliate;
2024-08-18 22:56:20 +12:00
// if (affiliate.hasOwnProperty('name')) {
// affiliate_data[key] = affiliate;
// }
}
//console.log('categories: ', categories);
//console.log('analogues: ', analogues);
//console.log('licenses: ', licenses);
//console.log('statuses: ', statuses);
//console.log('affiliates: ', affiliates);
//console.log('hosts: ', hosts);
return {
total_instances: instances,
active_services: current,
candidate_services: future,
tech_lists: {
category_list: category_list,
analogue_list: analogue_list,
license_list: license_list
},
instance_lists: {
status_list: status_list,
affiliate_list: affiliate_list,
host_list: host_list
2024-08-18 22:56:20 +12:00
},
hosts: hosts,
affiliates: affiliates
};
}
// console.log(technologies);
function hasInstances(tech) {
2024-08-18 22:56:20 +12:00
if (tech.hasOwnProperty('instances') && tech.instances.constructor === Array && tech.instances.length) return true;
return false;
}
function getKeys(ob) {
let keys = [];
for (let key in ob) {
keys.push(key);
};
return keys;
}
function toOxfordCommaString(arr) {
if (arr.length == 1) return arr;
else {
var last = arr.pop();
return arr.join(', ') + ', and ' + last;
}
}
function hostColours(host_list, colours, hosts) {
2024-08-18 22:56:20 +12:00
let host_array = {};
let i = 0;
//console.log('hosts:', hosts);
2024-08-18 22:56:20 +12:00
host_list.forEach(function(host) {
2024-08-18 22:56:20 +12:00
//console.log(host);
if (hosts[host].hasOwnProperty('domain') && hosts[host].hasOwnProperty('affiliation')) {
2024-08-18 22:56:20 +12:00
host_array[host] = {
"colour": colours[i++],
"domain": hosts[host].domain,
"affiliation": hosts[host].affiliation
2024-08-18 22:56:20 +12:00
}
}
});
return host_array;
}
function affiliateColours(affiliate_list, colours, affiliates) {
2024-08-18 22:56:20 +12:00
let affiliate_array = {};
let i = 0;
2024-08-18 22:56:20 +12:00
//console.log('affiliates:', affiliates);
2024-08-18 22:56:20 +12:00
for (const affiliate of affiliate_list) {
//console.log('affiliate:', affiliate);
if (affiliates[affiliate].hasOwnProperty('name') && affiliates[affiliate].hasOwnProperty('website')) {
2024-08-18 22:56:20 +12:00
affiliate_array[affiliate] = {
"colour": colours[i++],
"name": affiliates[affiliate].name,
"website": affiliates[affiliate].website
2024-08-18 22:56:20 +12:00
}
}
}
return affiliate_array;
}
const results = processData(webservices);
2024-08-18 22:56:20 +12:00
//console.log('results: ', results);
//const technologies = webservices.technologies;
const technologies = results.active_services;
//console.log(technologies);
const category_list = getKeys(results.tech_lists.category_list).sort();
const analogue_list = getKeys(results.tech_lists.analogue_list).sort();
const license_list = getKeys(results.tech_lists.license_list).sort();
const status_list = getKeys(results.instance_lists.status_list).sort();
const affiliate_list = getKeys(results.instance_lists.affiliate_list).sort();
const host_list = getKeys(results.instance_lists.host_list).sort();
const hosts = results.hosts;
2024-08-18 22:56:20 +12:00
//console.log('host_data: ', results.hosts);
const affiliates = results.affiliates;
//console.log('affiliate_data: ', results.affiliates);
const host_colours = hostColours(host_list, colours30, hosts);
2024-08-18 22:56:20 +12:00
//console.log('host_colours:', host_colours);
const affiliate_colours = affiliateColours(affiliate_list, colours30, affiliates);
//console.log('affiliate_colours:',affiliate_colours);
2024-08-18 22:56:20 +12:00
//console.log('categories array: ', results.tech_tags.categories);
2024-08-18 13:56:25 +12:00
//console.log('categories keys: ', categories);
</script>
<div class="webservices">
<h1>Web Services</h1>
<div class="summary">
<ul>
<li>Total number of services: {results.total_instances}</li>
</ul>
</div>
<div class="filters">
<div class="tag-list tech">
<div class="tags tech categories">Categories: {#each category_list as category}<span class="tag category">{category}</span> {/each}</div>
<!--<div class="tags tech analogues">{#each analogues as analogue}<span class="tag analogue">{analogue}</span> {/each}</div>-->
<div class="tags tech licenses">Licenses: {#each license_list as license}<span class="tag license">{license}</span> {/each}</div>
</div>
<div class="tag-list instance">
<div class="tags instance statuses">Statuses: {#each status_list as status}<span class="tag status">{status}</span> {/each}</div> <div class="tags instance affiliates">Affiliates: {#each affiliate_list as affiliate}<span class="tag affiliate"><span class="marker circle" style="background-color: {affiliate_colours[affiliate].colour}"></span> {affiliate}</span> {/each}</div>
<div class="tags instance hosts">Hosts: {#each host_list as host}<span class="tag host"><span class="marker square" style="background-color: {host_colours[host].colour}"></span> {host}</span> {/each}</div>
</div>
</div>
<div class="tiles">
{#each technologies as technology}
<div class="tile technology">
2024-08-18 22:56:20 +12:00
<h2><a href="{technology.website}">{technology.name}</a></h2>
{#if (technology.license)}<p class="license" title="The libre license for this project is {technology.license}">License: <span class="value">{technology.license}</span></p>{/if}
{#if (technology.analogues)}<p class="analogues">Alternative to <span class="value">{toOxfordCommaString(technology.analogues)}</span></p>{/if}
<p class="description">{technology.description}</p>
{#if hasInstances(technology)}
<div class="instances"><p>{#each technology.instances as instance}
<a href="https://{instance.domain}" title="{technology.name} instance {instance.domain} hosted on '{instance.host}' by {instance.affiliation}"><span class="marker circle" style="background-color: {affiliate_colours[instance.affiliation].colour}"></span></a>{/each}</p>
2024-08-18 22:56:20 +12:00
</div>
{:else}
<div class="instances">
Nothing here yet...
</div>
2024-08-18 22:56:20 +12:00
{/if}
</div>
{/each}
</div>
</div>
<style>
.webservices {
display: grid;
2024-08-18 22:56:20 +12:00
width: 96%;
margin: 0 auto 3em auto;
padding: 0;
}
.summary {
}
.filters {
2024-08-18 13:56:25 +12:00
/*background-color: #f1ff94;
padding: 0.5em;
border: 3px solid #cbea77;
2024-08-18 13:56:25 +12:00
margin: 1em 0;*/
margin-bottom: 1em;
}
.filters .tags {
/*padding: 0.5em;*/
margin: 1em 0;
2024-08-18 13:56:25 +12:00
display: block;
}
.tag-list {
white-space: normal;
word-break: normal;
display: inline;
}
.tag {
font-size: 80%;
2024-08-18 13:56:25 +12:00
margin-right: 0.5em;
line-height: 2.5;
padding: 6px 8px;
border-radius: 14px;
2024-08-18 13:56:25 +12:00
white-space: nowrap;
word-break: keep-all;
}
2024-08-18 13:56:25 +12:00
.tag:after { content: "\00a0"; }
.tag.category {
background-color: #a369a2;
color: #fff;
}
.tag.license {
background-color: #a369a2;
color: #fff;
}
.tag.status {
background-color: #a369a2;
color: #fff;
}
.tag.affiliate {
background-color: #fff;
color: #000;
}
.tag.host {
background-color: #fff;
color: #000;
}
.tiles {
display: grid;
grid-gap: 15px;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
/* flip card stuff: https://www.w3schools.com/howto/howto_css_flip_card.asp */
.tile {
2024-08-18 22:56:20 +12:00
height: 400px;
min-width: 250px;
max-width: 400px;
overflow: hidden;
box-sizing: border-box;
box-shadow: 5px 5px 3px #71ba71;
border: solid 3px #1e6831;
text-overflow: ellipsis;
overflow: hidden;
2024-08-18 22:56:20 +12:00
position: relative;
}
2024-08-18 22:56:20 +12:00
.tile h2 {
background-color: #999;
text-align: center;
padding: 0.5em;
margin: 0;
}
2024-08-18 22:56:20 +12:00
.tile h2 a { color: #e6c4fc; }
.tile h2 a:visited { color: #ced0ff; }
.tile h2 a:hover { color: #fff; }
.tile .description {
height: 200px;
text-overflow: ellipsis;
overflow: hidden;
}
2024-08-18 22:56:20 +12:00
.tile p {
padding: 0 1em 0.2em 1em;
2024-08-18 22:56:20 +12:00
font-size: 80%;
color: #555;
}
.instances {
background-color: #eee;
2024-08-18 22:56:20 +12:00
position: absolute;
bottom: 0;
height: 3em;
width: 100%;
}
.instances .marker {
margin-right: 3px;
}
.webservices li { list-style-type: none; }
2024-08-18 22:56:20 +12:00
.value { font-weight: bold; color: #000; }
.marker { vertical-align: middle; }
2024-08-18 22:56:20 +12:00
.triangle {
--side-size: 20px;
border-left: var(--side-size) solid transparent;
border-right: var(--side-size) solid transparent;
border-bottom: calc(2 * var(--side-size) * 0.866) solid green;
border-top: var(--side-size) solid transparent;
display: inline-block;
}
.circle {
height: 20px;
width: 20px;
2024-08-18 22:56:20 +12:00
background-color: #555;
border-radius: 50%;
display: inline-block;
2024-08-18 22:56:20 +12:00
}
.square {
height: 20px;
width: 20px;
background-color: #555;
display: inline-block;
2024-08-18 22:56:20 +12:00
}
</style>