qa: Refactor layout
This commit is contained in:
parent
859b6a318e
commit
c13da8b574
19 changed files with 425 additions and 295 deletions
13
qa/ui/src/routes/exercices/[eid]/+layout.js
Normal file
13
qa/ui/src/routes/exercices/[eid]/+layout.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { getExercice } from '$lib/exercices';
|
||||
import { getExerciceQA } from '$lib/qa.js';
|
||||
|
||||
/** @type {import('./$types').PageLoad} */
|
||||
export async function load({ depends, params }) {
|
||||
const exercice = getExercice(params.eid)
|
||||
depends(`api/exercices/${params.eid}`);
|
||||
|
||||
const qaitems = getExerciceQA(params.eid);
|
||||
depends(`api/exercices/${params.eid}/qa`);
|
||||
|
||||
return { exercice, qaitems };
|
||||
}
|
||||
20
qa/ui/src/routes/exercices/[eid]/+layout.svelte
Normal file
20
qa/ui/src/routes/exercices/[eid]/+layout.svelte
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<script>
|
||||
import { page } from '$app/stores';
|
||||
|
||||
import ExerciceLayout from '$lib/components/ExerciceLayout.svelte';
|
||||
import { themes } from '$lib/stores/themes';
|
||||
|
||||
if ($themes.length == 0) {
|
||||
themes.refresh();
|
||||
}
|
||||
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<ExerciceLayout
|
||||
exercice={data.exercice}
|
||||
qaitems={data.qaitems}
|
||||
query_selected={$page.params.qid}
|
||||
>
|
||||
<slot></slot>
|
||||
</ExerciceLayout>
|
||||
|
|
@ -1,26 +1,34 @@
|
|||
<script>
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Container,
|
||||
Icon,
|
||||
Spinner,
|
||||
Row,
|
||||
Table,
|
||||
} from 'sveltestrap';
|
||||
|
||||
import { getExercice } from '$lib/exercices';
|
||||
import ExerciceQA from '$lib/components/ExerciceQA.svelte';
|
||||
import QANewItem from '$lib/components/QANewItem.svelte';
|
||||
|
||||
let exerciceP = getExercice($page.params.eid);
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
{#await exerciceP}
|
||||
<Container class="mt-2 mb-5">
|
||||
<div class="d-flex justify-content-center">
|
||||
<Spinner size="lg" />
|
||||
</div>
|
||||
</Container>
|
||||
{:then exercice}
|
||||
<ExerciceQA {exercice} />
|
||||
{/await}
|
||||
<Row class="mb-3">
|
||||
<div
|
||||
class="col-md-6"
|
||||
style="overflow-y: auto; max-height: 40vh;"
|
||||
>
|
||||
{@html data.exercice.statement.replace("$FILES$", "../files")}
|
||||
</div>
|
||||
<div
|
||||
class="col-md-6"
|
||||
style="overflow-y: auto; max-height: 40vh;"
|
||||
>
|
||||
{@html data.exercice.overview.replace("$FILES$", "../files")}
|
||||
</div>
|
||||
</Row>
|
||||
|
||||
<QANewItem
|
||||
theme={data.theme}
|
||||
exercice={data.exercice}
|
||||
/>
|
||||
|
|
|
|||
21
qa/ui/src/routes/exercices/[eid]/[qid]/+layout.js
Normal file
21
qa/ui/src/routes/exercices/[eid]/[qid]/+layout.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { error } from '@sveltejs/kit';
|
||||
|
||||
/** @type {import('./$types').PageLoad} */
|
||||
export async function load({ params, parent }) {
|
||||
const { exercice, qaitems } = await parent();
|
||||
|
||||
let query_selected = null;
|
||||
for (const qaitem of qaitems) {
|
||||
if (qaitem.id == params.qid) {
|
||||
query_selected = qaitem;
|
||||
}
|
||||
}
|
||||
|
||||
if (!query_selected) {
|
||||
throw error(404, {
|
||||
message: 'Not found'
|
||||
});
|
||||
}
|
||||
|
||||
return { exercice, qaitems, query_selected };
|
||||
}
|
||||
10
qa/ui/src/routes/exercices/[eid]/[qid]/+page.svelte
Normal file
10
qa/ui/src/routes/exercices/[eid]/[qid]/+page.svelte
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script>
|
||||
import QAItem from '$lib/components/QAItem.svelte';
|
||||
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<QAItem
|
||||
exercice={data.exercice}
|
||||
query={data.query_selected}
|
||||
/>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<slot></slot>
|
||||
9
qa/ui/src/routes/themes/[tid]/+layout.js
Normal file
9
qa/ui/src/routes/themes/[tid]/+layout.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { getTheme } from '$lib/themes';
|
||||
|
||||
/** @type {import('./$types').PageLoad} */
|
||||
export async function load({ depends, params }) {
|
||||
const theme = getTheme(params.tid)
|
||||
depends(`api/themes/${params.tid}`);
|
||||
|
||||
return { theme };
|
||||
}
|
||||
|
|
@ -10,9 +10,9 @@
|
|||
Spinner,
|
||||
} from 'sveltestrap';
|
||||
|
||||
import { getTheme } from '$lib/themes';
|
||||
import { fieldsExercices, getThemedExercices } from '$lib/exercices';
|
||||
|
||||
export let data;
|
||||
let query = "";
|
||||
|
||||
function show(id) {
|
||||
|
|
@ -21,67 +21,61 @@
|
|||
</script>
|
||||
|
||||
<Container class="mt-2 mb-5">
|
||||
{#await getTheme($page.params.tid)}
|
||||
<div class="d-flex justify-content-center">
|
||||
<Spinner size="lg" />
|
||||
</div>
|
||||
{:then theme}
|
||||
<div class="d-flex align-items-end">
|
||||
<Button
|
||||
class="align-self-center"
|
||||
color="link"
|
||||
on:click={() => goto('themes/')}
|
||||
>
|
||||
<Icon name="chevron-left" />
|
||||
</Button>
|
||||
<h2>
|
||||
{theme.name}
|
||||
</h2>
|
||||
<small class="m-2 mb-3 text-muted text-truncate">{@html theme.authors}</small>
|
||||
</div>
|
||||
<div class="d-flex align-items-end">
|
||||
<Button
|
||||
class="align-self-center"
|
||||
color="link"
|
||||
on:click={() => goto('themes/')}
|
||||
>
|
||||
<Icon name="chevron-left" />
|
||||
</Button>
|
||||
<h2>
|
||||
{data.theme.name}
|
||||
</h2>
|
||||
<small class="m-2 mb-3 text-muted text-truncate">{@html data.theme.authors}</small>
|
||||
</div>
|
||||
|
||||
{#if theme.intro}
|
||||
<Container class="text-muted" style="overflow-y: auto; max-height: 34vh">
|
||||
{@html theme.intro.replace("$FILES$", "../files")}
|
||||
</Container>
|
||||
{/if}
|
||||
{#if data.theme.intro}
|
||||
<Container class="text-muted" style="overflow-y: auto; max-height: 34vh">
|
||||
{@html data.theme.intro.replace("$FILES$", "../files")}
|
||||
</Container>
|
||||
{/if}
|
||||
|
||||
{#await getThemedExercices($page.params.tid)}
|
||||
{:then exercices}
|
||||
<h3 class="mt-2">
|
||||
Défis ({exercices.length})
|
||||
</h3>
|
||||
{#await getThemedExercices($page.params.tid)}
|
||||
{:then exercices}
|
||||
<h3 class="mt-2">
|
||||
Défis ({exercices.length})
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
<input type="search" class="form-control form-control-sm" placeholder="Search" bind:value={query} autofocus>
|
||||
</p>
|
||||
<Table class="table-hover table-bordered table-striped table-sm">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
{#each fieldsExercices as field}
|
||||
<th>
|
||||
{field}
|
||||
</th>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each exercices as exercice (exercice.id)}
|
||||
{#if exercice.title.indexOf(query) >= 0}
|
||||
<tr on:click={() => show(exercice.id)}>
|
||||
{#each fieldsExercices as field}
|
||||
<td>
|
||||
{@html exercice[field]}
|
||||
{#if field == "title" && exercice.wip}
|
||||
<Icon name="cone-striped" />
|
||||
{/if}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/if}
|
||||
<p>
|
||||
<input type="search" class="form-control form-control-sm" placeholder="Search" bind:value={query} autofocus>
|
||||
</p>
|
||||
<Table class="table-hover table-bordered table-striped table-sm">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
{#each fieldsExercices as field}
|
||||
<th>
|
||||
{field}
|
||||
</th>
|
||||
{/each}
|
||||
</tbody>
|
||||
</Table>
|
||||
{/await}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each exercices as exercice (exercice.id)}
|
||||
{#if exercice.title.indexOf(query) >= 0}
|
||||
<tr on:click={() => show(exercice.id)}>
|
||||
{#each fieldsExercices as field}
|
||||
<td>
|
||||
{@html exercice[field]}
|
||||
{#if field == "title" && exercice.wip}
|
||||
<Icon name="cone-striped" />
|
||||
{/if}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
</tbody>
|
||||
</Table>
|
||||
{/await}
|
||||
</Container>
|
||||
|
|
|
|||
15
qa/ui/src/routes/themes/[tid]/[eid]/+layout.js
Normal file
15
qa/ui/src/routes/themes/[tid]/[eid]/+layout.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { getExercice } from '$lib/exercices';
|
||||
import { getExerciceQA } from '$lib/qa.js';
|
||||
|
||||
/** @type {import('./$types').PageLoad} */
|
||||
export async function load({ depends, params, parent }) {
|
||||
const { theme } = await parent();
|
||||
|
||||
const exercice = getExercice(params.eid)
|
||||
depends(`api/exercices/${params.eid}`);
|
||||
|
||||
const qaitems = getExerciceQA(params.eid);
|
||||
depends(`api/exercices/${params.eid}/qa`);
|
||||
|
||||
return { exercice, qaitems, theme };
|
||||
}
|
||||
21
qa/ui/src/routes/themes/[tid]/[eid]/+layout.svelte
Normal file
21
qa/ui/src/routes/themes/[tid]/[eid]/+layout.svelte
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script>
|
||||
import { page } from '$app/stores';
|
||||
|
||||
import ExerciceLayout from '$lib/components/ExerciceLayout.svelte';
|
||||
import { themes } from '$lib/stores/themes';
|
||||
|
||||
if ($themes.length == 0) {
|
||||
themes.refresh();
|
||||
}
|
||||
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<ExerciceLayout
|
||||
exercice={data.exercice}
|
||||
qaitems={data.qaitems}
|
||||
query_selected={$page.params.qid}
|
||||
theme={data.theme}
|
||||
>
|
||||
<slot></slot>
|
||||
</ExerciceLayout>
|
||||
|
|
@ -1,26 +1,34 @@
|
|||
<script>
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Container,
|
||||
Icon,
|
||||
Spinner,
|
||||
Row,
|
||||
Table,
|
||||
} from 'sveltestrap';
|
||||
|
||||
import { getThemedExercice } from '$lib/exercices';
|
||||
import ExerciceQA from '$lib/components/ExerciceQA.svelte';
|
||||
import QANewItem from '$lib/components/QANewItem.svelte';
|
||||
|
||||
let exerciceP = getThemedExercice($page.params.tid, $page.params.eid);
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
{#await exerciceP}
|
||||
<Container class="mt-2 mb-5">
|
||||
<div class="d-flex justify-content-center">
|
||||
<Spinner size="lg" />
|
||||
</div>
|
||||
</Container>
|
||||
{:then exercice}
|
||||
<ExerciceQA theme_id={$page.params.tid} {exercice} />
|
||||
{/await}
|
||||
<Row class="mb-3">
|
||||
<div
|
||||
class="col-md-6"
|
||||
style="overflow-y: auto; max-height: 40vh;"
|
||||
>
|
||||
{@html data.exercice.statement.replace("$FILES$", "../files")}
|
||||
</div>
|
||||
<div
|
||||
class="col-md-6"
|
||||
style="overflow-y: auto; max-height: 40vh;"
|
||||
>
|
||||
{@html data.exercice.overview.replace("$FILES$", "../files")}
|
||||
</div>
|
||||
</Row>
|
||||
|
||||
<QANewItem
|
||||
theme={data.theme}
|
||||
exercice={data.exercice}
|
||||
/>
|
||||
|
|
|
|||
21
qa/ui/src/routes/themes/[tid]/[eid]/[qid]/+layout.js
Normal file
21
qa/ui/src/routes/themes/[tid]/[eid]/[qid]/+layout.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { error } from '@sveltejs/kit';
|
||||
|
||||
/** @type {import('./$types').PageLoad} */
|
||||
export async function load({ params, parent }) {
|
||||
const { exercice, qaitems, theme } = await parent();
|
||||
|
||||
let query_selected = null;
|
||||
for (const qaitem of qaitems) {
|
||||
if (qaitem.id == params.qid) {
|
||||
query_selected = qaitem;
|
||||
}
|
||||
}
|
||||
|
||||
if (!query_selected) {
|
||||
throw error(404, {
|
||||
message: 'Not found'
|
||||
});
|
||||
}
|
||||
|
||||
return { exercice, qaitems, query_selected, theme };
|
||||
}
|
||||
11
qa/ui/src/routes/themes/[tid]/[eid]/[qid]/+page.svelte
Normal file
11
qa/ui/src/routes/themes/[tid]/[eid]/[qid]/+page.svelte
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<script>
|
||||
import QAItem from '$lib/components/QAItem.svelte';
|
||||
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<QAItem
|
||||
exercice={data.exercice}
|
||||
query={data.query_selected}
|
||||
theme={data.theme}
|
||||
/>
|
||||
Reference in a new issue