Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/splash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"algohub": patch:feat
---

Add splash screen before loading index page.
2 changes: 1 addition & 1 deletion src/components/MonacoEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const onSubmit = () => {
emit(
'submit',
rawEditor.value.getValue(),
language,
language.value,
(text: string, severity: Severity) => {
submitting.value = false
message.value = { text, severity }
Expand Down
88 changes: 88 additions & 0 deletions src/components/SplashScreen.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import * as api from "@/scripts/api";
import { useAccountStore } from '@/scripts/store';
import { useRouter } from 'vue-router';

const loading = defineModel<boolean>({ required: true })

const router = useRouter();

const texts = [
"Welcome to AlgoHub",
"Be true to your true self, not to your ego. Choose the normalcy, not human kind. \
Believe in civilization, not humanity."
]
const index = ref(0);
const status = ref("Loading...");
const onChange = () => {
index.value = (index.value + 1) % texts.length;
}
const accountStore = useAccountStore();

export interface LatestVersions {
nightly?: string;
stable?: string;
alpha?: string;
beta?: string;
rc?: string;
status: boolean;
}

onMounted(async () => {
status.value = "Checking for updates...";
try {
const { invoke } = (await import('@tauri-apps/api/core'));
const versions: LatestVersions = await invoke("get_latest_versions");
if (!versions.status) {
status.value = "Failed to get latest versions, skipping update check..."
} else {
if (versions.beta) {
status.value = `New beta version available: ${versions.beta}`;
} else {
status.value = `The latest alpha version is: ${versions.alpha}, no available updates.`
}
await new Promise(resolve => setTimeout(resolve, 3000));
}
} catch (e) {
console.error(e);
status.value = "Tauri API not found, skipping update check..."
await new Promise(resolve => setTimeout(resolve, 3000));
}
status.value = "Checking for login...";
if (accountStore.isLoggedIn) {
const res = await api.verifyToken(accountStore.auth);
if (!res.success) {
accountStore.logout();
status.value = "User credentials expired. Consider login again.";
await new Promise(resolve => setTimeout(resolve, 3000));
loading.value = false;
router.push('/login')
} else {
loading.value = false;
router.push('/dashboard')
}
}
loading.value = false;
})
</script>

<template>
<div @click="onChange" class="bg-gray-900 flex flex-col items-center justify-center h-full w-full">
<div class="flex flex-col items-center justify-center h-full w-full max-w-[700px] gap-[2em]">
<div class="flex flex-col items-center justify-center">
<img src="/acm-light.png" class="w-48" />
<div class=" text-white text-center font-bold text-4xl w-full">AlgoHub
</div>
</div>
<div class="flex flex-col gap-3 justify-center w-full px-20">
<div class="text-sm mb-5">{{ texts[index] }}</div>
<ProgressBar mode="indeterminate" class="w-full !h-[5px]"></ProgressBar>
<div class="text-gray-500 text-right font-bold text-sm">{{ status }}</div>
</div>
</div>
<div class="flex flex-col text-center w-full text-xs mb-10">
<span>Copyright © 2006-present ACM-SWPU. All rights reserved.</span>
</div>
</div>
</template>
37 changes: 36 additions & 1 deletion src/scripts/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import type {
Profile,
UserContent,
CreateProblem,
Language,
RecordId,
} from "./types";

export interface Response<D> {
Expand Down Expand Up @@ -79,6 +81,15 @@ export const login = async (form: Login) => {
}
};

export const verifyToken = async (auth?: Credentials) => {
try {
const response = await axios.post("/account/verify", auth);
return response.data as Response<Credentials>;
} catch (error) {
return handleAxiosError(AxiosError.from(error));
}
};

export const fetchProfile = async (id: string) => {
try {
const response = await axios.get(`/account/profile/${id}`);
Expand Down Expand Up @@ -131,10 +142,34 @@ interface SubmitCodeForm {
lang: string;
}

interface Id {
id: string;
}

export const submitCode = async (problem_id: string, form: SubmitCodeForm) => {
try {
const response = await axios.post(`/code/submit/${problem_id}`, form);
return response.data as Response<undefined>;
return response.data as Response<Id>;
} catch (error) {
return handleAxiosError(AxiosError.from(error));
}
};

interface Submission {
id: string;
lang: Language;
problem: RecordId;
code: string;
status: 'in_queue' | 'judging' | 'ready';
judge_details: { status: any, timeUsed: number, memoryUsed: number }[],
judge_result: { status: any, timeUsed: number, memoryUsed: number },
// contest
}

export const fetchSubmission = async (id: string, form?: Credentials) => {
try {
const response = await axios.post(`/code/get/${id}`, form);
return response.data as Response<Submission>;
} catch (error) {
return handleAxiosError(AxiosError.from(error));
}
Expand Down
14 changes: 6 additions & 8 deletions src/views/index.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
<script setup lang="ts">
import { useAccountStore } from '@/scripts/store';
import { ref } from 'vue';
import { useRouter } from 'vue-router';

const router = useRouter();
const accountStore = useAccountStore();

if (accountStore.isLoggedIn) {
router.push('/dashboard');
}
const loading = ref(true);
</script>

<template>
<div
<SplashScreen v-if="loading" v-model="loading" />
<div v-if="!loading"
class="fixed bottom-0 sm:bottom-unset w-full py-2 bg-indigo-600 text-white sm:flex sm:items-center sm:justify-between sm:px-6 lg:px-8">
<p class="text-center font-medium sm:text-left">
AlgoHub is on nightly build now! Want to try it out?
AlgoHub is on alpha now! Want to try it out?
<br class="sm:hidden" />
See the latest updates!
</p>
Expand All @@ -24,7 +22,7 @@ if (accountStore.isLoggedIn) {
Releases
</a>
</div>
<section class="bg-gray-900 text-white h-screen w-full">
<section v-if="!loading" class="bg-gray-900 text-white h-screen w-full">
<div class="mx-auto max-w-screen-xl px-4 py-32 lg:flex lg:h-screen lg:items-center">
<div class="mx-auto max-w-3xl text-center">
<h1
Expand Down
64 changes: 50 additions & 14 deletions src/views/problem/[id].vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { onMounted, onUnmounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import * as api from '@/scripts/api';
import { useAccountStore, useThemeStore } from '@/scripts/store';
Expand Down Expand Up @@ -33,7 +33,7 @@ const formatProblem = (problem: UserProblem) => {
}
hint && (formattedText += `## Hint\n\n${hint}\n\n`);

return formattedText;
return formattedText.repeat(10);
}

const code = ref('');
Expand All @@ -53,7 +53,12 @@ const onSubmit = async (code: string, lang: Language, finish: (text: string, sev
if (!res.success) {
return finish(res.message, 'error');
}
finish('Code submitted', 'success');
await new Promise(resolve => setTimeout(resolve, 2000));
const submission = await api.fetchSubmission(res.data!.id, accountStore.auth!);
if (!submission.success) {
return finish(submission.message, 'error');
}
finish(submission.data!.judge_result.status, 'success');
}

const path = ref<{ label?: string, link?: string }[]>([]);
Expand All @@ -74,24 +79,49 @@ onMounted(async () => {
]
loading.value = false;
})

const windowWidth = ref(window.innerWidth);
window.onresize = () => {
windowWidth.value = window.innerWidth;
}

onUnmounted(() => {
window.onresize = null;
})
</script>

<template>
<div class="flex flex-col h-full">
<UniversalToolBar :path></UniversalToolBar>
<Splitter :gutterSize="2" class="flex-1 overflow-hidden">
<Splitter :gutterSize="2" class="flex-1 overflow-hidden"
:layout="windowWidth > 768 ? 'horizontal' : 'vertical'">
<SplitterPanel>
<Panel class="w-full h-full overflow-auto" pt:header:class="!hidden">
<MdPreview v-if="!loading" class="!bg-transparent" :modelValue="formatProblem(problem!)"
:theme="themeStore.dark ? 'dark' : 'light'" codeTheme="github" previewTheme="github">
</MdPreview>
<div v-else class="flex flex-col gap-4 m-3">
<Skeleton height="2em" width="15vw"></Skeleton>
<Skeleton height="5em" width="40vw"></Skeleton>
<Skeleton height="2em" width="30vw"></Skeleton>
<Skeleton height="10em" width="40vw"></Skeleton>
<div class="flex flex-col gap-2 w-full h-full">
<div class="p-3 flex flex-wrap flex-row items-center justify-between w-full">
<Button size="small" icon="pi pi-arrow-left" plain outlined></Button>
<div class="inline-flex items-center gap-1">
<Button icon="pi pi-pencil" size="small" plain outlined></Button>
<Button size="small" severity="danger" icon="pi pi-trash" outlined></Button>
</div>
</div>
<div class="flex flex-row w-full h-full">
<div class="flex flex-col w-20 gap-4">
<Button pt:label:class="text-xs" label="Problem" icon="pi pi-code" size="small"
iconPos="top" plain text disabled></Button>
<Button pt:label:class="text-xs" label="Records" icon="pi pi-file" size="small"
iconPos="top" plain text disabled></Button>
</div>
<MdPreview v-if="!loading" class="!bg-transparent" :modelValue="formatProblem(problem!)"
:theme="themeStore.dark ? 'dark' : 'light'" codeTheme="github" previewTheme="github">
</MdPreview>
<div v-else class="flex flex-col gap-4 m-3">
<Skeleton height="2em" width="15vw"></Skeleton>
<Skeleton height="5em" width="40vw"></Skeleton>
<Skeleton height="2em" width="30vw"></Skeleton>
<Skeleton height="10em" width="40vw"></Skeleton>
</div>
</div>
</Panel>
</div>
</SplitterPanel>
<SplitterPanel>
<MonacoEditor :code="code" :language="language" :onSubmit>
Expand All @@ -100,3 +130,9 @@ onMounted(async () => {
</Splitter>
</div>
</template>

<style scoped>
:deep(.md-editor-preview-wrapper) {
padding: 0 1em 0 1em;
}
</style>
Loading