diff --git a/src/lib/components/profile/TableRow.svelte b/src/lib/components/profile/TableRow.svelte
new file mode 100644
index 0000000..0058234
--- /dev/null
+++ b/src/lib/components/profile/TableRow.svelte
@@ -0,0 +1,14 @@
+
+
+
+
+
+ |
+
+
+ |
+
diff --git a/src/lib/components/settings/timetable/TimetableCell.svelte b/src/lib/components/settings/timetable/TimetableCell.svelte
index 012b5b8..e9b58a7 100644
--- a/src/lib/components/settings/timetable/TimetableCell.svelte
+++ b/src/lib/components/settings/timetable/TimetableCell.svelte
@@ -2,6 +2,7 @@
import TextInput from '$lib/components/input/Text.svelte';
import { i } from '$lib/i18n/store';
import { asyncRequestAnimationFrame } from '$lib/utils/dom';
+ import { safeMap } from '$lib/utils/null/safeMap';
import { svocal } from '$lib/utils/store/svocal';
import type { TimetableWeekday } from './types';
import { addRow, countMaxLessons, getLastLessons } from './utils';
@@ -28,9 +29,11 @@
$timetable[day][lessonIndex] = detail;
}}
on:enter={async () => {
- const isOnlyNull = getLastLessons($timetable).every((x) => x === null);
- const hasLessons = countMaxLessons($timetable) > 0;
- if (!(isOnlyNull && hasLessons)) {
+ const lastSessions = getLastLessons($timetable);
+ const lastRowHasContent = lastSessions.some((i) => safeMap(i, (str) => str.trim()));
+ const lastRowIsFocused = countMaxLessons($timetable) <= lessonIndex + 1;
+
+ if (lastRowHasContent && lastRowIsFocused) {
timetable.update(addRow);
await asyncRequestAnimationFrame();
}
diff --git a/src/lib/components/settings/timetable/utils.ts b/src/lib/components/settings/timetable/utils.ts
index 9f94d85..739970f 100644
--- a/src/lib/components/settings/timetable/utils.ts
+++ b/src/lib/components/settings/timetable/utils.ts
@@ -11,9 +11,9 @@ import { fromEntries, objectEntries } from '$lib/utils/objects/entries';
import { self } from '$lib/utils/utils';
export function countMaxLessons(timetable: Timetable) {
- const lessonCounts = Object.values(timetable).map((x) => x.length);
+ const lessonCountsPerDay = Object.values(timetable).map((x) => x.length);
- return Math.max(...lessonCounts);
+ return Math.max(...lessonCountsPerDay);
}
export function addRow(timetable: Timetable): Timetable {
diff --git a/src/lib/constants/footer/links.ts b/src/lib/constants/footer/links.ts
index 39987f7..06078cd 100644
--- a/src/lib/constants/footer/links.ts
+++ b/src/lib/constants/footer/links.ts
@@ -42,6 +42,11 @@ export const links: LinkGroup[] = [
name: i('nav.footer.auth.join'),
href: '/join',
icon: RectangleGroup
+ },
+ {
+ name: i('nav.footer.auth.profile'),
+ href: '/profile',
+ icon: User
}
]
},
diff --git a/src/lib/constants/launcher.ts b/src/lib/constants/launcher.ts
index 2165e1b..2045b37 100644
--- a/src/lib/constants/launcher.ts
+++ b/src/lib/constants/launcher.ts
@@ -85,6 +85,16 @@ export const launcherItems: LauncherItem[] = [
},
searchTerms: split(i('launcher.register.terms'))
},
+ {
+ label: i('launcher.profile'),
+ description: null,
+ icon: User,
+ callback: () => {
+ goto('/profile');
+ closeLauncher();
+ },
+ searchTerms: split(i('launcher.profile.terms'))
+ },
{
label: i('launcher.join'),
description: null,
diff --git a/src/lib/locales/de.ts b/src/lib/locales/de.ts
index a1b3c9a..7567694 100644
--- a/src/lib/locales/de.ts
+++ b/src/lib/locales/de.ts
@@ -33,6 +33,8 @@ const de = {
'launcher.homework.terms': 'Aufgaben\nArbeitsauftrag',
'launcher.register': 'Registrieren',
'launcher.register.terms': 'Account',
+ 'launcher.profile': 'Dein Profil',
+ 'launcher.profile.terms': 'Profil\nDetails\nAccount\nNutzer',
'launcher.join': 'Einer Klasse beitreten',
'launcher.join.terms': 'Klasse\nbeitreten\nKurs\nGruppe\nhinzufügen',
'launcher.mod.own': 'Eigene Anfragen',
@@ -104,6 +106,7 @@ const de = {
'nav.footer.auth.login': 'Einloggen',
'nav.footer.auth.register': 'Registrieren',
'nav.footer.auth.join': 'Klasse beitreten',
+ 'nav.footer.auth.profile': 'Dein Profil',
'nav.footer.notes': 'Notizen',
'nav.footer.notes.notes': 'Notizen',
'nav.footer.calendar': 'Kalender',
@@ -683,12 +686,28 @@ Deine bisherigen Einstellungen sind leider nicht mit der neuen Version kompatibe
'keyboardshortcuts.markdown.bold': 'Fett',
'keyboardshortcuts.markdown.italic': 'Kursiv',
'keyboardshortcuts.markdown.link': 'Link',
- 'keyboardshortcuts.markdown.heading': 'Überscirft',
+ 'keyboardshortcuts.markdown.heading': 'Überschrift',
'markdownEditor.views.edit': 'Bearbeiten',
'markdownEditor.views.preview': 'Vorschau',
'markdownpreview.noPreview': 'Gebe etwas ein, um eine Vorschau sehen zu können.',
+ 'profile.logInRequired': 'Für diese Funktion musst du dich einloggen.',
+ 'profile.logInRequired.link': 'Klicke hier',
+ 'profile.title': 'Dein Profil',
+ 'profile.classes': 'Klassen',
+ 'profile.classes.count': {
+ counts: {
+ default: '$count Klassen',
+ 0: 'Keine Klassen',
+ 1: 'Eine Klasse',
+ 2: 'Two Klassen'
+ }
+ },
+ 'profile.registered': 'Am $date registriert',
+ 'profile.links.reqs': 'Deine Beitritts-Anfragen',
+ 'profile.links.settings': 'Deine Profil Einstellungen',
+
literal: '$literal'
} as const satisfies I18nDict;
diff --git a/src/lib/locales/en.ts b/src/lib/locales/en.ts
index 4ab2260..9860ecc 100644
--- a/src/lib/locales/en.ts
+++ b/src/lib/locales/en.ts
@@ -32,6 +32,8 @@ const en = {
'launcher.homework.terms': 'Task\nHomework',
'launcher.register': 'Register',
'launcher.register.terms': 'Account',
+ 'launcher.profile': 'Your Profile',
+ 'launcher.profile.terms': 'Profile\nDetails\nAccount',
'launcher.join': 'Join a class',
'launcher.join.terms': 'Class\nJoin\nCourse\nGroup\nAdd',
'launcher.mod.own': 'Own join requests',
@@ -101,6 +103,7 @@ const en = {
'nav.footer.auth.login': 'Login',
'nav.footer.auth.register': 'Register',
'nav.footer.auth.join': 'Join class',
+ 'nav.footer.auth.profile': 'Your Profile',
'nav.footer.notes': 'Notes',
'nav.footer.notes.notes': 'Notes',
'nav.footer.calendar': 'Calendar',
@@ -677,6 +680,22 @@ Your current settings sadly won't be compatible withthe new version. But you can
'markdownEditor.views.preview': 'Preview',
'markdownpreview.noPreview': 'To show a preview some input is required',
+ 'profile.logInRequired': 'For this function you first need to log in.',
+ 'profile.logInRequired.link': 'Click here',
+ 'profile.title': 'Your Profile',
+ 'profile.classes': 'Classes',
+ 'profile.classes.count': {
+ counts: {
+ default: '$count classes',
+ 0: 'No classes',
+ 1: 'One class',
+ 2: 'Two classes'
+ }
+ },
+ 'profile.registered': 'Registered on the $date',
+ 'profile.links.reqs': 'Your Join-Requests',
+ 'profile.links.settings': 'Your Profile Settings',
+
literal: '$literal'
} as const satisfies I18nDict;
diff --git a/src/lib/utils/url/query.test.ts b/src/lib/utils/url/query.test.ts
index 877db08..8841564 100644
--- a/src/lib/utils/url/query.test.ts
+++ b/src/lib/utils/url/query.test.ts
@@ -13,7 +13,7 @@ describe('object to query params', () => {
expect(objToQueryParams({ key: 'value', key2: 'value2' })).toBe('key=value&key2=value2');
expect(objToQueryParams({ key: 'value', key2: null })).toBe('key=value');
});
- it('converrts a Record>', () => {
+ it('converts a Record>', () => {
const obj = { key: { key: { key: { key: [4, 2.42, { key: { value: 'hi' } }] } } } };
expect(objToQueryParams({ key: obj, key2: 'value2' })).toBe(
diff --git a/src/routes/join/+page.svelte b/src/routes/join/+page.svelte
index 38facf0..55d5aa9 100644
--- a/src/routes/join/+page.svelte
+++ b/src/routes/join/+page.svelte
@@ -107,8 +107,8 @@
'Joined class successfully!': i('toast.join.joined')
}[res.message];
- ownUserInfo().then((d) => {
- svocal('dlool.ownUserDetails').set(d.data);
+ ownUserInfo().then(({ data }) => {
+ svocal('dlool.ownUserDetails').set(data);
});
sendToast({
diff --git a/src/routes/profile/+page.svelte b/src/routes/profile/+page.svelte
new file mode 100644
index 0000000..4ba7e2d
--- /dev/null
+++ b/src/routes/profile/+page.svelte
@@ -0,0 +1,120 @@
+
+
+
+
+{#if $userDetails && $isLoggedIn}
+ {@const ud = $userDetails}
+ {@const school = ud.classes.at(0)?.school.name}
+
+
+
+
+
+
+
+
+
{ud.displayname}
+
{ud.username}
+
+
+
+ {#if school}
+
+ {school}
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#each sortByPredicate(ud.classes, ({ name }) => name) as { name: className }}
+ {@const subject = smartSubject(className)}
+ {@const icon = safeMap(subject, getSubjectIcon)}
+ -
+ {#if icon}
+
+
+ {/if}
+ {className}
+
+ {:else}
+
+
+
+ {/each}
+
+
+
+{:else}
+
+
+
+
+{/if}