diff --git a/src/lib/components/CollapsibleSection.svelte b/src/lib/components/CollapsibleSection.svelte index 62acc24..cb701e5 100644 --- a/src/lib/components/CollapsibleSection.svelte +++ b/src/lib/components/CollapsibleSection.svelte @@ -4,67 +4,40 @@ // Inclusive Components by Heydon Pickering https://inclusive-components.design/collapsible-sections/ export let headerText; - let expanded = false; + let expanded = false

- +
diff --git a/src/lib/components/Filterable.svelte b/src/lib/components/Filterable.svelte index 059986f..fd311f8 100644 --- a/src/lib/components/Filterable.svelte +++ b/src/lib/components/Filterable.svelte @@ -6,8 +6,7 @@ export let tabindex = 0; export let context = 'none'; export let filterValues; - export let histogram; // an array with key = filter value, val = number of technologies - //console.log('Filterable contextFilter: ', filterValues); + console.log('Filterable contextFilter: ', filterValues); let activeFiltersString = 'None'; // @@ -21,8 +20,8 @@ }); function joinActive(isActive) { - //console.log('joinActive'); - //console.log('filterValues: ', filterValues); + console.log('joinActive'); + console.log('filterValues: ', filterValues); if (isActive.length) return formatter.format(isActive); return 'No'; } @@ -41,7 +40,7 @@ // active is an array of active filter filterValues export function filterVerbage(active) { - //console.log('l = ', active.length); + console.log('l = ', active.length); if (active.length == 1) return 'filter is'; else return 'filters are'; } @@ -49,9 +48,9 @@ // // managing filter values function updateFilterValues(filter) { - //console.log('filter ('+ filter.id + ') has state ' + filter.active + '...'); + console.log('filter ('+ filter.id + ') has state ' + filter.active + '...'); $filterValues.forEach(function(b, i) { - //console.log('b: ', b); + console.log('b: ', b); if (b.id == filter.id) { $filterValues[i].active = filter.active; } }) return filterValues; @@ -74,8 +73,6 @@ activeFiltersString = joinActive(isActive); filterText = filterVerbage(isActive); } - - console.log('histogram: ', histogram);

Test Array

