ui: Use Masonry layout to present themes and exercices on home page

This commit is contained in:
nemunaire 2024-03-16 10:18:03 +01:00
parent 13a11269a8
commit 5e48ab0928
5 changed files with 86 additions and 39 deletions

View File

@ -14,6 +14,7 @@
"bootswatch": "^5.1.3",
"hash-wasm": "^4.9.0",
"seedrandom": "^3.0.5",
"svelte-bricks": "^0.2.1",
"vite": "^5.0.0",
"wordcloud": "^1.2.2"
},
@ -46,7 +47,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
@ -516,7 +516,6 @@
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
@ -530,7 +529,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
@ -539,7 +537,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
@ -547,14 +544,12 @@
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
@ -880,8 +875,7 @@
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"dev": true
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
},
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
@ -893,7 +887,6 @@
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
@ -973,7 +966,6 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"dependencies": {
"dequal": "^2.0.3"
}
@ -982,7 +974,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz",
"integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==",
"dev": true,
"dependencies": {
"dequal": "^2.0.3"
}
@ -1127,7 +1118,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.1",
@ -1187,7 +1177,6 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
"dev": true,
"dependencies": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
@ -1244,7 +1233,6 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
"dev": true,
"engines": {
"node": ">=6"
}
@ -1519,7 +1507,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0"
}
@ -1840,7 +1827,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
"dev": true,
"dependencies": {
"@types/estree": "*"
}
@ -1930,8 +1916,7 @@
"node_modules/locate-character": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
"dev": true
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="
},
"node_modules/locate-path": {
"version": "6.0.0",
@ -1970,7 +1955,6 @@
"version": "0.30.8",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
"integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
@ -1981,8 +1965,7 @@
"node_modules/mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"dev": true
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
},
"node_modules/minimatch": {
"version": "3.1.2",
@ -2158,7 +2141,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^3.0.0",
@ -2593,7 +2575,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -2638,7 +2619,6 @@
"version": "4.2.12",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.12.tgz",
"integrity": "sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
@ -2659,6 +2639,14 @@
"node": ">=16"
}
},
"node_modules/svelte-bricks": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/svelte-bricks/-/svelte-bricks-0.2.1.tgz",
"integrity": "sha512-cc3XK3j5ViPyZ3K183+Sr53B2e8mJaiV3POyoJtjmm1dYc/TBMy7jOUMt8MW/snJzodpACfqwFzokBQbrZ297w==",
"dependencies": {
"svelte": "^4.2.1"
}
},
"node_modules/svelte-eslint-parser": {
"version": "0.33.1",
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz",

View File

@ -31,6 +31,7 @@
"bootswatch": "^5.1.3",
"hash-wasm": "^4.9.0",
"seedrandom": "^3.0.5",
"svelte-bricks": "^0.2.1",
"vite": "^5.0.0",
"wordcloud": "^1.2.2"
}

View File

@ -17,13 +17,18 @@
export { className as class };
export let theme = {};
export let exercice = null;
export let style = '';
export let color = !exercice ? "dark" : "light";
let className = '';
let textColor = "light";
$: textColor = color === "dark" ? "light" : "dark";
</script>
<div class="theme-card h-100">
<div class="theme-card" {style}>
<Card
class="text-light h-100 rounded-3 niceborder {className}"
color="dark"
class="text-{textColor} rounded-3 niceborder {className}"
{color}
on:click
>
{#if exercice && exercice.image}
@ -95,8 +100,4 @@
.theme-card .card-img-top {
height: 10rem;
}
p {
color: #ccc;
}
</style>

View File

@ -12,15 +12,41 @@
import { goto } from '$app/navigation';
import Masonry from 'svelte-bricks';
import CardTheme from '$lib/components/CardTheme.svelte';
import { my } from '$lib/stores/my.js';
import { teams } from '$lib/stores/teams.js';
import { myThemes, themes } from '$lib/stores/mythemes.js';
import { settings } from '$lib/stores/settings.js';
import { themesStore } from '$lib/stores/themes.js';
let items = [];
$: {
const tmpitems = [];
for (const th of $themes) {
if (th.id == 0) continue;
tmpitems.push({id: th.id, theme: th});
}
if ($themesStore["0"] && !$themesStore["0"].locked && $themesStore["0"].exercices) {
let i = 1;
for (let j = $themesStore["0"].exercices.length - 1; j >= 0 && i < tmpitems.length; j--) {
if ($my && $my.team_id && !$my.exercices[$themesStore["0"].exercices[j].id])
continue;
tmpitems.splice(i, 0, {id: tmpitems.length, theme: $themesStore["0"], exercice: $themesStore["0"].exercices[j]});
i += 2;
}
}
items = tmpitems;
}
</script>
<Container class="mt-3">
<Container class="mt-3 mb-5">
{#if !$my}
{#if $settings.allowRegistration}
<Alert color="warning" class="text-justify" fade={false}>
@ -48,15 +74,27 @@
{/if}
{/if}
<Row cols={{ lg: 3, md: 2, sm: 1 }}>
{#each $themes as th, index}
<Col class="mb-3">
<Masonry
{items}
let:item
>
{#if item.exercice}
{@const theme = item.theme}
{@const exercice = item.exercice}
<CardTheme
class="{$my && $my.team_id && exercice.solved?'border-light ':''}{exercice.curcoeff > 1?'border-success ':''}{theme.locked || exercice.disabled?' border-secondary ':''}"
{theme}
{exercice}
on:click={goto(`${theme.urlid}/${exercice.urlid}`)}
/>
{:else}
{@const th = item.theme}
<CardTheme
class="{$my && $my.team_id && $myThemes[th.id].exercice_solved > 0?'border-light ':''}{th.exercice_coeff_max > 1?'border-success ':''}{th.locked?' border-secondary ':''}"
theme={th}
on:click={goto(`${th.urlid}`)}
/>
</Col>
{/each}
</Row>
{/if}
</Masonry>
</Container>

View File

@ -12,6 +12,9 @@
import { goto } from '$app/navigation';
import Masonry from 'svelte-bricks';
import CardTheme from '$lib/components/CardTheme.svelte';
import { current_theme } from '$lib/stores/themes';
import { set_current_exercice } from '$lib/stores/exercices';
import { my } from '$lib/stores/my.js';
@ -19,6 +22,21 @@
set_current_exercice.set(null);
</script>
{#if $current_theme.id == 0}
<Masonry
class="mb-5"
items={$current_theme.exercices}
let:item={exercice}
>
<CardTheme
style="min-width: max(30vw,300px); width: max(30vw,300px)"
class="item {$my && $my.team_id && exercice.solved?'border-light ':''}{exercice.curcoeff > 1?'border-success ':''}{$current_theme.locked || exercice.disabled?' border-secondary ':''}"
theme={$current_theme}
{exercice}
on:click={goto(`${$current_theme.urlid}/${exercice.urlid}`)}
/>
</Masonry>
{:else}
<Card class="bg-dark niceborder text-indent mt-2 mb-4">
<Row>
@ -142,6 +160,7 @@
</Row>
</Card>
{/if}
<style>
.list-group-item-action {