migrate web to svelte 5

This commit is contained in:
Rotimi Best
2025-12-25 05:37:21 +00:00
parent 50d6ee3111
commit 334c67f22a
63 changed files with 621 additions and 479 deletions
@@ -112,7 +112,7 @@
<div
class="lg:w-full max-w-7xl flex flex-col lg:items-center items-start lg:justify-center justify-start gap-y-4"
>
<h1 class="text-3xl md:text-5xl font-bold">Inspire Student Success</h1>
<h1 class="text-3xl">Inspire Student Success</h1>
<p class="text-[#334155] text-sm md:text-base font-light lg:text-center md:w-[80%]">
Scale your bootcamp with ClassroomIO's comprehensive toolkit. Create engaging content,
foster community, and drive student achievement.
@@ -132,7 +132,7 @@
/>
<div class="w-full flex flex-col justify-start align-start gap-y-2">
<h1 class="text-xl font-medium">{benefits.title}</h1>
<h1 class="text-md">{benefits.title}</h1>
{#each benefits.points as point}
<div class="flex flex-row justify-start items-start gap-x-3">
@@ -162,7 +162,7 @@
<div
class="w-full flex flex-col lg:items-center items-start lg:justify-center justify-start gap-y-4"
>
<h1 class="text-3xl md:text-5xl font-bold">Why We're the Perfect Fit</h1>
<h1 class="text-3xl">Why We're the Perfect Fit</h1>
<p class="text-[#334155] text-sm md:text-base font-light lg:text-center md:w-[80%]">
Discover why we’re the ideal partner for your bootcamp training needs. Experience
innovative solutions designed to elevate student engagement and maximize learning
@@ -187,7 +187,7 @@
alt="team icon"
/>
<div class="md:w-full flex flex-col items-start justify-start gap-y-4">
<h1 class="font-bold text-4xl">{feature.title}</h1>
<h1 class="text-2xl">{feature.title}</h1>
<p class="leading-8 text-lg text-gray-500">
{feature.description}
</p>
@@ -92,11 +92,11 @@
<div
class="w-full gap-y-4 flex flex-col lg:items-center items-start lg:justify-center justify-start"
>
<Badge class="py-2! px-4!" variant="outline">Our benefits</Badge>
<Badge class="py-1! px-4!" variant="outline">Our benefits</Badge>
<div
class="lg:w-full max-w-7xl flex flex-col lg:items-center items-start lg:justify-center justify-start gap-y-4"
>
<h1 class="text-3xl md:text-5xl font-bold">The customer education toolkit</h1>
<h1 class="text-3xl">The customer education toolkit</h1>
<p class="text-[#334155] text-sm md:text-base font-light lg:text-center md:w-[80%]">
Create beautiful, branded landing pages to showcase your courses and get customers up to
speed quickly
@@ -116,7 +116,7 @@
/>
<div class="w-full flex flex-col justify-start align-start gap-y-2">
<h1 class="text-xl font-medium">{benefits.title}</h1>
<p class="text-lg">{benefits.title}</p>
<div class="flex flex-row justify-start items-start gap-x-3">
<p class="leading-8 text-gray-500 font-[#656565] font-light">
@@ -136,14 +136,14 @@
class="w-full gap-y-4 flex flex-col lg:items-center items-start lg:justify-center justify-start"
>
<div class="w-fit py-2 px-4 rounded-full border-[#C2D2FF] border-2 text-center">
<p class=" text-sm md:text-base text-[#4B5563] text-center font-medium">
<p class="text-sm text-[#4B5563] text-center">
Explore our features
</p>
</div>
<div
class="lg:w-full max-w-7xl flex flex-col lg:items-center items-start lg:justify-center justify-start gap-y-4"
>
<h1 class="text-3xl md:text-5xl font-bold">Why Choose Us For Education Needs</h1>
<h1 class="text-3xl">Why Choose Us For Education Needs</h1>
<p class="text-[#334155] text-sm md:text-base font-light lg:text-center md:w-[80%]">
Discover how our innovative solutions can reduce stress, enhance productivity, and achieve
your training goals.
@@ -154,9 +154,9 @@
<div class="w-full max-w-7xl flex flex-col justify-start items-center lg:gap-y-24 gap-y-16">
{#each featureDetails as feature, i}
<div
class="w-full lg:w-[70%] flex lg:flex-row {i % 2 !== 0
class="w-full flex lg:flex-row {i % 2 !== 0
? 'lg:flex-row-reverse'
: ''} flex-col lg:justify-between justify-start lg:items-center items-start gap-10"
: ''} flex-col lg:justify-evenly justify-start lg:items-center items-start gap-10"
>
<div
class="w-full max-w-sm lg:w-[40%] lg:gap-y-6 gap-y-3 flex flex-col items-start justify-start"
@@ -166,7 +166,7 @@
alt="team icon"
/>
<div class="md:w-full flex flex-col items-start justify-start gap-y-4">
<h1 class="font-bold text-4xl">{feature.title}</h1>
<h1 class="text-2xl">{feature.title}</h1>
<p class="leading-8 text-lg text-gray-500">
{feature.description}
</p>
@@ -86,7 +86,7 @@
<Badge variant="outline">Amazing benefits</Badge>
<div class="md:w-full flex flex-col items-start justify-start gap-y-4">
<h1 class="font-bold text-4xl">Unlock your team's potential</h1>
<h1 class="text-3xl">Unlock your team's potential</h1>
<p class="leading-8 text-lg text-gray-500">
Modern teams require solutions that are easy to use and allows them move quickly.
</p>
@@ -106,8 +106,8 @@
/>
<div class="w-full flex flex-col justify-start align-start gap-y-2">
<h1 class="text-xl font-medium">{benefits.title}</h1>
<p class="leading-8 text-gray-500 font-[#656565] font-light">
<h1 class="text-lg">{benefits.title}</h1>
<p class="text-base leading-8 text-gray-500 font-[#656565] font-light">
{benefits.description}
</p>
</div>
@@ -127,7 +127,7 @@
<div
class="lg:w-full max-w-7xl flex flex-col lg:items-center items-start lg:justify-center justify-start gap-y-4"
>
<h1 class="text-3xl md:text-5xl font-bold">What makes us the right choice</h1>
<h1 class="text-3xl">What makes us the right choice</h1>
<p class="text-[#334155] text-sm md:text-base font-light lg:text-center md:w-[80%]">
Discover why we’re the perfect partner for your employee training needs. Experience
innovative solutions designed to reduce stress and enhance productivity.
@@ -151,7 +151,7 @@
alt="team icon"
/>
<div class="md:w-full flex flex-col items-start justify-start gap-y-4">
<h1 class="font-bold text-4xl">{feature.title}</h1>
<h1 class="text-2xl">{feature.title}</h1>
<p class="leading-8 text-lg text-gray-500">
{feature.description}
</p>
@@ -185,10 +185,10 @@
>
<div class="w-full lg:w-[40%] gap-y-4 flex flex-col items-start justify-start">
<div class="md:w-full flex flex-col items-start justify-start gap-y-4">
<h1 class="font-bold text-4xl text-white">
<h1 class="text-2xl text-white">
Did you know you can request for custom features?
</h1>
<p class="leading-8 text-[#DEDEDE] text-xl font-light">
<p class="leading-8 text-[#DEDEDE] text-base">
Companies get the opportunity to request custom features from us.
</p>
</div>
@@ -1,5 +1,8 @@
import { redirect } from '@sveltejs/kit';
export const load = async () => {
redirect(307, 'https://docs.google.com/presentation/d/1eqvNPNk167ZcP21gZGVAatdDpWAFL9lfmWJHHrzsVFc');
redirect(
307,
'https://docs.google.com/presentation/d/1eqvNPNk167ZcP21gZGVAatdDpWAFL9lfmWJHHrzsVFc'
);
};
@@ -7,8 +7,5 @@ export const load = async ({ request }) => {
event: 'privacy page visited'
});
redirect(
307,
'https://app.enzuzo.com/policies/privacy/958fc978-5477-11ee-a03b-7b111830c594'
);
redirect(307, 'https://app.enzuzo.com/policies/privacy/958fc978-5477-11ee-a03b-7b111830c594');
};
+3 -3
View File
@@ -9,7 +9,7 @@
import '../app.css';
export let data;
let { children, data } = $props();
onMount(() => {
if (dev) {
@@ -17,7 +17,7 @@
}
});
$: metaTags = extend(true, {}, data.baseMetaTags, page.data.pageMetaTags);
let metaTags = $derived(extend(true, {}, data.baseMetaTags, page.data.pageMetaTags));
</script>
<MetaTags {...metaTags} />
@@ -29,7 +29,7 @@
{#if page.status === 404}
<NotFound className="mt-5" />
{:else}
<slot />
{@render children?.()}
{/if}
</PageTransition>
+1 -1
View File
@@ -1,7 +1,7 @@
<script>
import { PageSignupCTA, PageHeader, BlogListItem } from '$lib/components';
export let data;
let { data } = $props();
</script>
<svelte:head>
@@ -6,7 +6,7 @@
import { BlogListItem } from '$lib/components';
export let data;
let { data } = $props();
</script>
<div class=" mt-[10%] md:mt-16">
@@ -28,7 +28,7 @@
<!-- Post -->
<div class="prose border-b-2 border-gray-200 pb-4 pt-2">
<svelte:component this={data.content} />
<data.content />
<!-- Tags -->
<div class="flex gap-2 py-4">
{#each data.meta.tags as tag}
+2 -2
View File
@@ -8,7 +8,7 @@
import { PageHeader } from '$lib/components';
import FeedbackForm from '$lib/features/contact/feedback-form.svelte';
let currentForm: FORM_TYPE_KEY;
let currentForm: FORM_TYPE_KEY = $state();
const formList = [
{
@@ -72,7 +72,7 @@
>
{#each formList as list}
<button
on:click={() => onChange(list.id, list.to)}
onclick={() => onChange(list.id, list.to)}
class="w-full rounded-md border-[1.5px] p-3 text-start {currentForm === list.id
? `border-[#0233BD]`
: `border-gray-200`} flex items-center justify-between"
@@ -2,7 +2,7 @@
import { PageHeader } from '$lib/components';
import { Button } from '@cio/ui/base/button';
export let data;
let { data } = $props();
</script>
<svelte:head>
+3 -3
View File
@@ -6,7 +6,7 @@
import { PageSignupCTA, PageHeader } from '$lib/components';
let isYearlyPlan = false;
let isYearlyPlan = $state(false);
function toggleIsYearlyPlan() {
isYearlyPlan = !isYearlyPlan;
@@ -32,14 +32,14 @@
? '#5e636b'
: '#fff'}"
class="rounded-[30px] bg-blue-700 px-3 py-1 text-xs text-white lg:px-4 lg:py-2"
on:click={toggleIsYearlyPlan}>Monthly</button
onclick={toggleIsYearlyPlan}>Monthly</button
>
<button
style="background-color: {isYearlyPlan ? '#1D4EE2' : ''}; color: {isYearlyPlan
? '#fff'
: '#5e636b'}"
class="rounded-[30px] px-3 py-1 text-xs text-white lg:px-4 lg:py-2"
on:click={toggleIsYearlyPlan}>Annually</button
onclick={toggleIsYearlyPlan}>Annually</button
>
<div
class="absolute right-[-40%] top-[-85%] scale-[90%] rounded-full bg-[#006600] px-3.5 py-1.5 text-xs text-white lg:right-[-43%] lg:top-[-75%] lg:scale-100"
+2 -2
View File
@@ -79,7 +79,7 @@
<img src="/roadmap-two.svg" alt="" class="hidden lg:block absolute top-0 left-0" />
<div class="flex flex-col items-start space-y-10 px-4">
<div>
<h1 class="text-3xl font-bold">Latest Features</h1>
<h1 class="text-3xl">Latest Features</h1>
</div>
<Timeline items={newFeatures} />
@@ -89,7 +89,7 @@
<section class="flex flex-col items-center w-full px-4 py-20 border-b-2">
<div class="flex flex-col items-start space-y-10 px-4">
<div>
<h1 class="text-3xl font-bold">Upcoming Features</h1>
<h1 class="text-3xl">Upcoming Features</h1>
</div>
<Timeline items={upcomingFeatures} />
+29 -37
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import { slide } from 'svelte/transition';
import { PageSignupCTA, PageHeader } from '$lib/components';
import { Button } from '@cio/ui/base/button';
import * as Accordion from '@cio/ui/base/accordion';
const whyStart = [
{
@@ -41,35 +41,31 @@
}
];
let faqs = [
const faqs = [
{
value: 'tutors',
question: 'What kind of tutors does ClassroomIO look for?',
answer:
'We are looking for all kinds of tutors. The most important thing is that you have some experience teaching and you have proven track record of excellent communication',
showAnswer: false
'We are looking for all kinds of tutors. The most important thing is that you have some experience teaching and you have proven track record of excellent communication'
},
{
value: 'equipment',
question: 'What equipment do I need to teach on ClassroomIO?',
answer: 'You just need internet access and a laptop.',
showAnswer: false
answer: 'You just need internet access and a laptop.'
},
{
value: 'apply',
question: 'What happens after I apply?',
answer:
'We will get your application and review it. You should get a response from us within 2-5 working days depending on the volume of applications',
showAnswer: false
'We will get your application and review it. You should get a response from us within 2-5 working days depending on the volume of applications'
},
{
value: 'earn',
question: 'How much can I earn?',
answer:
'That depends on how much your course sells for and how many students buy your course. Your income is limitless, you can keep making money while you sleep.',
showAnswer: false
'That depends on how much your course sells for and how many students buy your course. Your income is limitless, you can keep making money while you sleep.'
}
];
function toggleAnswer(index: number) {
faqs[index].showAnswer = !faqs[index].showAnswer;
}
</script>
<svelte:head>
@@ -88,7 +84,7 @@
<section>
<PageHeader className="flex items-center justify-evenly px-5 flex-wrap text-left">
<div>
<h1 class="text-5xl font-bold">Teach with us</h1>
<h1 class="text-3xl lg:text-5xl">Teach with us</h1>
<p class="my-5 text-center lg:w-[77%] lg:text-left">
With ClassroomIO, you can make side income while teaching the subject you love
</p>
@@ -108,7 +104,7 @@
<div class="mx-auto mt-10">
<div class="border-b border-slate-100 px-[10%] pb-10">
<h1 class="flex items-center justify-center gap-3 pb-28 text-center text-4xl font-bold">
<h1 class="flex items-center justify-center gap-3 pb-28 text-center text-3xl">
Why you should teach with us? <img src="/teach/star.svg" alt="" />
</h1>
@@ -119,7 +115,7 @@
>
<img src={why.src} alt="" class="h-[80px] w-[80px]" />
<figcaption>
<h1 class="text-base font-bold">{why.header}</h1>
<h1 class="text-base">{why.header}</h1>
<p class="mt-1 text-sm">
{why.subText}
</p>
@@ -130,14 +126,14 @@
</div>
<div class="mt-10 px-[10%] py-10">
<h1 class="mb-28 flex items-center justify-center gap-3 text-center text-4xl font-bold">
<h1 class="mb-28 flex items-center justify-center gap-3 text-center text-3xl">
How to get started <img src="/teach/thumbs-up.svg" alt="" />
</h1>
<div class="mx-auto mt-5 flex flex-wrap justify-between gap-y-10">
{#each steps as step, i}
<div class="px-10 py-5 lg:max-w-[40%]">
<h1 class="text-2xl font-bold">
<h1 class="text-2xl">
<span class="mr-3 rounded-md bg-[#F7F7F7] px-2 py-1">{i + 1}</span>
{step.title}
</h1>
@@ -159,7 +155,7 @@
</div>
<div class="my-10 h-[75%] bg-[#F5F8FE] px-2 py-12 lg:h-[80%] lg:px-[12%]">
<h1 class="flex items-center justify-center gap-3 text-center text-2xl font-bold">
<h1 class="flex items-center justify-center gap-3 text-center text-2xl">
Word from our fufilled facilitators
</h1>
@@ -180,25 +176,21 @@
</div>
<div class="mx-auto my-10 mt-10 px-10 lg:max-w-[65%] lg:px-[15%]">
<h1 class="text-center text-2xl font-bold">Frequently asked questions</h1>
<h1 class="text-center text-xl">Frequently asked questions</h1>
<div class="mt-10">
{#each faqs as faq, index}
<div class="border-b border-black pb-2 pt-1 lg:px-3">
<div>
<button
type="button"
class="my-2 flex w-full justify-between text-left text-sm font-medium md:text-center md:text-lg"
on:click={() => toggleAnswer(index)}
>
{faq.question} <span>{faq.showAnswer ? '-' : '+'}</span>
</button>
</div>
{#if faq.showAnswer}
<div transition:slide class="text-base font-light leading-5">{faq.answer}</div>
{/if}
</div>
{/each}
<Accordion.Root type="single" class="w-full">
{#each faqs as faq}
<Accordion.Item value={faq.value}>
<Accordion.Trigger class="text-left md:text-center">
{faq.question}
</Accordion.Trigger>
<Accordion.Content>
{faq.answer}
</Accordion.Content>
</Accordion.Item>
{/each}
</Accordion.Root>
</div>
</div>
+8 -1
View File
@@ -1,5 +1,12 @@
<script>
import { PageSignupCTA } from '$lib/components';
/**
* @typedef {Object} Props
* @property {import('svelte').Snippet} [children]
*/
/** @type {Props} */
let { children } = $props();
</script>
<svelte:head>
@@ -29,7 +36,7 @@
<meta name="twitter:image" content="https://brand.cdn.clsrio.com/og/free-tools.png" />
</svelte:head>
<slot />
{@render children?.()}
<PageSignupCTA
header="Scale Your Bootcamp Today with ClassroomIO"
+3 -3
View File
@@ -9,7 +9,7 @@
<PageHeader>
<!-- added bg-white to keep the background white on devices that are on darkmode -->
<div class="bg-white text-left md:text-center md:w-2/4 px-7 md:p-0 mx-auto">
<h1 class="text-5xl md:text-6xl font-bold">
<h1 class="text-3xl md:text-5xl">
Explore our free <span class="text-blue-700">tools</span>
</h1>
<p class="my-4 md:my-8">
@@ -58,7 +58,7 @@
</PageHeader>
<div class="p-10 px-2 md:px-0 bg-white">
<h1 class="text-center font-bold text-3xl">Featured Tools</h1>
<h1 class="text-center text-2xl">Featured Tools</h1>
<div class="flex justify-evenly gap-y-8 flex-wrap w-full md:w-[70%] mt-10 mx-auto bg-white">
{#each freeTools as tool}
@@ -68,7 +68,7 @@
>
<img class="w-[30%] rounded-l-md" src={tool.src} alt="" />
<div class="bg-[#F5F8FE] p-5 rounded-r-md w-[70%]">
<h1 class="font-bold text-sm md:text-base">{tool.title}</h1>
<h1 class="text-sm md:text-base">{tool.title}</h1>
<p class="text-xs text-gray-600 mt-1.5">
{tool.subText}
</p>
@@ -1,12 +1,14 @@
<script lang="ts">
import { run } from 'svelte/legacy';
import { ToolsHeader } from '$lib/components';
let namesInput = '';
let numNames = 0;
let wordCount = 0;
let selectedNames: string[] = [];
let avatarUrls: string[] = [];
let avatarUrlsFetched = false;
let namesInput = $state('');
let numNames = $state(0);
let wordCount = $state(0);
let selectedNames: string[] = $state([]);
let avatarUrls: string[] = $state([]);
let avatarUrlsFetched = $state(false);
// function to shuffle an array
const shuffleArray = (array: string[]) => {
@@ -98,7 +100,9 @@
}
}
$: wordCount = namesInput?.split(',').filter((name) => name.trim())?.length ?? 0;
run(() => {
wordCount = namesInput?.split(',').filter((name) => name.trim())?.length ?? 0;
});
</script>
<svelte:head>
@@ -123,7 +127,7 @@
<section class="bg-white px-5 md:px-0">
<ToolsHeader>
<img src="/free-tools/name-picker.svg" class="mx-auto w-[15%] rounded-full border md:w-[5%]" alt="" />
<h1 class="my-3 text-4xl font-bold text-[#040F2D] md:text-6xl">Random Name Picker</h1>
<h1 class="my-3 text-3xl text-[#040F2D] md:text-5xl">Random Name Picker</h1>
<p class="text-md mx-auto font-light text-[#656565] md:w-[45%] md:font-normal">
Use this online name picker to draw a random name from a list of names, or to draw several names randomly out of a
list. You can use it as a name randomizer for a class activities.
@@ -132,24 +136,24 @@
<div class="mx-auto my-10 rounded-md border bg-white py-8 shadow-md md:w-[60%] md:py-[3%]">
<div class="mx-auto w-[85%] bg-white md:w-[70%]">
<h1 class="text-sm font-bold">List of names</h1>
<h1 class="text-sm">List of names</h1>
<!-- container -->
<div
class="relative mt-5 h-[12rem] overflow-hidden rounded-sm border-2 bg-[#F1F2F4] pl-3 pt-2 focus-within:border-[#0233BD]"
class="relative mt-5 h-48 overflow-hidden rounded-sm border-2 bg-[#F1F2F4] pl-3 pt-2 focus-within:border-[#0233BD]"
>
<!-- sidebar -->
<div class="absolute right-2 top-3 flex flex-col gap-y-3 md:right-7">
<button
type="button"
on:click={sortRandom}
onclick={sortRandom}
class="flex items-center justify-center rounded-full bg-[#D9E0F5] p-1.5"
>
<img src="/sort-icon.svg" class="w-2.5" alt="" />
</button>
<button
type="button"
on:click={unsortRandom}
onclick={unsortRandom}
class="flex items-center justify-center rounded-full bg-[#D9E0F5] p-1.5"
>
<img src="/unsort-icon.svg" class="w-2.5" alt="" />
@@ -175,7 +179,7 @@
<p class="border-b py-4 text-xs">Each name must be separated by a comma</p>
<div class="mt-10">
<h1 class="text-sm font-bold">Number of Names</h1>
<h1 class="text-sm">Number of Names</h1>
<!-- number input & button -->
<div class="mt-5 flex w-full flex-wrap justify-between gap-y-3">
<input
@@ -185,7 +189,7 @@
/>
<button
type="button"
on:click={selectName}
onclick={selectName}
class="w-[70%] rounded-md bg-[#0F62FE] py-3 text-sm text-white md:w-[35%] md:py-0"
>Select name(s) at random</button
>
@@ -196,7 +200,7 @@
<div class="mb-5 mt-10 flex items-center justify-center gap-3 bg-[#F1F6FF] py-3">
<img src="/free-tools/name-picker.svg" class="w-[12%] md:w-[9%]" alt="" />
{#if selectedNames.length > 0}
<h1 class="text-xl font-bold text-[#0233BD]">Selected Names</h1>
<h1 class="text-xl text-[#0233BD]">Selected Names</h1>
{/if}
</div>
@@ -226,12 +230,12 @@
<div class="mt-3 flex flex-wrap items-center justify-between md:justify-center md:gap-3">
<button
type="button"
on:click={resetEntry}
onclick={resetEntry}
class="w-[45%] rounded-md border py-2 text-xs md:w-[20%] md:text-sm">Reset Entries</button
>
<button
type="button"
on:click={selectName}
onclick={selectName}
class="w-[45%] rounded-md bg-[#0F62FE] py-2 text-xs text-white md:w-[27%] md:text-sm"
>Select other names</button
>
@@ -1,4 +1,6 @@
<script lang="ts">
import { preventDefault } from 'svelte/legacy';
import { onMount } from 'svelte';
import { ToolsHeader } from '$lib/components';
@@ -12,15 +14,15 @@
isVisible: boolean;
}
let addInput: HTMLInputElement;
let addInput: HTMLInputElement = $state();
let buzzSound: HTMLAudioElement;
let todoList: TodoItem[] = [];
let todoList: TodoItem[] = $state([]);
let countdownTime: number = 25 * 60;
let countdownDisplay: string = '25:00';
let timerState: string = 'pomodoro';
let countdownDisplay: string = $state('25:00');
let timerState: string = $state('pomodoro');
let isPaused: boolean = true;
let isPaused: boolean = $state(true);
let timerInterval: any = null;
let isVisible: boolean = false;
@@ -174,7 +176,7 @@
class="mx-auto w-[15%] rounded-full border md:w-[5%]"
alt=""
/>
<h1 class="my-3 text-4xl font-bold text-[#040F2D] md:text-6xl">Pomodoro Timer</h1>
<h1 class="my-3 text-3xl text-[#040F2D] md:text-5xl">Pomodoro Timer</h1>
<p class="mx-auto mt-10 text-sm font-light text-[#656565] md:w-[45%] md:font-normal">
Make your workday more engaging and effective with the Pomodoro timer, break work into
25-minute focused intervals called "pomodoros," followed by 5-minute breaks. take a longer
@@ -193,7 +195,7 @@
<div class="item-center flex justify-evenly">
<button
type="button"
on:click={() => setTimerState('pomodoro')}
onclick={() => setTimerState('pomodoro')}
class:bg-[#3ADFECED]={timerState === 'pomodoro'}
class:bg-[#0233BD]={timerState !== 'pomodoro'}
class="w-[25%] rounded-md py-1.5 text-xs italic transition-all duration-500 hover:bg-[#3ADFECED] md:py-2 md:text-sm md:font-medium"
@@ -201,7 +203,7 @@
>
<button
type="button"
on:click={() => setTimerState('long-break')}
onclick={() => setTimerState('long-break')}
class:bg-[#3ADFECED]={timerState === 'long-break'}
class:bg-[#0233BD]={timerState !== 'long-break'}
class="w-[25%] rounded-md py-1.5 text-xs italic transition-all duration-500 hover:bg-[#3ADFECED] md:py-2 md:text-sm md:font-medium"
@@ -209,7 +211,7 @@
</button>
<button
type="button"
on:click={() => setTimerState('short-break')}
onclick={() => setTimerState('short-break')}
class:bg-[#3ADFECED]={timerState === 'short-break'}
class:bg-[#0233BD]={timerState !== 'short-break'}
class="w-[25%] rounded-md py-1.5 text-xs italic transition-all duration-500 hover:bg-[#3ADFECED] md:py-2 md:text-sm md:font-medium"
@@ -223,7 +225,7 @@
<!-- controls -->
<div class="flex items-center justify-center gap-7">
<!-- reset -->
<button type="button" on:click={resetCountdown}>
<button type="button" onclick={resetCountdown}>
<img
src="/free-tools/pomodoro/restart-icon.svg"
alt="Restart Icon"
@@ -234,14 +236,14 @@
<!-- start (i intentionally disabled this button once the user clicks start so they can use the pause button to actually pause the countdown) -->
<button
type="button"
on:click={isPaused ? startCountdown : pauseCountdown}
class="rounded-md border bg-white px-14 py-3 text-base font-bold uppercase text-[#0542CC] transition-all duration-300 hover:border hover:border-white hover:bg-transparent hover:text-white"
onclick={isPaused ? startCountdown : pauseCountdown}
class="rounded-md border bg-white px-14 py-3 text-base uppercase text-[#0542CC] transition-all duration-300 hover:border hover:border-white hover:bg-transparent hover:text-white"
>
{isPaused ? 'Start' : 'Pause'}
</button>
<!-- next -->
<button type="button" on:click={nextTimerState}>
<button type="button" onclick={nextTimerState}>
<img
src="/free-tools/pomodoro/timer-play-icon.svg"
alt="Play Icon"
@@ -266,7 +268,7 @@
{#each todoList as todo, i}
<div class="border p-5 text-black">
{#if todo.isEditing}
<form on:submit|preventDefault={() => setEditing(i, false)}>
<form onsubmit={preventDefault(() => setEditing(i, false))}>
<p class="text-left text-xs font-semibold text-[#656565]">Pomodoro name</p>
<input
type="text"
@@ -277,7 +279,7 @@
<div class="mt-5 flex items-center justify-end gap-5">
<button
type="button"
on:click={() => deleteTodo(i)}
onclick={() => deleteTodo(i)}
class="rounded-sm bg-[#F7F7F7] px-5 py-2 text-xs font-semibold"
>Discard</button
>
@@ -295,11 +297,11 @@
<!-- pen and menu icon -->
<div class="relative flex w-[15%] justify-between">
<button type="button" on:click={() => setEditing(i, true)}>
<button type="button" onclick={() => setEditing(i, true)}>
<img src="/free-tools/pomodoro/pen-icon.svg" alt="Pen icon" class="w-5" />
</button>
<button type="button" on:click={() => (todo.isVisible = !todo.isVisible)}>
<button type="button" onclick={() => (todo.isVisible = !todo.isVisible)}>
<img src="/free-tools/pomodoro/menu-icon.svg" alt="Menu icon" class="w-5" />
</button>
@@ -309,14 +311,14 @@
>
<button
type="button"
on:click={() => markTodoAsDone(i)}
onclick={() => markTodoAsDone(i)}
class="w-full px-5 py-3 text-left font-medium"
>
Mark as done
</button>
<button
type="button"
on:click={() => deleteTodo(i)}
onclick={() => deleteTodo(i)}
class="w-full rounded-b-[5px] bg-red-600 px-5 py-3 text-left font-medium text-white"
>
Delete
@@ -335,7 +337,7 @@
<button
type="button"
on:click={() => {
onclick={() => {
if (todo.isPaused) {
startCountdown();
} else {
@@ -373,7 +375,7 @@
<!-- todo button -->
<button
type="button"
on:click={addTodo}
onclick={addTodo}
class="mt-10 flex w-full items-center justify-center gap-3 rounded-md bg-[#1D4ED8] py-3 text-center font-medium"
>
Add new item
@@ -16,11 +16,11 @@
import DownloadButton from '$lib/features/tools/progress/download-button.svelte';
const MAX_CHARS = 160;
let remainingChars = MAX_CHARS;
let showReport: boolean = false;
let showSetter: boolean = true;
let remainingChars = $state(MAX_CHARS);
let showReport: boolean = $state(false);
let showSetter: boolean = $state(true);
let isDownloading: boolean = false;
let isDisabled: boolean;
let isDisabled: boolean = $state();
// sets the result of the mini validation for the htmlBody store
const unsubscribe = isFormComplete.subscribe((value) => {
@@ -88,7 +88,7 @@
<section class=" w-full px-1 md:w-full md:px-0">
<ToolsHeader>
<img src="/free-tools/progress-report.svg" class="mx-auto w-[15%] rounded-full border md:w-[5%]" alt="" />
<h1 class="my-3 text-4xl font-bold text-[#040F2D] md:text-6xl">Progress Report</h1>
<h1 class="my-3 text-3xl text-[#040F2D] md:text-5xl">Progress Report</h1>
<p class="text-md mx-auto font-light text-[#656565] md:w-[45%] md:font-normal">
Generate cool reports of your learning progress. Share reports with your network for collaborative learning
</p>
@@ -113,7 +113,7 @@
<div class="mb-5 flex justify-end md:hidden">
<button
type="button"
on:click={() => {
onclick={() => {
showSetter = false;
showReport = true;
}}
@@ -130,7 +130,7 @@
<input
type="text"
bind:value={$htmlBody.name}
on:input={(event) => handleInputChange(event, 'name')}
oninput={(event) => handleInputChange(event, 'name')}
placeholder="Enter your name here"
class="my-3 w-full rounded-sm border bg-[#F1F2F4] px-3 py-2 text-xs outline-none placeholder:text-sm placeholder:text-[#ADADAD]"
/>
@@ -141,7 +141,7 @@
<p class="text-sm text-[#656565]">Select your mood</p>
<button
type="button"
on:click={() => ($openModal.mood = true)}
onclick={() => ($openModal.mood = true)}
class="my-3 flex w-full items-center justify-between rounded-sm border bg-[#F1F2F4] px-3 py-2 text-sm text-gray-400 outline-none"
>
{#if $htmlBody.mood.text}
@@ -172,7 +172,7 @@
<textarea
bind:value={$htmlBody.learning}
maxlength={MAX_CHARS}
on:input={(event) => handleInputChange(event, 'learning')}
oninput={(event) => handleInputChange(event, 'learning')}
placeholder="Tell us what you are learning"
class="my-3 h-[17vh] w-full rounded-sm border bg-[#F1F2F4] px-3 py-2 text-sm outline-none placeholder:text-sm placeholder:text-[#ADADAD]"
></textarea>
@@ -189,7 +189,7 @@
max="100"
bind:value={$htmlBody.progress}
class="range-input"
on:input={(event) => handleInputChange(event, 'progress')}
oninput={(event) => handleInputChange(event, 'progress')}
style="background: linear-gradient(to right, #0F62FE {$htmlBody.progress}%, #ccc {$htmlBody.progress}%);"
/>
<p class="text-sm font-semibold">{$htmlBody.progress}%</p>
@@ -202,7 +202,7 @@
<p class="text-[12px] text-[#656565] md:text-sm">Choose your avatar</p>
<button
type="button"
on:click={() => ($openModal.avatar = true)}
onclick={() => ($openModal.avatar = true)}
class="mt-3 flex w-full items-center justify-between gap-2 bg-[#F7F7F7] px-5 py-1.5 md:w-[65%] md:justify-center md:px-0"
>
<img
@@ -223,7 +223,7 @@
<p class="text-[12px] text-[#656565] md:text-sm">Choose your background</p>
<button
type="button"
on:click={() => ($openModal.background = true)}
onclick={() => ($openModal.background = true)}
class="mt-3 flex w-full items-center justify-between gap-2 bg-[#F7F7F7] px-5 py-1.5 md:w-[65%] md:justify-center md:px-0"
>
<img
@@ -265,19 +265,19 @@
<div class="mx-auto mt-2 flex w-[60%] justify-evenly gap-5 rounded-xl border px-5 py-2 md:w-[80%]">
<button
type="button"
on:click={shareOnFacebook}
onclick={shareOnFacebook}
class="w-10 transition-all duration-300 hover:scale-[1.2]"
>
<Facebook size={32} />
</button>
<button
type="button"
on:click={shareOnLinkedIn}
onclick={shareOnLinkedIn}
class="w-10 transition-all duration-300 hover:scale-[1.2]"
>
<Linkedin size={32} />
</button>
<button type="button" on:click={shareOnTwitter} class="w-5 transition-all duration-300 hover:scale-[1.2]">
<button type="button" onclick={shareOnTwitter} class="w-5 transition-all duration-300 hover:scale-[1.2]">
<img src="/twitter_logo.png" alt="X.com" />
</button>
</div>
@@ -290,7 +290,7 @@
<div class="mb-5 flex justify-end">
<button
type="button"
on:click={() => {
onclick={() => {
showReport = false;
showSetter = true;
}}
@@ -313,19 +313,19 @@
<div class="mx-auto mt-2 flex w-[60%] justify-evenly gap-5 rounded-xl border px-5 py-2 md:w-[80%]">
<button
type="button"
on:click={shareOnFacebook}
onclick={shareOnFacebook}
class="w-10 transition-all duration-300 hover:scale-[1.2]"
>
<Facebook size={32} />
</button>
<button
type="button"
on:click={shareOnLinkedIn}
onclick={shareOnLinkedIn}
class="w-10 transition-all duration-300 hover:scale-[1.2]"
>
<Linkedin size={32} />
</button>
<button type="button" on:click={shareOnTwitter} class="w-5 transition-all duration-300 hover:scale-[1.2]">
<button type="button" onclick={shareOnTwitter} class="w-5 transition-all duration-300 hover:scale-[1.2]">
<img src="/twitter_logo.png" alt="X.com" />
</button>
</div>
@@ -1,4 +1,6 @@
<script lang="ts">
import { preventDefault } from 'svelte/legacy';
import { onMount } from 'svelte';
import { fly } from 'svelte/transition';
import { sineInOut } from 'svelte/easing';
@@ -7,18 +9,18 @@
let timer: NodeJS.Timeout;
let buzzSound: HTMLAudioElement;
let isNextStep: boolean = false;
let isPaused: boolean = false;
let soundOn: boolean = true;
let isNextStep: boolean = $state(false);
let isPaused: boolean = $state(false);
let soundOn: boolean = $state(true);
let hours: number = 0;
let minutes: number = 0;
let seconds: number = 0;
let hours: number = $state(0);
let minutes: number = $state(0);
let seconds: number = $state(0);
let activityName: string = '';
let displayTime: string = '00:00:00';
let activityName: string = $state('');
let displayTime: string = $state('00:00:00');
let totalSeconds: number = 0;
let formattedTime: string = '00:00';
let formattedTime: string = $state('00:00');
export function toggleTimer() {
if (isPaused) {
@@ -146,7 +148,7 @@
<!-- countdown setter -->
{#if !isNextStep}
<div transition:fly={{ y: -300, delay: 0, easing: sineInOut }} class="bg-white px-6 py-8">
<form on:submit|preventDefault={startTimer}>
<form onsubmit={preventDefault(startTimer)}>
<div>
<h1 class="text-sm font-bold">Name of activity</h1>
<input
@@ -6,10 +6,10 @@
import { scores, changeToComputer } from '$lib/features/tools/tic-tac-toe/store';
import { ToolsHeader } from '$lib/components';
let startGame = false;
let message: string | null = null;
let winner: Winner | null = null;
let game = createGame();
let startGame = $state(false);
let message: string | null = $state(null);
let winner: Winner | null = $state(null);
let game = $state(createGame());
interface Winner {
symbol?: string;
@@ -114,7 +114,7 @@
class="absolute top-[43%] z-[150] flex w-full flex-col items-center justify-center"
>
<div
class="flex h-[8vh] w-full items-center justify-center gap-10 bg-white py-1 font-bold text-[#0233BD] md:h-[13vh]"
class="flex h-[8vh] w-full items-center justify-center gap-10 bg-white py-1 text-[#0233BD] md:h-[13vh]"
>
{#if message != 'Tie game!'}
<img src="/free-tools/tic-tac/winner-star-icon.svg" alt="Star icon" class="h-full" />
@@ -124,8 +124,8 @@
<button
type="button"
on:click={playAgain}
class="mt-10 rounded-md border border-white bg-[#0F62FE] px-16 pb-1.5 pt-1 text-xs font-bold md:text-base"
onclick={playAgain}
class="mt-10 rounded-md border border-white bg-[#0F62FE] px-16 pb-1.5 pt-1 text-xs md:text-base"
>Play Again</button
>
</div>
@@ -136,7 +136,7 @@
<div class="flex h-full w-full flex-col items-center justify-between border p-5">
<header class="flex w-full items-center justify-between">
<button
on:click={changePlayer}
onclick={changePlayer}
class="flex w-[35%] flex-row items-center gap-2 text-[10px] font-medium leading-3 md:w-28 md:text-xs"
>
<img src="/free-tools/tic-tac/computer-icon.svg" alt="Computer icon" class="w-4 md:w-6" />
@@ -147,7 +147,7 @@
{/if}
</button>
<button
on:click={newGame}
onclick={newGame}
class="flex w-24 flex-col items-center gap-1 rounded-md border bg-white p-2 text-[10px] font-medium leading-3 text-[#0542CC] shadow-md"
>
<img src="/free-tools/tic-tac/restart-icon.svg" alt="Restart icon" class="w-3 md:w-4" />
@@ -182,7 +182,7 @@
<div class="flex flex-col gap-3">
<button
type="button"
on:click={() => {
onclick={() => {
changePlayer();
startTicTac();
}}
@@ -192,7 +192,7 @@
>
<button
type="button"
on:click={() => {
onclick={() => {
startTicTac();
}}
class="rounded-md border border-white bg-[#0F62FE] px-16 pb-1.5 pt-1 text-sm font-bold"
+7 -2
View File
@@ -1,11 +1,16 @@
<script lang="ts">
import { fade } from 'svelte/transition';
export let url: string;
interface Props {
url: string;
children?: import('svelte').Snippet;
}
let { url, children }: Props = $props();
</script>
{#key url}
<div class="transition" in:fade>
<slot />
{@render children?.()}
</div>
{/key}