@@ -91,7 +88,7 @@ {filter.name}{#if (histogram[filter.name] > 1) }  ({histogram[filter.name]}){/if} + name="{filter.id}" role="button" tabindex={tabindex + filter.id}>{filter.name} {/each} @@ -100,7 +97,6 @@ diff --git a/src/lib/components/Tile.svelte b/src/lib/components/Tile.svelte deleted file mode 100644 index 92e95ea..0000000 --- a/src/lib/components/Tile.svelte +++ /dev/null @@ -1,189 +0,0 @@ - - -
- -

{technology.name}

-

- {technology.description}{#if technology.extended_description}i{/if} -

- {#if technology.categories}

- {pluraliser('Category', 'Categories', technology.categories.length)}: - {toOxfordCommaString(technology.categories)} -

{/if} - {#if technology.analogues}

- Alternative to {toOxfordCommaString(technology.analogues)} -

{/if} - {#if technology.license}

- License: {technology.license} -

{/if} - {#if hasInstances(technology)} -
-

- {#each technology.instances as instance} - {/each} -

-
- {:else} -
Nothing here yet...
- {/if} -
- - diff --git a/src/lib/components/filter.js b/src/lib/components/filter.js index 158410a..e70cc4a 100644 --- a/src/lib/components/filter.js +++ b/src/lib/components/filter.js @@ -3,17 +3,17 @@ import { getContext, setContext } from 'svelte'; export function setFilter(context) { let contextFilter = writable(0); - //console.log('setFilter: ', contextFilter); + console.log('setFilter: ', contextFilter); contextFilter.subscribe((value) => { - //console.log('initial value: ', value); + console.log('initial value: ', value); }); setContext(context, contextFilter); - //console.log('contextFilter (' + context + '): ', contextFilter); + console.log('contextFilter (' + context + '): ', contextFilter); } export function getFilter(context) { - //console.log('looking for writable for context ', context); + console.log('looking for writable for context ', context); let f = getContext(context); - //console.log('returning filter writable: ', f); + console.log('returning filter writable: ', f); return f; } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index f436bcf..84fc96f 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -10,18 +10,16 @@ import { setFilter, getFilter } from '$lib/components/filter.js'; import Filterable from '$lib/components/Filterable.svelte'; // collapsible sections - import CollapsibleSection from '$lib/components/CollapsibleSection.svelte'; - import Tile from '$lib/components/Tile.svelte'; + import CollapsibleSection from '$lib/components/CollapsibleSection.svelte' //console.log('colours: ', colours); // // digest and return useful info from the Webservices JSON feed function processData(webservices) { - let stats = { 'instances': 0, 'technologies': 0, 'licenses': 0,'weak': 0, 'copyleft': 0 }; - let all = []; // all services - let current = []; // those with active instances - let future = []; // those that are planned + let instances = 0; + let current = []; + let future = []; // properties of technologies let category_list = []; let analogue_list = []; @@ -34,7 +32,6 @@ // actual objects let hosts = []; let affiliates = []; - // // just a trivial reassignment //let hosts = webservices.hosts; @@ -42,10 +39,7 @@ // pull out relevant info in useful chunks. for (let key in webservices.technologies) { let tech = webservices.technologies[key]; - tech['name'] = key; - console.log('tech '+key+' ('+tech.categories.length+'):', tech.categories); if (tech.hasOwnProperty('categories') && tech.categories.constructor === Array) { - //console.log('tech '+key+' ('+tech.categories.length+'):', tech.categories); tech.categories.forEach(function (category, index) { if (category_list.hasOwnProperty(category)) category_list[category]++; else category_list[category] = 1; @@ -62,11 +56,13 @@ if (license_list.hasOwnProperty(license)) license_list[license]++; else license_list[license] = 1; } + if (hasInstances(tech)) { + tech['name'] = key; current.push(tech); //console.log(tech.name + ': ' + tech.instances.length + ' instances...'); tech.instances.forEach(function (instance, i) { - stats.instances++; + instances++; if (instance.hasOwnProperty('status')) { let tag = instance.status; if (status_list.hasOwnProperty(tag)) status_list[tag]++; @@ -87,7 +83,6 @@ } else { future[key] = tech; } - all[key] = tech; } for (let key in webservices.hosts) { //console.log('key: ', key); @@ -106,15 +101,8 @@ affiliates[key] = affiliate; } - // assign stats based on gathered data... - stats.current = current.length; - stats.future = future.length; - console.log('license_list: ', license_list); - stats.licenses = license_list.length; - return { - stats: stats, - all_services: all, + total_instances: instances, active_services: current, candidate_services: future, tech_lists: { @@ -132,7 +120,18 @@ }; } - // return an object with ob's keys ordered alphabetically, with an id from an object + // console.log(technologies); + // return true if a tech object includes valid instances + function hasInstances(tech) { + if ( + tech.hasOwnProperty('instances') && + tech.instances.constructor === Array && + tech.instances.length + ) return true; + return false; + } + + // return an object with ob's keys ordered alphabetically, with an idfrom an object function getSortedFilter(ob) { let keys = []; let i = 0; @@ -150,17 +149,6 @@ return key_array; } - // return true if a tech object includes valid instances - function hasInstances(tech) { - if ( - tech.hasOwnProperty('instances') && - tech.instances.constructor === Array && - tech.instances.length - ) return true; - return false; - } - - // get intersection: ref https://bobbyhadz.com/blog/javascript-get-intersection-of-two-arrays function getIntersection(a, b) { const set1 = new Set(a); @@ -171,6 +159,22 @@ return intersection; } + // combine an array of terms into a sentence with proper Oxford commas, dealing with the special cases + // of one or two elements. + function toOxfordCommaString(arr) { + if (arr.length == 1) return arr; + if (arr.length == 2) return arr.join(' and '); + else { + var last = arr.pop(); + return arr.join(', ') + ', and ' + last; + } + } + + // return a singular or plural term depending on the value of 'count' + function pluraliser(singular, plural, count) { + if (count > 1) return plural; + return singular; + } // assign colours from a set of differentiated colours to a list of tags... // this one is for 'hosts' @@ -235,7 +239,7 @@ const set2 = new Set(b); const intersection = [...set1].filter((element) => set2.has(element)); - //console.log('intersection = ', intersection); + console.log('intersection = ', intersection); return intersection; } @@ -250,14 +254,13 @@ // filter technologies based on a list of Categories function filterTechnologiesByCategoryList(technologies, list) { - //console.log('looking for tech in categories: ', list); + console.log('looking for tech in categories: ', list); const included = []; technologies.forEach(function (tech) { if (hasInstances(tech)) { const intersection = inCommon(tech.categories, list); - console.log('for tech: ', tech.name); - console.log('categories: ', tech.categories); - console.log('list: ', list); + //console.log('categories: ', tech.categories); + //console.log('list: ', list); console.log('intersection: ', intersection); if (intersection && intersection.constructor === Array) { //console.log('found intersection!', intersection.constructor); @@ -319,9 +322,8 @@ // reactive stuff... $: { - //console.log('about to filterTechnologiesByCategoryList'); + console.log('about to filterTechnologiesByCategoryList'); filteredTechnologies = filterTechnologiesByCategoryList(results.active_services, flattenFilter($categoryFilter)); - //filteredTechnologies = filterTechnologiesByCategoryList(results.all_services, flattenFilter($categoryFilter)); const technologies = sortTechnologies(filteredTechnologies); } @@ -333,75 +335,61 @@
-
-
-

Web Services

-

This sites exists to provide an 'always-up-to-date', in-depth description of the libre software web services I have set - up and maintain. -

+

Web Services

+ +
+

This sites exists to provide an 'always-up-to-date', in-depth description of the libre software web services I have set + up and maintain. +

-
-
-

Statistics

-
    -
  • Number of individual services: {results.stats.instances}
  • -
  • Number of individual technologies: {results.stats.current}
  • -
  • Number of new technologies to be added: {results.stats.future}
  • -
  • Number of libre licenses used by these technologies: {results.stats.licenses}
  • -
  •   'weak' corporate-exploitation-friendly open source licenses : {results.stats.weak}
  • -
  •   'strong' user-protecting copyleft licenses: {results.stats.copyleft}
  • -
  • Total number of services: {results.stats.instances}
  • -
-
- +
+
    +
  • Total number of services: {results.total_instances}
  • +
+
+
- -
- + +
+

Categories

- -
- + +
+

Analogues

- -
- + +
+

Open Source & Copyleft Licenses

- -
- + +
+

Statuses

- -
- + +
+

Affiliates

- -
- + +
+

Hosts

@@ -410,7 +398,56 @@
{#each filteredTechnologies as technology} - +
+ +

{technology.name}

+

+ {technology.description}{#if technology.extended_description}i{/if} +

+ {#if technology.categories}

+ {pluraliser('Category', 'Categories', technology.categories.length)}: + {toOxfordCommaString(technology.categories)} +

{/if} + {#if technology.analogues}

+ Alternative to {toOxfordCommaString(technology.analogues)} +

{/if} + {#if technology.license}

+ License: {technology.license} +

{/if} + {#if hasInstances(technology)} +
+

+ {#each technology.instances as instance} + {/each} +

+
+ {:else} +
Nothing here yet...
+ {/if} +
{/each}
@@ -420,31 +457,170 @@ display: grid; margin: 0 auto 3em auto; padding: 0; - position: relative; - } - .introduction { - width: 50%; } .summary { - border-radius: 15px; - /*position: absolute; - right: 20px;*/ background-color: #ccc; - /*display: block;*/ - width: 50%; - border: 2px #aaa solid; - margin: 0; - padding: 0 20px; + display: block; + } + .filters { + /*background-color: #f1ff94; + padding: 0.5em; + border: 3px solid #cbea77; + margin: 1em 0;*/ + margin-bottom: 1em; } -/* .filters { margin-bottom: 1em;} .filters .tags { + /*padding: 0.5em;*/ margin: 1em 0; display: block; - }*/ + } + .tag-list { +/* white-space: normal; + word-break: normal; + display: inline;*/ + } + .tags { +/* white-space: normal; + word-break: normal; + display: inline;*/ + } + .tag { + font-size: 80%; + margin-right: 0.5em; + line-height: 2.5; + padding: 6px 8px; + border-radius: 10px; + white-space: nowrap; + word-break: normal; + box-shadow: 3px 3px 3px #6a6d6a; + } + .tag:hover { box-shadow: 4px 4px 3px #727372;} + .tag.category { + background-color: #9aa34d; + color: #fff; + } + .tag.license { + background-color: #6498a3; + color: #fff; + } + .tag.status { + background-color: #a369a2; + color: #fff; + } + .tag.affiliate { + background-color: #fff; + color: #000; + } + .tag.host { + background-color: #fff; + color: #000; + } + .tag.on { + padding-right: 25px; + background-image: url('/images/check-black-in-white-20px.png'); + background-position: right center; + background-repeat: no-repeat; + } + .tag.off { + color: #ccc; + opacity: 0.5; + } .tiles { - /*display: grid; + display: grid; grid-gap: 15px; - grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));*/ - /*grid-template-columns: repeat(auto-fit);*/ + grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); + } + /* flip card stuff: https://www.w3schools.com/howto/howto_css_flip_card.asp */ + .tile { + height: 515px; + min-width: 240px; + max-width: 300px; + /*width: 290px;*/ + overflow: hidden; + box-sizing: border-box; + box-shadow: 5px 5px 3px #6a6d6a; + border: solid 3px #1e6831; + text-overflow: ellipsis; + overflow: hidden; + position: relative; + background-color: #eee; + } + .tile .links { + position: absolute; + top: 0; + right: 0; + padding: 2px 6px; + font-size: 90%; + } + .tile:hover { + box-shadow: 10px 10px 6px #727372; + } + .tile .links h2 a { + color: #e6c4fc; + } + .tile .links a:visited { + color: #ced0ff; + } + .tile .links a:hover, + .tile:hover h2 a { + color: #fff !important; + } + .tile h2 { + background-color: #999; + text-align: center; + padding: 0.5em; + margin: 0; + } + .tile h2 a { + color: #e6c4fc; + } + .tile h2 a:visited { + color: #ced0ff; + } + .tile h2 a:hover { + color: #fff; + } + .tile .description { + height: 260px; + text-overflow: ellipsis; + overflow: hidden; + } + .tile p { + padding: 0 1em 0.2em 1em; + font-size: 80%; + color: #555; + } + .instances { + background-color: #ddd; + position: absolute; + bottom: 0; + height: 3em; + width: 100%; + } + .instances .marker { + margin-right: 3px; + } + .webservices li { + list-style-type: none; + } + .value { + font-weight: bold; + color: #000; + } + .marker { + vertical-align: middle; + } + .circle { + height: 20px; + width: 20px; + background-color: #555; + border-radius: 50%; + display: inline-block; + } + .square { + height: 20px; + width: 20px; + background-color: #555; + display: inline-block; }