feat: [lw] free tools (#297)
* checkpoint * checkpoint * feat: Create free tools page * responsiveness fix * rename free-tools to tools * add slug * feat: Random name picker * quick fix * PR Fixes * PR Fixes * - adjustments * update env example * remove base url * remove base url in .env.example * fix type errors * add og images * add signup cta to /tools layout * update cta * add socials avatar * add meta tags * feat: tic tac toe (#307) * Feat: tic tac toe * PR Adjustments * feat: Implement Timed Activity Tool (#316) * chore: update verification email content * chore: landing page improvements * feat: grade exercise with AI (#296) * working on the UI of the grading * working on the grading function of the radio and checkboxes * ai grading fully implemented with dummy functions for generating scores * working on the openai response * working on the openai response * finished with the ai_grading * finished with the ai_grading * creating new migration file * working on reviews * updated the translations * improvements --------- Co-authored-by: Rotimi Best <[email protected]> * feat: selfhost tinymce * fix: logo resolution error in manifest.json * feat: move from gpt3.5 to gpt-4o * feat: customize the LMS from dashboard (#304) * Done with the customization of the LMS task * generated custom_lms migration file * updated the migration file * copy improvements * update wording * made updates based on reviews,i hope i didnt miss anything * updated the translations and migration files * refactoring * disabled improvements for apps * more improvements * more custom improvements * pr refactoring --------- Co-authored-by: Rotimi Best <[email protected]> * fix: CustomizeLMS not found * fix: CustomizeLms wrong path * setup * docs: update short hero tagline * debug: courses not showing on vercel * more debugging * i think this fixes it * fix: phew, clean up debug cause it works * fix: move RBS into coursecontainer on marks page * chore: cleaner way to implement redirect if role permission denied * docs: update tagline * fix: delete /org/# route * checkpoint * add reusable header component * fix: empty lesson title bug (#314) * finished the lesson title bug * made chnages based on review * Update +page.svelte --------- Co-authored-by: Rotimi Best <[email protected]> * feat: add sound cdn * remove console.log * feat: course types - self paced and live class (#309) * working on the course type * trying to mark it persist * almost done here * fixed sendig emtpy options bug * created migration file * created migration file * made updates based on PR review * merge * update course type card * add redirect logic with classroomio.com/new * make new course modal only open/close with url * feat: page active state (#315) * finished the active link state * updated the active link state based on review * simplify code --------- Co-authored-by: Rotimi Best <[email protected]> * add type to course card --------- Co-authored-by: Rotimi Best <[email protected]> * general improvements to free tools * fix timer and styling issues --------- Co-authored-by: Rotimi Best <[email protected]> Co-authored-by: Em_Dev <[email protected]> * update tagline for tools page * feat: Add Free Section to Landing Page (#332) * feat: Add Free Section to Landing Page * PR Fixes * refactor * PR Fixes * restructure * improve cursor UX --------- Co-authored-by: Rotimi Best <[email protected]> * feat: Progress Report Tool (#329) * checkpoint * fix: corrections * finalization * improve ux of progress tool * more styling improvements * PR Fixes * PR Fixes * fix: mood bg on report * fix: generate exercise with AI bug (#331) * fix: enable lesson cascade delete (#335) * styling improvements * chore: hide course grading toggle in settings (#338) * feat: reset select in community page (#339) * Feat: Add Reset for comminity dropdown * - add translation * refactor --------- Co-authored-by: Rotimi Best <[email protected]> * fix: prevent hypen at start or end of organzation or domain name (#340) * fix: adding hypen to start or end of org or domain name * fix: add org name validation to settings page * chore: remove unnecessary variable use * chore: remove error reset function * Update OrgSettings.svelte --------- Co-authored-by: Rotimi Best <[email protected]> * fix: full screen * fix: pnpm version error & add top level .nvmrc (#343) * update name of tool * chore: add translations for validation messages (#345) * chore: add validation texts to locale file * feat: switch all validations from plain text to use i18n locale * feat: switch review form validations from plain text to use locale file * run translation script * chore: add translations for validation messages (#345) (#347) * chore: add translations for validation messages (#345) * chore: add validation texts to locale file * feat: switch all validations from plain text to use i18n locale * feat: switch review form validations from plain text to use locale file * run translation script --------- Co-authored-by: Iniubong Obonguko <[email protected]> * PR Fixes * Bug fixes on mobile * Final bug fix * code improvements * PR Fixes * Merge Fix * PR Fixes * fix: width * code cleanup * feat: Promodo Tool (tracks tim spent) * feat: Pomodoro timer (without tracking feature) * fix: - change pause functionality to next - correct spelling of pomodoro * fix: pomodoro logo rename * styling improvements --------- Co-authored-by: Rotimi Best <[email protected]> Co-authored-by: Em_Dev <[email protected]> Co-authored-by: Iniubong Obonguko <[email protected]> Co-authored-by: Iniubong Obonguko <[email protected]> Co-authored-by: Aditya Deshlahre <[email protected]> * feat: Implement Bottom menu (#341) * popup logic done * popup UI first phase done * finished the menupop up for both lms and admin * finished the menupop up for both lms and admin * done * cleanup * fixed popover position * still working on the routing * i think that is it for the day * updated the menupopup currentorgdomain * rename popup to bottomMenu * refactoring --------- Co-authored-by: Rotimi Best <[email protected]> * remove logout * change tagline * feat: Store todolist to localStorage (#375) * feat: Save todo to localStorage * remove fly animation to todos * feat: Progress Report avatar update (#376) * feat: Reorder Avatar list * quick fix * change avatar url * more improvements * quick background fix * fix: white background * body background fix * update lock --------- Co-authored-by: Rotimi Best <[email protected]> Co-authored-by: Em_Dev <[email protected]> Co-authored-by: Iniubong Obonguko <[email protected]> Co-authored-by: Iniubong Obonguko <[email protected]> Co-authored-by: Aditya Deshlahre <[email protected]>
@@ -17,7 +17,7 @@
|
||||
"carbon-icons-svelte": "^12.3.0",
|
||||
"mdsvex": "^0.11.0",
|
||||
"postcss": "^8.4.29",
|
||||
"svelte": "^4.0.5",
|
||||
"svelte": "^4.1.2",
|
||||
"svelte-check": "^3.4.3",
|
||||
"svelte-sequential-preprocessor": "^2.0.1",
|
||||
"tailwindcss": "^3.3.3",
|
||||
@@ -26,6 +26,7 @@
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"html-to-image": "^1.11.11",
|
||||
"just-extend": "^6.2.0",
|
||||
"posthog-node": "^3.1.3",
|
||||
"rehype-slug": "^6.0.0",
|
||||
|
||||
@@ -106,6 +106,14 @@ li {
|
||||
background-image: url('/hero-bg.svg');
|
||||
}
|
||||
|
||||
.tools-hero-bg {
|
||||
background-image: url('/tools-hero-bg.svg');
|
||||
}
|
||||
@media (min-width: 760px) {
|
||||
.tools-hero-bg {
|
||||
min-height: 350px;
|
||||
}
|
||||
}
|
||||
.cio-bg-blue {
|
||||
background: rgb(2, 51, 189);
|
||||
background-size: cover;
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1920" />
|
||||
<meta property="og:image:height" content="1080" />
|
||||
<meta property="og:image:secure_url" itemprop="image"
|
||||
content="https://classroomio.com/classroomio-opengraph-image.png" />
|
||||
<meta property="og:image:secure_url" itemprop="image" content="https://brand.cdn.clsrio.com/og/classroomio-og.png" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:domain" content="classroomio.com" />
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<p class="lg:text-base mb-5 mr-2 text-sm leading-7 tracking-wide text-gray-600 lg:leading-7">
|
||||
Launch Your Online Bootcamp In Minutes
|
||||
<br />
|
||||
The easiest way to launch and scale your online bootcamp
|
||||
ClassroomIO is the easiest way to grow your teaching business.
|
||||
</p>
|
||||
<!-- <a
|
||||
href="https://www.producthunt.com/posts/classroomio?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-classroomio"
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export { before, after, offset, overlay, contain, hideOnSlide };
|
||||
|
||||
let hideOnSlide = true,
|
||||
imgOffset = null,
|
||||
sliding = false,
|
||||
contain = false,
|
||||
overlay = true,
|
||||
offset = 0.5,
|
||||
before = '',
|
||||
after = '',
|
||||
img;
|
||||
|
||||
function resize(e) {
|
||||
imgOffset = (e.type === 'load' ? e.target : img).getBoundingClientRect();
|
||||
w = imgOffset && imgOffset.width;
|
||||
h = imgOffset && imgOffset.height;
|
||||
style = contain ? `width:100%;height:100%;` : `width:${w}px;height:${h}px;`;
|
||||
}
|
||||
|
||||
function move(e) {
|
||||
if (sliding && imgOffset) {
|
||||
let x = (e.touches ? e.touches[0].pageX : e.pageX) - imgOffset.left;
|
||||
x = x < 0 ? 0 : x > w ? w : x;
|
||||
offset = x / w;
|
||||
}
|
||||
}
|
||||
|
||||
function start(e) {
|
||||
sliding = true;
|
||||
move(e);
|
||||
}
|
||||
|
||||
function end() {
|
||||
sliding = false;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
resize({});
|
||||
});
|
||||
|
||||
$: w = imgOffset && imgOffset.width;
|
||||
$: h = imgOffset && imgOffset.height;
|
||||
$: x = w * offset;
|
||||
$: opacity = hideOnSlide && sliding ? 0 : 1;
|
||||
$: style = contain ? `width:100%;height:100%;` : `width:${w}px;height:${h}px;`;
|
||||
</script>
|
||||
|
||||
<svelte:window on:resize={resize} />
|
||||
|
||||
<button
|
||||
class="container floating w-[85%] lg:w-[70%] h-full mx-auto rounded-md"
|
||||
{style}
|
||||
on:touchstart={start}
|
||||
on:mousedown={start}
|
||||
on:touchmove={move}
|
||||
on:touchend={end}
|
||||
on:mousemove={move}
|
||||
on:mouseup={end}
|
||||
>
|
||||
<img
|
||||
loading="lazy"
|
||||
bind:this={img}
|
||||
src={after}
|
||||
alt="after"
|
||||
on:mousedown|preventDefault
|
||||
on:load={resize}
|
||||
{style}
|
||||
/>
|
||||
<img
|
||||
loading="lazy"
|
||||
src={before}
|
||||
alt="before"
|
||||
on:mousedown|preventDefault
|
||||
style="{style}clip:rect(0, {x}px, {h}px, 0);"
|
||||
/>
|
||||
{#if overlay}
|
||||
<div class="overlay" style="opacity:{opacity}" />
|
||||
{/if}
|
||||
<div class="before-label" style="opacity:{opacity}">
|
||||
<slot name="before" />
|
||||
</div>
|
||||
<div class="after-label" style="opacity:{opacity}">
|
||||
<slot name="after" />
|
||||
</div>
|
||||
<div class="handle" style="left: calc({offset * 100}% - 20px)">
|
||||
<div class="arrow-left" />
|
||||
<div class="arrow-right" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-sizing: content-box;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
.container img {
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 20;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
user-select: none;
|
||||
object-fit: cover;
|
||||
position: absolute;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
}
|
||||
.overlay {
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
z-index: 25;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
transition: opacity 0.5s;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.before-label,
|
||||
.after-label {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 25;
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
}
|
||||
.before-label {
|
||||
left: 0;
|
||||
}
|
||||
.after-label {
|
||||
right: 0;
|
||||
}
|
||||
.container:hover > .overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
.handle {
|
||||
z-index: 30;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: move;
|
||||
background: none;
|
||||
margin-top: -4px;
|
||||
margin-left: -4px;
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
border-radius: 50px;
|
||||
top: calc(50% - 20px);
|
||||
border: 4px solid white;
|
||||
}
|
||||
.handle:before,
|
||||
.handle:after {
|
||||
content: '';
|
||||
height: 9999px;
|
||||
position: absolute;
|
||||
left: calc(50% - 2px);
|
||||
border: 2px solid white;
|
||||
}
|
||||
.handle:before {
|
||||
top: 40px;
|
||||
}
|
||||
.handle:after {
|
||||
bottom: 40px;
|
||||
}
|
||||
.arrow-right,
|
||||
.arrow-left {
|
||||
width: 0;
|
||||
height: 0;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
border-top: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
}
|
||||
.arrow-right {
|
||||
left: 17px;
|
||||
bottom: 13px;
|
||||
border-left: 10px solid white;
|
||||
}
|
||||
.arrow-left {
|
||||
left: 5px;
|
||||
top: 7px;
|
||||
border-right: 10px solid white;
|
||||
}
|
||||
|
||||
img,
|
||||
.overlay,
|
||||
.container {
|
||||
max-height: 500px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Section from './Section.svelte';
|
||||
import Section from './CoreFeatureSection.svelte';
|
||||
import { env } from '$env/dynamic/public';
|
||||
</script>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { onMount } from 'svelte';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { folder, globe, team, transcription } from '$lib/emojis';
|
||||
import { tools } from '$lib/utils/constants/tools';
|
||||
|
||||
let selected = 0;
|
||||
let interval: NodeJS.Timer;
|
||||
@@ -36,6 +37,8 @@
|
||||
}
|
||||
];
|
||||
|
||||
const freeTools = tools.filter((item) => item.showFeature);
|
||||
|
||||
onMount(() => {
|
||||
if (window.innerWidth > 768) {
|
||||
interval = setInterval(() => {
|
||||
@@ -104,6 +107,45 @@
|
||||
{/key}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- free tools section -->
|
||||
<div>
|
||||
<div class="flex justify-evenly gap-y-8 flex-wrap w-full mt-10 mx-auto">
|
||||
<div class="text-center">
|
||||
<h1 class="text-3xl md:text-5xl font-bold">
|
||||
Play With Our <span class="text-[#0233BD]">Free Tools</span>
|
||||
</h1>
|
||||
<p class="text-sm md:text-base text-[#334155] md:w-[65%] mt-5 md:mt-10 mx-auto">
|
||||
Innovative tools to help you aid you example preparation, as well as making learning
|
||||
more fun for students and educator looking for engaging resources.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#each freeTools as tool}
|
||||
<a
|
||||
class="w-full flex flex-col gap-3 max-w-[400px] md:max-w-[300px] mt-5 p-5 border rounded-md bg-white shadow-sm hover:scale-95 transition-all ease-in-out cursor-pointer"
|
||||
href="/tools/{tool.slug}"
|
||||
>
|
||||
<img class="w-[30%] rounded-full border border-[#EAEAEA]" src={tool.src} alt="" />
|
||||
<div class="rounded-r-md p-3">
|
||||
<h1 class="font-bold text-sm md:text-base">{tool.title}</h1>
|
||||
<p class="text-xs text-gray-600 mt-1.5">
|
||||
{tool.subText}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-20">
|
||||
<a
|
||||
class="md:text-base w-full md:max-w-[300px] max-w-[400px] rounded-md bg-blue-700 px-6 py-3 lg:px-6 lg:py-3 text-sm font-medium text-white text-center transition-all delay-100 hover:bg-blue-800 hover:shadow-xl hover:scale-95 lg:font-semibold cursor-pointer"
|
||||
href="/tools"
|
||||
rel="noopener noreferrer nofollow"
|
||||
>
|
||||
More Tools
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<script>
|
||||
export let className = '';
|
||||
export let open = false;
|
||||
</script>
|
||||
|
||||
{#if open}
|
||||
<div class="relative flex items-center justify-center">
|
||||
<!-- black background -->
|
||||
<div class="fixed z-[3000] top-0 left-0 w-full h-full bg-black opacity-[0.7]"></div>
|
||||
<div
|
||||
class="fixed z-[3001] {className} w-full md:w-[30%] md:min-w-[500px] bg-white rounded-md mx-auto py-6 px-7"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -52,7 +52,7 @@
|
||||
<div
|
||||
class="flex w-full justify-between items-center py-6 border-b-[1px] md:px-12 px-5 fixed top-0 z-[3000] filter backdrop-blur-xl shadow-sm bg-white"
|
||||
>
|
||||
<a href="/" class="w-[20%]">
|
||||
<a href="/" class="w-[10%]">
|
||||
<div class="flex items-center w-full">
|
||||
<img
|
||||
loading="lazy"
|
||||
@@ -66,7 +66,7 @@
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<nav class="w-[40%] hidden md:hidden lg:block">
|
||||
<nav class="w-[50%] hidden md:hidden lg:block">
|
||||
<ul class="flex items-center justify-between w-full gap-2">
|
||||
<li class="text-gray-800 font-semibold text-sm cursor-pointer relative">
|
||||
<button
|
||||
@@ -111,20 +111,20 @@
|
||||
{/if}
|
||||
</li>
|
||||
<a
|
||||
href="/pricing"
|
||||
href="/tools"
|
||||
class="text-gray-800 font-semibold text-sm cursor-pointer"
|
||||
class:active={activeLink.startsWith('/pricing')}
|
||||
class:active={activeLink.startsWith('/tools')}
|
||||
>
|
||||
<li class="hover:bg-gray-100 px-4 py-2 rounded-md">Pricing</li>
|
||||
<li class="hover:bg-gray-100 px-4 py-2 rounded-md">Free Tools</li>
|
||||
</a>
|
||||
<a
|
||||
<!-- <a
|
||||
href="/docs"
|
||||
target="_blank"
|
||||
class="text-gray-800 font-semibold text-sm cursor-pointer"
|
||||
class:active={activeLink.startsWith('/docs')}
|
||||
>
|
||||
<li class="hover:bg-gray-100 px-4 py-2 rounded-md">Docs</li>
|
||||
</a>
|
||||
</a> -->
|
||||
|
||||
<a
|
||||
href="/blog"
|
||||
@@ -133,6 +133,13 @@
|
||||
>
|
||||
<li class="hover:bg-gray-100 px-4 py-2 rounded-md">Blog</li>
|
||||
</a>
|
||||
<a
|
||||
href="/pricing"
|
||||
class="text-gray-800 font-semibold text-sm cursor-pointer"
|
||||
class:active={activeLink.startsWith('/pricing')}
|
||||
>
|
||||
<li class="hover:bg-gray-100 px-4 py-2 rounded-md">Pricing</li>
|
||||
</a>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -214,17 +221,15 @@
|
||||
</div>
|
||||
{/if}
|
||||
</li>
|
||||
<!-- Free Tools -->
|
||||
<a
|
||||
class="text-gray-800 font-semibold text-sm md:text-lg cursor-pointer hover:bg-gray-100 py-3 px-4 rounded-xl w-full"
|
||||
on:click={() => {
|
||||
handleShowNav();
|
||||
}}
|
||||
href="/pricing"
|
||||
class:active={activeLink.startsWith('/pricing')}
|
||||
on:click={handleShowNav}
|
||||
href="/tools"
|
||||
>
|
||||
<li>Pricing</li>
|
||||
<li>Free Tools</li>
|
||||
</a>
|
||||
<a
|
||||
<!-- <a
|
||||
class="text-gray-800 font-semibold text-sm md:text-lg cursor-pointer hover:bg-gray-100 py-3 px-4 rounded-md w-full"
|
||||
on:click={() => {
|
||||
handleShowNav();
|
||||
@@ -234,7 +239,7 @@
|
||||
target="_blank"
|
||||
>
|
||||
<li>Docs</li>
|
||||
</a>
|
||||
</a> -->
|
||||
<a
|
||||
class="text-gray-800 font-semibold text-sm md:text-lg cursor-pointer hover:bg-gray-100 py-3 px-4 rounded-md w-full"
|
||||
on:click={() => {
|
||||
@@ -245,6 +250,17 @@
|
||||
>
|
||||
<li>Blog</li>
|
||||
</a>
|
||||
<!-- Pricing -->
|
||||
<a
|
||||
class="text-gray-800 font-semibold text-sm md:text-lg cursor-pointer hover:bg-gray-100 py-3 px-4 rounded-xl w-full"
|
||||
on:click={() => {
|
||||
handleShowNav();
|
||||
}}
|
||||
href="/pricing"
|
||||
class:active={activeLink.startsWith('/pricing')}
|
||||
>
|
||||
<li>Pricing</li>
|
||||
</a>
|
||||
<a
|
||||
class="text-gray-800 font-semibold text-sm md:text-lg cursor-pointer hover:bg-gray-100 py-3 px-4 rounded-md w-full"
|
||||
on:click={() => {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<script>
|
||||
export let className = '';
|
||||
</script>
|
||||
|
||||
<header class="tools-hero-bg text-center py-14 {className} border-b border-slate-100 bg-white">
|
||||
<slot />
|
||||
</header>
|
||||
@@ -0,0 +1,71 @@
|
||||
interface Tool {
|
||||
src: string;
|
||||
title: string;
|
||||
subText: string;
|
||||
slug: string;
|
||||
show: boolean;
|
||||
showFeature: boolean;
|
||||
}
|
||||
|
||||
export const tools: Tool[] = [
|
||||
{
|
||||
src: '/free-tools/progress-report.svg',
|
||||
title: 'Progress Report',
|
||||
subText: 'Monitor your progress with a system to check and share your progress with others',
|
||||
slug: 'progress',
|
||||
show: true,
|
||||
showFeature: true
|
||||
},
|
||||
{
|
||||
src: '/free-tools/pomodoro.svg',
|
||||
title: 'Pomodoro Timer',
|
||||
subText:
|
||||
'Make your workday more engaging and effective with the Pomodoro timer, break work into 25-minute focused intervals called "pomodoros".',
|
||||
slug: 'pomodoro',
|
||||
show: true,
|
||||
showFeature: false
|
||||
},
|
||||
{
|
||||
src: '/free-tools/name-picker.svg',
|
||||
title: 'Random Name Picker',
|
||||
subText: 'Effortlessly choose names for class participation or group activities',
|
||||
slug: 'name-picker',
|
||||
show: true,
|
||||
showFeature: false
|
||||
},
|
||||
{
|
||||
src: '/free-tools/activity-stopwatch.svg',
|
||||
title: 'Activity Stopwatch',
|
||||
subText:
|
||||
'Stay on track and enhance productivity with our customizable stopwatch for timed tasks, quizzes, and study sessions',
|
||||
slug: 'stopwatch',
|
||||
show: true,
|
||||
showFeature: true
|
||||
},
|
||||
{
|
||||
src: '/free-tools/tic-tac.svg',
|
||||
title: 'Tic tac toe game',
|
||||
subText:
|
||||
"More than just a game; it's an educational tool that teaches pattern recognition, and decision-making.",
|
||||
slug: 'tic-tac-toe',
|
||||
show: true,
|
||||
showFeature: true
|
||||
},
|
||||
{
|
||||
src: '/free-tools/waec.svg',
|
||||
title: 'WAEC Practice tool',
|
||||
subText: 'Ace your WAEC exams with comprehensive study materials, past questions',
|
||||
slug: 'waec',
|
||||
show: false,
|
||||
showFeature: false
|
||||
},
|
||||
{
|
||||
src: '/free-tools/jamb.svg',
|
||||
title: 'JAMB Practice tool',
|
||||
subText:
|
||||
'Prepare for JAMB with past questions and instant feedback for effective exam readiness',
|
||||
slug: 'jamb',
|
||||
show: false,
|
||||
showFeature: false
|
||||
}
|
||||
];
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<MetaTags {...metaTags} />
|
||||
|
||||
<div class="overflow-hidden">
|
||||
<div class="overflow-hidden bg-white">
|
||||
<Navigation />
|
||||
|
||||
<PageTransition url={data.url}>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script>
|
||||
import Hero from '$lib/Hero/Hero.svelte';
|
||||
import Body from '$lib/Body/Body.svelte';
|
||||
import Faq from '$lib/Faq/Faq.svelte';
|
||||
import StudentDashboard from '$lib/StudentDashboard/StudentDashboard.svelte';
|
||||
import MoreFeatures from '$lib/MoreFeatures/MoreFeatures.svelte';
|
||||
import Testimonial from '$lib/Testimonial/Testimonial.svelte';
|
||||
import Hero from '$lib/Home/Hero.svelte';
|
||||
import CoreFeatures from '$lib/Home/CoreFeatures.svelte';
|
||||
import Faq from '$lib/Home/Faq.svelte';
|
||||
import StudentDashboard from '$lib/Home/StudentDashboard.svelte';
|
||||
import MoreFeatures from '$lib/Home/MoreFeatures.svelte';
|
||||
import Testimonial from '$lib/Home/Testimonial.svelte';
|
||||
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { onMount } from 'svelte';
|
||||
@@ -15,7 +15,7 @@
|
||||
</script>
|
||||
|
||||
<Hero />
|
||||
<Body />
|
||||
<CoreFeatures />
|
||||
<StudentDashboard />
|
||||
<Testimonial />
|
||||
<MoreFeatures />
|
||||
|
||||
@@ -186,9 +186,9 @@
|
||||
</section>
|
||||
|
||||
<PageSignupCTA
|
||||
header="Launch Your First Training in Minutes"
|
||||
header="Bring your bootcamp vision online"
|
||||
subText="Try before you buy. No credit card required."
|
||||
btnLabel="Sign up"
|
||||
btnLabel="Sign up for free"
|
||||
link="/signup"
|
||||
demo={false}
|
||||
/>
|
||||
|
||||
@@ -77,11 +77,7 @@
|
||||
|
||||
<svelte:head>
|
||||
<title>Teach | ClassroomIO</title>
|
||||
<meta
|
||||
property="og:image"
|
||||
itemprop="image"
|
||||
content="https://classroomio.com/teach/teacher-banner.png"
|
||||
/>
|
||||
<meta property="og:image" itemprop="image" content="https://brand.cdn.clsrio.com/og/teach.png" />
|
||||
<meta property="og:title" content="Teach on ClassroomIO" />
|
||||
<meta
|
||||
property="og:description"
|
||||
@@ -91,7 +87,7 @@
|
||||
<meta
|
||||
property="og:image:secure_url"
|
||||
itemprop="image"
|
||||
content="https://classroomio.com/teach/teacher-banner.png"
|
||||
content="https://brand.cdn.clsrio.com/og/teach.png"
|
||||
/>
|
||||
|
||||
<meta name="twitter:title" content="Teach on ClassroomIO" />
|
||||
@@ -99,7 +95,7 @@
|
||||
name="twitter:description"
|
||||
content="On ClassroomIO you can make side income while doing what you love."
|
||||
/>
|
||||
<meta name="twitter:image" content="https://classroomio.com/teach/teacher-banner.png" />
|
||||
<meta name="twitter:image" content="https://brand.cdn.clsrio.com/og/teach.png" />
|
||||
</svelte:head>
|
||||
|
||||
<section>
|
||||
@@ -113,7 +109,7 @@
|
||||
<a
|
||||
href="/teach/register"
|
||||
target="_blank"
|
||||
class="w-full block text-center lg:w-[30%] py-3 text-base text-white rounded-md bg-[#1D4ED8]"
|
||||
class="w-full block text-center lg:w-[30%] py-3 text-base text-white rounded-md bg-blue-700"
|
||||
>
|
||||
Register
|
||||
</a>
|
||||
@@ -169,7 +165,7 @@
|
||||
<a
|
||||
href="/teach/register"
|
||||
target="_blank"
|
||||
class="w-full lg:max-w-[20%] py-3 text-base text-white rounded-md bg-[#1D4ED8] text-center"
|
||||
class="w-full lg:max-w-[20%] py-3 text-base text-white rounded-md bg-blue-700 text-center"
|
||||
>
|
||||
Get Started
|
||||
</a>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<script>
|
||||
import PageSignupCTA from '$lib/PageSignupCTA/index.svelte';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Free Tools | ClassroomIO</title>
|
||||
<meta
|
||||
property="og:image"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
<meta property="og:title" content="ClassroomIO Free Tools" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="At ClassroomIO, we have built a suit of tools for anyone to use freely while collaborating with students"
|
||||
/>
|
||||
|
||||
<meta
|
||||
property="og:image:secure_url"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
|
||||
<meta name="twitter:title" content="ClassroomIO Free Tools" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="At ClassroomIO, we have built a suit of tools for anyone to use freely while collaborating with students"
|
||||
/>
|
||||
<meta name="twitter:image" content="https://brand.cdn.clsrio.com/og/free-tools.png" />
|
||||
</svelte:head>
|
||||
|
||||
<slot />
|
||||
|
||||
<PageSignupCTA
|
||||
header="Scale Your Bootcamp Today with ClassroomIO"
|
||||
subText="ClassroomIO gives small and medium bootcamps the power of online learning, simplified."
|
||||
btnLabel="Sign me up"
|
||||
link="/signup"
|
||||
demo={false}
|
||||
/>
|
||||
@@ -0,0 +1 @@
|
||||
export const prerender = true;
|
||||
@@ -0,0 +1,80 @@
|
||||
<script>
|
||||
import PageHeader from '$lib/PageHeader/PageHeader.svelte';
|
||||
import { tools } from '$lib/utils/constants/tools';
|
||||
|
||||
const freeTools = tools.filter((item) => item.show);
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<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">
|
||||
Explore our free <span class="text-blue-700">tools</span>
|
||||
</h1>
|
||||
<p class="my-4 md:my-8">
|
||||
Innovative tools to help you aid you example preparation, as well as making learning more
|
||||
fun for students and educator looking for engaging resources.
|
||||
</p>
|
||||
|
||||
<div class="flex relative w-[90%] md:w-[50%] my-3 md:mt-10 mx-auto bg-white">
|
||||
<!-- <img
|
||||
class="w-[18%] rounded-full border hover:scale-110 transition-all hover:z-50 absolute left-0 z-0"
|
||||
src="/free-tools/waec.svg"
|
||||
alt="Waec logo"
|
||||
/> -->
|
||||
<img
|
||||
class="w-[18%] rounded-full border hover:scale-110 transition-all hover:z-50 absolute left-[55px] z-10"
|
||||
src="/free-tools/progress-report.svg"
|
||||
alt="Progress Report"
|
||||
/>
|
||||
<img
|
||||
class="w-[18%] rounded-full border hover:scale-110 transition-all hover:z-50 absolute left-[100px] z-20"
|
||||
src="/free-tools/activity-stopwatch.svg"
|
||||
alt="Activity Stopwatch logo"
|
||||
/>
|
||||
<img
|
||||
class="w-[18%] rounded-full border hover:scale-110 transition-all hover:z-50 absolute left-[150px] z-30"
|
||||
src="/free-tools/name-picker.svg"
|
||||
alt="Name picker logo"
|
||||
/>
|
||||
<img
|
||||
class="w-[18%] rounded-full border hover:scale-110 transition-all hover:z-50 absolute left-[200px] z-40"
|
||||
src="/free-tools/tic-tac.svg"
|
||||
alt="Tic tac logo"
|
||||
/>
|
||||
<img
|
||||
class="w-[18%] rounded-full border hover:scale-110 transition-all hover:z-50 absolute left-[250px] z-50 bg-white"
|
||||
src="/free-tools/pomodoro.svg"
|
||||
alt="Pomodoro Timer logo"
|
||||
/>
|
||||
<!-- <img
|
||||
class="w-[18%] rounded-full border hover:scale-110 transition-all hover:z-50 absolute left-[250px] z-50"
|
||||
src="/free-tools/jamb.svg"
|
||||
alt="Jamb logo"
|
||||
/> -->
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
|
||||
<div class="p-10 px-2 md:px-0 bg-white">
|
||||
<h1 class="text-center font-bold text-3xl">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}
|
||||
<a
|
||||
href="/tools/{tool.slug}"
|
||||
class="w-full flex md:max-w-[370px] border rounded-md shadow-sm hover:scale-95 transition-all ease-in-out"
|
||||
>
|
||||
<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>
|
||||
<p class="text-xs text-gray-600 mt-1.5">
|
||||
{tool.subText}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,260 @@
|
||||
<script lang="ts">
|
||||
import ToolsHeader from '$lib/ToolsHeader/ToolsHeader.svelte';
|
||||
|
||||
let namesInput = '';
|
||||
let numNames = 0;
|
||||
let wordCount = 0;
|
||||
let selectedNames: string[] = [];
|
||||
let avatarUrls: string[] = [];
|
||||
let avatarUrlsFetched = false;
|
||||
|
||||
// function to shuffle an array
|
||||
const shuffleArray = (array: string[]) => {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
return array;
|
||||
};
|
||||
|
||||
// function to reset entries
|
||||
const resetEntry = () => {
|
||||
namesInput = '';
|
||||
numNames = 0;
|
||||
wordCount = 0;
|
||||
selectedNames = [];
|
||||
};
|
||||
|
||||
// function to sort the input alphabetically
|
||||
const sortRandom = () => {
|
||||
const sortedNames = namesInput
|
||||
.split(',')
|
||||
.map((name) => name.trim())
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
namesInput = sortedNames.join(', ');
|
||||
};
|
||||
|
||||
// function to unsort
|
||||
const unsortRandom = () => {
|
||||
const unsortedNames = namesInput
|
||||
.split(',')
|
||||
.map((name) => name.trim())
|
||||
.sort(() => 0.5 - Math.random());
|
||||
namesInput = unsortedNames.join(', ');
|
||||
};
|
||||
|
||||
const selectName = async () => {
|
||||
const namesArray = namesInput.split(',').map((name) => name.trim());
|
||||
|
||||
if (numNames > namesArray.length) {
|
||||
console.error('Number of names to pick exceeds the length of the name list.');
|
||||
return;
|
||||
}
|
||||
|
||||
wordCount = namesArray.length;
|
||||
const shuffledNames = shuffleArray(namesArray);
|
||||
|
||||
selectedNames = shuffledNames.slice(0, numNames);
|
||||
avatarUrls = []; // reset avatar URLs
|
||||
avatarUrlsFetched = false; // reset avatarUrlsFetched flag
|
||||
|
||||
try {
|
||||
// set loading state
|
||||
avatarUrlsFetched = false;
|
||||
|
||||
// generate avatar for each selected name
|
||||
for (const name of selectedNames) {
|
||||
const avatarUrl = await generateRandomAvatar('pixel-art');
|
||||
if (avatarUrl) {
|
||||
avatarUrls.push(avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// set avatarUrlsFetched to true after avatars are fetched
|
||||
avatarUrlsFetched = true;
|
||||
} catch (error) {
|
||||
console.error('Error fetching avatars:', error);
|
||||
avatarUrlsFetched = true;
|
||||
}
|
||||
};
|
||||
|
||||
// function to generate a random avatar
|
||||
async function generateRandomAvatar(styleName: string, format = 'svg') {
|
||||
const baseUrl = 'https://api.dicebear.com/8.x/';
|
||||
const randomSeed = Math.random().toString(36).substring(7);
|
||||
|
||||
try {
|
||||
const apiUrl = `${baseUrl}${styleName}/svg?seed=${randomSeed}`;
|
||||
const response = await fetch(apiUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch avatar');
|
||||
}
|
||||
|
||||
return response.url;
|
||||
} catch (error) {
|
||||
console.error('Error generating random avatar:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$: wordCount = namesInput?.split(',').filter((name) => name.trim())?.length ?? 0;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Random Name Picker | ClassroomIO</title>
|
||||
<meta
|
||||
property="og:image"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
<meta property="og:title" content="Random Name Picker | ClassroomIO" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Use this online name picker to draw a random name from a list of names for your online or physical classroom."
|
||||
/>
|
||||
|
||||
<meta
|
||||
property="og:image:secure_url"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
|
||||
<meta name="twitter:title" content="Random Name Picker | ClassroomIO" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Use this online name picker to draw a random name from a list of names for your online or physical classroom."
|
||||
/>
|
||||
<meta name="twitter:image" content="https://brand.cdn.clsrio.com/og/free-tools.png" />
|
||||
</svelte:head>
|
||||
|
||||
<section class="mt-[10%] md:mt-16 px-5 md:px-0 bg-white">
|
||||
<ToolsHeader>
|
||||
<img
|
||||
src="/free-tools/name-picker.svg"
|
||||
class="w-[15%] md:w-[5%] mx-auto border rounded-full"
|
||||
alt=""
|
||||
/>
|
||||
<h1 class="text-4xl md:text-6xl font-bold text-[#040F2D] my-3">Random Name Picker</h1>
|
||||
<p class="text-md text-[#656565] font-light md:font-normal md:w-[45%] mx-auto">
|
||||
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.
|
||||
</p>
|
||||
</ToolsHeader>
|
||||
|
||||
<div class="border rounded-md md:w-[60%] my-10 py-8 md:py-[3%] mx-auto shadow-md bg-white">
|
||||
<div class="w-[85%] md:w-[70%] mx-auto bg-white">
|
||||
<h1 class="font-bold text-sm">List of names</h1>
|
||||
|
||||
<!-- container -->
|
||||
<div
|
||||
class="relative focus-within:border-[#0233BD] border-2 mt-5 h-[12rem] pl-3 pt-2 overflow-hidden rounded-sm bg-[#F1F2F4]"
|
||||
>
|
||||
<!-- sidebar -->
|
||||
<div class="flex flex-col gap-y-3 absolute right-2 md:right-7 top-3">
|
||||
<button
|
||||
type="button"
|
||||
on:click={sortRandom}
|
||||
class="p-1.5 rounded-full bg-[#D9E0F5] flex justify-center items-center"
|
||||
>
|
||||
<img src="/sort-icon.svg" class="w-2.5" alt="" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={unsortRandom}
|
||||
class="p-1.5 rounded-full bg-[#D9E0F5] flex justify-center items-center"
|
||||
>
|
||||
<img src="/unsort-icon.svg" class="w-2.5" alt="" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- content -->
|
||||
<div class="z-10 h-[80%]">
|
||||
<span
|
||||
role="textbox"
|
||||
tabindex={0}
|
||||
contenteditable
|
||||
bind:textContent={namesInput}
|
||||
class="w-full pr-9 md:pr-14 overflow-y-auto text-xs block border-0 outline-none h-full"
|
||||
></span>
|
||||
</div>
|
||||
|
||||
<!-- word count -->
|
||||
<p
|
||||
class="rounded-xl w-[80px] mt-1 py-1 bg-[#D9E0F5] text-center text-[#0F62FE] text-[10px] font-semibold"
|
||||
>
|
||||
name count: {wordCount}
|
||||
</p>
|
||||
</div>
|
||||
<p class="py-4 border-b text-xs">Each name must be separated by a comma</p>
|
||||
|
||||
<div class="mt-10">
|
||||
<h1 class="font-bold text-sm">Number of Names</h1>
|
||||
<!-- number input & button -->
|
||||
<div class="flex flex-wrap gap-y-3 justify-between w-full mt-5">
|
||||
<input
|
||||
type="number"
|
||||
bind:value={numNames}
|
||||
class="px-3 py-2 text-sm w-full md:w-2/4 border-2 rounded-sm outline focus:border-[#0233BD] bg-[#F1F2F4] outline-none"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
on:click={selectName}
|
||||
class="bg-[#0F62FE] rounded-md text-sm py-3 md:py-0 text-white w-[70%] md:w-[35%]"
|
||||
>Select name(s) at random</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- footer logo -->
|
||||
<div class="py-3 mt-10 mb-5 bg-[#F1F6FF] flex justify-center items-center gap-3">
|
||||
<img src="/free-tools/name-picker.svg" class="w-[12%] md:w-[9%]" alt="" />
|
||||
{#if selectedNames.length > 0}
|
||||
<h1 class="text-[#0233BD] text-xl font-bold">Selected Names</h1>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- loading state -->
|
||||
{#if selectedNames.length > 0 && !avatarUrlsFetched}
|
||||
<div class="w-full flex justify-center items-center">
|
||||
<p class="font-bold">Loading...</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- generated name -->
|
||||
{#if selectedNames.length > 0 && avatarUrlsFetched}
|
||||
<div>
|
||||
<ul>
|
||||
{#each selectedNames as name, index}
|
||||
<li class="py-2 border-b">
|
||||
<div class="flex item-center gap-3 md:gap-5 justify-center">
|
||||
<img src={avatarUrls[index]} alt="" class="w-7" />
|
||||
<p
|
||||
class="font-medium text-sm md:text-base w-[20%] md:w-[10%] flex justify-center items-center"
|
||||
>
|
||||
{name}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<div class="flex flex-wrap justify-between md:justify-center items-center md:gap-3 mt-3">
|
||||
<button
|
||||
type="button"
|
||||
on:click={resetEntry}
|
||||
class="py-2 border text-xs md:text-sm rounded-md w-[45%] md:w-[20%]"
|
||||
>Reset Entries</button
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={selectName}
|
||||
class="py-2 bg-[#0F62FE] rounded-md text-xs md:text-sm text-white w-[45%] md:w-[27%]"
|
||||
>Select other names</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,393 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import ToolsHeader from '$lib/ToolsHeader/ToolsHeader.svelte';
|
||||
|
||||
interface TodoItem {
|
||||
id: number;
|
||||
content: string;
|
||||
time: string;
|
||||
isPaused: boolean;
|
||||
isEditing: boolean;
|
||||
isDone: boolean;
|
||||
isVisible: boolean;
|
||||
}
|
||||
|
||||
let addInput: HTMLInputElement;
|
||||
let buzzSound: HTMLAudioElement;
|
||||
let todoList: TodoItem[] = [];
|
||||
|
||||
let countdownTime: number = 25 * 60;
|
||||
let countdownDisplay: string = '25:00';
|
||||
let timerState: string = 'pomodoro';
|
||||
|
||||
let isPaused: boolean = true;
|
||||
let timerInterval: any = null;
|
||||
let isVisible: boolean = false;
|
||||
|
||||
const timerSequence = ['pomodoro', 'long-break', 'short-break'];
|
||||
|
||||
function saveTodoList() {
|
||||
localStorage.setItem('todoList', JSON.stringify(todoList));
|
||||
}
|
||||
|
||||
function loadTodoList() {
|
||||
const storedTodoList = localStorage.getItem('todoList');
|
||||
if (storedTodoList) {
|
||||
todoList = JSON.parse(storedTodoList);
|
||||
}
|
||||
}
|
||||
|
||||
function setEditing(i: number, isEditing: boolean) {
|
||||
todoList[i].isEditing = isEditing;
|
||||
saveTodoList();
|
||||
}
|
||||
|
||||
function deleteTodo(i: number) {
|
||||
todoList.splice(i, 1);
|
||||
todoList = todoList;
|
||||
isVisible = false;
|
||||
saveTodoList();
|
||||
}
|
||||
|
||||
function markTodoAsDone(i: number) {
|
||||
todoList[i].isDone = true;
|
||||
todoList = [...todoList];
|
||||
todoList[i].isVisible = false;
|
||||
saveTodoList();
|
||||
}
|
||||
|
||||
function addTodo() {
|
||||
todoList = [
|
||||
...todoList,
|
||||
{
|
||||
id: new Date().getMilliseconds(),
|
||||
content: '',
|
||||
isEditing: true,
|
||||
time: '25:00',
|
||||
isPaused: true,
|
||||
isDone: false,
|
||||
isVisible: false
|
||||
}
|
||||
];
|
||||
|
||||
setTimeout(() => {
|
||||
addInput.focus();
|
||||
}, 50);
|
||||
|
||||
saveTodoList();
|
||||
}
|
||||
|
||||
function startCountdown() {
|
||||
if (!isPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
isPaused = false;
|
||||
|
||||
timerInterval = setInterval(() => {
|
||||
if (countdownTime > 0) {
|
||||
countdownTime--;
|
||||
updateCountdownDisplay();
|
||||
} else {
|
||||
clearInterval(timerInterval);
|
||||
countdownDisplay = '00:00';
|
||||
buzzSound.play();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function pauseCountdown() {
|
||||
if (isPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
isPaused = true;
|
||||
clearInterval(timerInterval);
|
||||
}
|
||||
|
||||
function resetCountdown() {
|
||||
clearInterval(timerInterval);
|
||||
|
||||
switch (timerState) {
|
||||
case 'pomodoro':
|
||||
countdownTime = 25 * 60;
|
||||
break;
|
||||
case 'short-break':
|
||||
countdownTime = 15 * 60;
|
||||
break;
|
||||
case 'long-break':
|
||||
countdownTime = 5 * 60;
|
||||
break;
|
||||
}
|
||||
|
||||
isPaused = true;
|
||||
|
||||
updateCountdownDisplay();
|
||||
}
|
||||
|
||||
function nextTimerState() {
|
||||
const currentIndex = timerSequence.indexOf(timerState);
|
||||
const nextIndex = (currentIndex + 1) % timerSequence.length;
|
||||
setTimerState(timerSequence[nextIndex]);
|
||||
}
|
||||
|
||||
function updateCountdownDisplay() {
|
||||
const minutes = Math.floor(countdownTime / 60);
|
||||
const seconds = countdownTime % 60;
|
||||
countdownDisplay = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function setTimerState(state: string) {
|
||||
timerState = state;
|
||||
resetCountdown();
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
buzzSound = new Audio('https://assets.cdn.clsrio.com/beeping-sound.mp3');
|
||||
loadTodoList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Pomodoro Timer | ClassroomIO</title>
|
||||
<meta property="og:image" itemprop="image" content="" />
|
||||
<meta property="og:title" content="Pomodoro Timer | ClassroomIO" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="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"
|
||||
/>
|
||||
|
||||
<meta property="og:image:secure_url" itemprop="image" content="" />
|
||||
|
||||
<meta name="twitter:title" content="Pomodoro Timer | ClassroomIO" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="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"
|
||||
/>
|
||||
<meta name="twitter:image" content="" />
|
||||
</svelte:head>
|
||||
|
||||
<section class="mt-[10%] md:mt-16 px-1 md:px-0 w-full md:w-full bg-white">
|
||||
<ToolsHeader>
|
||||
<img
|
||||
src="/free-tools/pomodoro.svg"
|
||||
class="w-[15%] md:w-[5%] mx-auto border rounded-full"
|
||||
alt=""
|
||||
/>
|
||||
<h1 class="text-4xl md:text-6xl font-bold text-[#040F2D] my-3">Pomodoro Timer</h1>
|
||||
<p class="text-sm mt-10 text-[#656565] font-light md:font-normal md:w-[45%] mx-auto">
|
||||
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
|
||||
break.
|
||||
</p>
|
||||
</ToolsHeader>
|
||||
|
||||
<div
|
||||
class="body w-full md:h-[60vh] flex flex-col gap-y-10 md:flex-row justify-evenly px-5 md:px-10 my-10 text-white text-center"
|
||||
>
|
||||
<!-- left side -->
|
||||
<div
|
||||
class="w-full md:w-[50%] bg-[#0D4CFF] rounded-lg md:rounded-2xl py-7 px-5 md:p-10 flex flex-col gap-y-16 md:gap-y-0 justify-between"
|
||||
>
|
||||
<!-- types -->
|
||||
<div class="flex item-center justify-evenly">
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => setTimerState('pomodoro')}
|
||||
class:bg-[#3ADFECED]={timerState === 'pomodoro'}
|
||||
class:bg-[#0233BD]={timerState !== 'pomodoro'}
|
||||
class="transition-all duration-500 italic py-1.5 md:py-2 w-[25%] text-xs md:text-sm md:font-medium rounded-md hover:bg-[#3ADFECED]"
|
||||
>Pomodoro</button
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => setTimerState('long-break')}
|
||||
class:bg-[#3ADFECED]={timerState === 'long-break'}
|
||||
class:bg-[#0233BD]={timerState !== 'long-break'}
|
||||
class="transition-all duration-500 italic py-1.5 md:py-2 w-[25%] text-xs md:text-sm md:font-medium rounded-md hover:bg-[#3ADFECED]"
|
||||
>Short Break
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => setTimerState('short-break')}
|
||||
class:bg-[#3ADFECED]={timerState === 'short-break'}
|
||||
class:bg-[#0233BD]={timerState !== 'short-break'}
|
||||
class="transition-all duration-500 italic py-1.5 md:py-2 w-[25%] text-xs md:text-sm md:font-medium rounded-md hover:bg-[#3ADFECED]"
|
||||
>Long Break
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- countdown -->
|
||||
<h1 class="text-7xl md:text-9xl font-bold">{countdownDisplay}</h1>
|
||||
|
||||
<!-- controls -->
|
||||
<div class="flex items-center justify-center gap-7">
|
||||
<!-- reset -->
|
||||
<button type="button" on:click={resetCountdown}>
|
||||
<img
|
||||
src="/free-tools/pomodoro/restart-icon.svg"
|
||||
alt="Restart Icon"
|
||||
class="w-7 hover:scale-110 transition-all duration-300"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<!-- 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="bg-white text-[#0542CC] border text-base font-bold uppercase py-3 px-14 rounded-md hover:bg-transparent hover:text-white hover:border-white hover:border transition-all duration-300"
|
||||
>
|
||||
{isPaused ? 'Start' : 'Pause'}
|
||||
</button>
|
||||
|
||||
<!-- next -->
|
||||
<button type="button" on:click={nextTimerState}>
|
||||
<img
|
||||
src="/free-tools/pomodoro/timer-play-icon.svg"
|
||||
alt="Play Icon"
|
||||
class="w-7 hover:scale-110 transition-all duration-300"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- right side -->
|
||||
<div class="w-full md:w-[36%] relative">
|
||||
<h1
|
||||
class="bg-[#040F2D] uppercase text-xl font-bold py-4"
|
||||
style="clip-path: polygon(0 0, 100% 1%, 100% 65%, 0% 100%);"
|
||||
>
|
||||
To do list
|
||||
</h1>
|
||||
|
||||
<div class="overflow-hidden">
|
||||
<!-- todos -->
|
||||
<div class="overflow-y-auto mt-3 max-h-[40vh] md:max-h-[50vh]">
|
||||
{#each todoList as todo, i}
|
||||
<div class="border text-black p-5">
|
||||
{#if todo.isEditing}
|
||||
<form on:submit|preventDefault={() => setEditing(i, false)}>
|
||||
<p class="text-xs text-left text-[#656565] font-semibold">Pomodoro name</p>
|
||||
<input
|
||||
type="text"
|
||||
bind:this={addInput}
|
||||
bind:value={todo.content}
|
||||
class="bg-[#F1F2F4] border-[#EAEAEA] w-full border mt-2 px-3 py-2 text-base outline-none"
|
||||
/>
|
||||
<div class="flex justify-end items-center gap-5 mt-5">
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => deleteTodo(i)}
|
||||
class="rounded-sm py-2 px-5 text-xs font-semibold bg-[#F7F7F7]"
|
||||
>Discard</button
|
||||
>
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded-sm py-2 px-5 text-xs font-semibold bg-[#0D4CFF] text-white"
|
||||
>Save</button
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
{:else}
|
||||
<div class="">
|
||||
<div class="flex justify-between">
|
||||
<p class="text-sm font-medium">{todo.content}</p>
|
||||
|
||||
<!-- pen and menu icon -->
|
||||
<div class="relative flex justify-between w-[15%]">
|
||||
<button type="button" on:click={() => 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)}>
|
||||
<img src="/free-tools/pomodoro/menu-icon.svg" alt="Menu icon" class="w-5" />
|
||||
</button>
|
||||
|
||||
{#if todo.isVisible}
|
||||
<ul
|
||||
class="z-40 absolute top-6 -right-3 text-xs w-[8rem] bg-white border shadow-md rounded-[5px]"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => markTodoAsDone(i)}
|
||||
class="w-full font-medium text-left py-3 px-5"
|
||||
>
|
||||
Mark as done
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => deleteTodo(i)}
|
||||
class="w-full font-medium text-left py-3 px-5 bg-red-600 text-white rounded-b-[5px]"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center mt-10">
|
||||
<p
|
||||
class="rounded-[3px] text-xs font-medium text-[#656565] bg-[#EAEAEA] py-0.5 px-1.5"
|
||||
>
|
||||
{todo.time}
|
||||
</p>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => {
|
||||
if (todo.isPaused) {
|
||||
startCountdown();
|
||||
} else {
|
||||
pauseCountdown();
|
||||
}
|
||||
|
||||
todo.isPaused = !todo.isPaused;
|
||||
}}
|
||||
class="{todo.isDone
|
||||
? 'bg-[#00D06C] border-none text-white'
|
||||
: todo.isPaused
|
||||
? 'bg-white text-[#0D4CFF] border-[#0D4CFF]'
|
||||
: 'bg-[#0D4CFF] text-white border-none'}
|
||||
|
||||
flex items-center border-2 justify-center gap-2 py-1.5 px-4 rounded-[4px] text-xs font-bold uppercase"
|
||||
>
|
||||
{#if todo.isDone}
|
||||
<img src="/free-tools/pomodoro/done-icon.svg" alt="Done icon" />
|
||||
done
|
||||
{:else if todo.isPaused}
|
||||
<img src="/free-tools/pomodoro/list-play-icon.svg" alt="Play icon" />
|
||||
play task
|
||||
{:else}
|
||||
<img src="/free-tools/pomodoro/pause-icon.svg" alt="Pause icon" />
|
||||
pause task
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- todo button -->
|
||||
<button
|
||||
type="button"
|
||||
on:click={addTodo}
|
||||
class="bg-[#1D4ED8] rounded-md text-center font-medium mt-10 py-3 w-full flex justify-center items-center gap-3"
|
||||
>
|
||||
Add new item
|
||||
<img src="/free-tools/pomodoro/add-icon.svg" alt="Add icon" class="w-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:[email protected]&display=swap');
|
||||
|
||||
.body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,426 @@
|
||||
<script lang="ts">
|
||||
import { LogoFacebook, LogoLinkedin } from 'carbon-icons-svelte';
|
||||
import { onDestroy } from 'svelte';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { sineInOut } from 'svelte/easing';
|
||||
import Mood from './components/Mood.svelte';
|
||||
import ToolsHeader from '$lib/ToolsHeader/ToolsHeader.svelte';
|
||||
import Avatar from './components/Avatar.svelte';
|
||||
import Background from './components/Background.svelte';
|
||||
import Report from './components/Report.svelte';
|
||||
import FullView from './components/FullView.svelte';
|
||||
import DownloadButton from './components/DownloadButton.svelte';
|
||||
import { htmlBody, type HtmlBody, openModal, isFormComplete } from './components/store';
|
||||
|
||||
const MAX_CHARS = 160;
|
||||
let remainingChars = MAX_CHARS;
|
||||
let showReport: boolean = false;
|
||||
let showSetter: boolean = true;
|
||||
let isDownloading: boolean = false;
|
||||
let isDisabled: boolean;
|
||||
|
||||
// sets the result of the mini validation for the htmlBody store
|
||||
const unsubscribe = isFormComplete.subscribe((value) => {
|
||||
isDisabled = value;
|
||||
});
|
||||
|
||||
function handleInputChange(event: any, property: keyof HtmlBody) {
|
||||
$htmlBody[property] = event.target.value;
|
||||
|
||||
if (property === 'learning') {
|
||||
remainingChars = MAX_CHARS - event.target.value.length;
|
||||
}
|
||||
}
|
||||
|
||||
function shareTemplate() {
|
||||
return encodeURIComponent(
|
||||
`Learning Progress Update: ${$htmlBody.learning} and I'm ${$htmlBody.mood.text}. \nGenerated yours on classroomio.com\n`
|
||||
);
|
||||
}
|
||||
|
||||
function shareOnTwitter() {
|
||||
const text = shareTemplate();
|
||||
const hashtags = encodeURIComponent('classroomIO,progressReport');
|
||||
const url = `https://x.com/intent/post?text=${text}&hashtags=${hashtags}`;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
function shareOnFacebook() {
|
||||
const text = shareTemplate();
|
||||
window.open(
|
||||
`https://www.facebook.com/dialog/share?app_id=145634995501895&display=popup&href=https%3A%2F%2Fclassroomio.com%2Fdocs%2F&redirect_uri=https%3A%2F%2Fclassroomio.com%2Ftools%2Fexplorer&hashtag=${text}`
|
||||
);
|
||||
}
|
||||
|
||||
function shareOnLinkedIn() {
|
||||
const text = shareTemplate();
|
||||
const url = `http://www.linkedin.com/shareArticle?summary=${text}&text=${text}`;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
unsubscribe();
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Random Name Picker | ClassroomIO</title>
|
||||
<meta
|
||||
property="og:image"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
<meta property="og:title" content="Random Name Picker | ClassroomIO" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Use this online name picker to draw a random name from a list of names for your online or physical classroom."
|
||||
/>
|
||||
|
||||
<meta
|
||||
property="og:image:secure_url"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
|
||||
<meta name="twitter:title" content="Random Name Picker | ClassroomIO" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Use this online name picker to draw a random name from a list of names for your online or physical classroom."
|
||||
/>
|
||||
<meta name="twitter:image" content="https://brand.cdn.clsrio.com/og/free-tools.png" />
|
||||
</svelte:head>
|
||||
|
||||
<section class="mt-[10%] md:mt-16 px-1 md:px-0 w-full md:w-full">
|
||||
<ToolsHeader>
|
||||
<img
|
||||
src="/free-tools/progress-report.svg"
|
||||
class="w-[15%] md:w-[5%] mx-auto border rounded-full"
|
||||
alt=""
|
||||
/>
|
||||
<h1 class="text-4xl md:text-6xl font-bold text-[#040F2D] my-3">Progress Report</h1>
|
||||
<p class="text-md text-[#656565] font-light md:font-normal md:w-[45%] mx-auto">
|
||||
Generate cool reports of your learning progress. Share reports with your network for
|
||||
collaborative learning
|
||||
</p>
|
||||
</ToolsHeader>
|
||||
|
||||
<!-- modals -->
|
||||
<Avatar />
|
||||
<Mood />
|
||||
<Background />
|
||||
<FullView />
|
||||
|
||||
<div
|
||||
class="border rounded-md w-full md:w-11/12 lg:w-[80%] my-10 mx-auto shadow-md flex md:flex-row flex-col justify-evenly"
|
||||
>
|
||||
<!-- left side -->
|
||||
{#if showSetter}
|
||||
<div
|
||||
transition:fly={{ y: 100, easing: sineInOut }}
|
||||
class="w-full mx-auto md:w-[48%] md:max-w-[500px] p-5 md:border-r"
|
||||
>
|
||||
<!-- preview button -->
|
||||
<div class="flex md:hidden justify-end mb-5">
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => {
|
||||
showSetter = false;
|
||||
showReport = true;
|
||||
}}
|
||||
class="flex justify-between items-center gap-2 px-3 py-1 rounded-full text-white text-xs bg-[#0233BD]"
|
||||
>
|
||||
<img
|
||||
src="/free-tools/progress-report/preview-icon.svg"
|
||||
alt="preview icon"
|
||||
class="w-4"
|
||||
/>
|
||||
Preview
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- name input -->
|
||||
<div>
|
||||
<p class="text-sm text-[#656565]">Add your name</p>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={$htmlBody.name}
|
||||
on:input={(event) => handleInputChange(event, 'name')}
|
||||
placeholder="Enter your name here"
|
||||
class="w-full border my-3 py-2 px-3 outline-none rounded-sm bg-[#F1F2F4] text-xs placeholder:text-sm placeholder:text-[#ADADAD]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- mood input -->
|
||||
<div class="mt-3">
|
||||
<p class="text-sm text-[#656565]">Select your mood</p>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => ($openModal.mood = true)}
|
||||
class="w-full flex justify-between items-center border my-3 py-2 px-3 outline-none rounded-sm bg-[#F1F2F4] text-gray-400 text-sm"
|
||||
>
|
||||
{#if $htmlBody.mood.text}
|
||||
<div
|
||||
class="px-3 py-1 border border-[#EDEDED] text-white bg-blue-500 rounded-2xl font-semibold text-[7px] md:text-xs flex items-center justify-between"
|
||||
>
|
||||
{#if $htmlBody.mood.text}
|
||||
<span class="flex gap-1 items-center">
|
||||
<p class="font-semibold text-[9px] md:text-xs">is {$htmlBody.mood.text}</p>
|
||||
<img
|
||||
src="https://assets.cdn.clsrio.com/progress-report/emojis/{$htmlBody.mood
|
||||
.iconSrc}.png"
|
||||
alt={$htmlBody.mood.text}
|
||||
class="w-3"
|
||||
/>
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
What feeling describes you?
|
||||
<img
|
||||
src="/free-tools/progress-report/smiley-face-icon.svg"
|
||||
alt="smiley face"
|
||||
class="w-3"
|
||||
/>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- learning input -->
|
||||
<div class="mt-5">
|
||||
<p class="text-sm text-[#656565]">What are you learning?</p>
|
||||
<textarea
|
||||
bind:value={$htmlBody.learning}
|
||||
maxlength={MAX_CHARS}
|
||||
on:input={(event) => handleInputChange(event, 'learning')}
|
||||
placeholder="Tell us what you are learning"
|
||||
class="w-full h-[17vh] border my-3 py-2 px-3 outline-none rounded-sm bg-[#F1F2F4] text-sm placeholder:text-sm placeholder:text-[#ADADAD]"
|
||||
></textarea>
|
||||
<p class="text-xs text-right text-[#656565]">{remainingChars} characters remaining</p>
|
||||
</div>
|
||||
|
||||
<!-- range input -->
|
||||
<div class="mt-3">
|
||||
<p class="text-sm text-[#656565] pb-4">Estimate your progress</p>
|
||||
<div class="flex justify-between items-center">
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
bind:value={$htmlBody.progress}
|
||||
class="range-input"
|
||||
on:input={(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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- avatar button -->
|
||||
<div class="flex flex-wrap justify-between items-center mt-3">
|
||||
<div class="w-full md:w-2/4">
|
||||
<p class="text-[12px] md:text-sm text-[#656565]">Choose your avatar</p>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => ($openModal.avatar = true)}
|
||||
class="bg-[#F7F7F7] w-full py-1.5 px-5 md:px-0 mt-3 flex md:w-[65%] items-center justify-between md:justify-center gap-2"
|
||||
>
|
||||
<img
|
||||
src={`https://assets.cdn.clsrio.com/progress-report/avatars/${
|
||||
$htmlBody.avatar || 'avatar_m'
|
||||
}.svg`}
|
||||
alt=""
|
||||
class="w-[15%] md:w-[30%]"
|
||||
/>
|
||||
<img
|
||||
src="/free-tools/progress-report/question-mark.svg"
|
||||
alt="A question mark"
|
||||
class="w-[15%] md:w-[30%]"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- & background -->
|
||||
<div class="w-full md:w-2/4">
|
||||
<p class="text-[12px] md:text-sm text-[#656565]">Choose your background</p>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => ($openModal.background = true)}
|
||||
class="bg-[#F7F7F7] w-full py-1.5 px-5 md:px-0 mt-3 flex md:w-[65%] items-center justify-between md:justify-center gap-2"
|
||||
>
|
||||
<img
|
||||
src={`https://assets.cdn.clsrio.com/progress-report/backgrounds/${
|
||||
$htmlBody.background || 'blue_tetiary_background'
|
||||
}.webp`}
|
||||
alt="An avatar"
|
||||
class="w-[15%] md:w-[30%]"
|
||||
/>
|
||||
<img
|
||||
src="/free-tools/progress-report/question-mark.svg"
|
||||
alt="A question mark"
|
||||
class="w-[15%] md:w-[30%]"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<DownloadButton {isDisabled} {isDownloading} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- right side -->
|
||||
|
||||
<div
|
||||
transition:fly={{ y: 100, easing: sineInOut }}
|
||||
class="w-full mx-auto md:w-[48%] md:min-w-[400px] md:max-w-[500px] px-5 md:px-1 md:mt-0 mt-5 md:p-5"
|
||||
>
|
||||
<div class="hidden md:block">
|
||||
<Report />
|
||||
|
||||
<!-- download & share button -->
|
||||
<div class="mt-9 pt-8 px-2 h-auto border-t">
|
||||
<DownloadButton {isDisabled} {isDownloading} text="Download Image" />
|
||||
|
||||
<!-- share button -->
|
||||
<div class="w-full md:w-[70%] mx-auto my-5">
|
||||
<h1 class="text-sm font-semibold text-center">Share on image on social media:</h1>
|
||||
|
||||
<div
|
||||
class="flex justify-evenly border rounded-xl gap-5 w-[60%] md:w-[80%] px-5 py-2 mt-2 mx-auto"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={shareOnFacebook}
|
||||
class="w-10 hover:scale-[1.2] transition-all duration-300"
|
||||
>
|
||||
<LogoFacebook size={32} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={shareOnLinkedIn}
|
||||
class="w-10 hover:scale-[1.2] transition-all duration-300"
|
||||
>
|
||||
<LogoLinkedin size={32} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={shareOnTwitter}
|
||||
class="w-5 hover:scale-[1.2] transition-all duration-300"
|
||||
>
|
||||
<img src="/twitter_logo.png" alt="X.com" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if showReport}
|
||||
<!-- hide button -->
|
||||
<div class="flex justify-end mb-5">
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => {
|
||||
showReport = false;
|
||||
showSetter = true;
|
||||
}}
|
||||
class="flex justify-between items-center gap-2 px-3 py-1 rounded-full text-white text-xs bg-[#0233BD]"
|
||||
>
|
||||
<img src="/free-tools/progress-report/hide-icon.svg" alt="preview icon" class="w-4" />
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
<Report />
|
||||
|
||||
<!-- download & share button -->
|
||||
<div class="mt-9 pt-8 px-2 h-auto border-t">
|
||||
<DownloadButton {isDisabled} {isDownloading} />
|
||||
|
||||
<!-- share button -->
|
||||
<div class="w-full md:w-[70%] mx-auto my-5">
|
||||
<h1 class="text-sm font-semibold text-center">Share on image on social media:</h1>
|
||||
|
||||
<div
|
||||
class="flex justify-evenly border rounded-xl gap-5 w-[60%] md:w-[80%] px-5 py-2 mt-2 mx-auto"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={shareOnFacebook}
|
||||
class="w-10 hover:scale-[1.2] transition-all duration-300"
|
||||
>
|
||||
<LogoFacebook size={32} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={shareOnLinkedIn}
|
||||
class="w-10 hover:scale-[1.2] transition-all duration-300"
|
||||
>
|
||||
<LogoLinkedin size={32} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={shareOnTwitter}
|
||||
class="w-5 hover:scale-[1.2] transition-all duration-300"
|
||||
>
|
||||
<img src="/twitter_logo.png" alt="X.com" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.range-input {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 80%;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
border-radius: 15px;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.range-input::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
background-color: #0f62fe;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
transition: 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.range-input::-moz-range-thumb {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
background-color: yellow;
|
||||
border-radius: 50%;
|
||||
transition: 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.range-input:active::-webkit-slider-thumb {
|
||||
border: 3px solid #fff;
|
||||
filter: drop-shadow(0px 1px 1px #000000);
|
||||
}
|
||||
|
||||
.range-input:focus::-webkit-slider-thumb {
|
||||
border: 3px solid #fff;
|
||||
filter: drop-shadow(0px 1px 1px #000000);
|
||||
}
|
||||
|
||||
.range-input::-moz-range-thumb:hover {
|
||||
border: 3px solid #fff;
|
||||
box-shadow: 0 0 0 10px rgba(255, 85, 0, 0.1);
|
||||
}
|
||||
|
||||
.range-input:active::-moz-range-thumb {
|
||||
border: 3px solid #fff;
|
||||
filter: drop-shadow(0px 1px 1px #000000);
|
||||
}
|
||||
|
||||
.range-input:focus::-moz-range-thumb {
|
||||
border: 3px solid #fff;
|
||||
filter: drop-shadow(0px 1px 1px #000000);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,88 @@
|
||||
<script lang="ts">
|
||||
import { openModal, htmlBody } from './store';
|
||||
import Modal from '$lib/Modal/Modal.svelte';
|
||||
|
||||
interface Avatar {
|
||||
src: string;
|
||||
}
|
||||
|
||||
let isAddIcon = false;
|
||||
let hoveredIndex: number | null = null;
|
||||
|
||||
let avatars: Avatar[] = [
|
||||
{ src: 'avatar_a' },
|
||||
{ src: 'avatar_b' },
|
||||
{ src: 'avatar_c' },
|
||||
{ src: 'avatar_d' },
|
||||
{ src: 'avatar_e' },
|
||||
{ src: 'avatar_f' },
|
||||
{ src: 'avatar_g' },
|
||||
{ src: 'avatar_h' },
|
||||
{ src: 'avatar_i' },
|
||||
{ src: 'avatar_j' },
|
||||
{ src: 'avatar_k' },
|
||||
{ src: 'avatar_l' },
|
||||
{ src: 'avatar_m' },
|
||||
{ src: 'avatar_n' },
|
||||
{ src: 'avatar_o' },
|
||||
{ src: 'avatar_p' },
|
||||
{ src: 'avatar_q' },
|
||||
{ src: 'avatar_r' },
|
||||
{ src: 'avatar_s' },
|
||||
{ src: 'avatar_t' }
|
||||
];
|
||||
|
||||
function selectAvatar(avatar: Avatar) {
|
||||
$htmlBody.avatar = avatar.src;
|
||||
$openModal.avatar = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal bind:open={$openModal.avatar}>
|
||||
<!-- heading -->
|
||||
<div class="flex justify-between">
|
||||
<h1 class="text-sm font-semibold">Choose your Avatars</h1>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => ($openModal.avatar = false)}
|
||||
class="p-2 bg-[#F1F6FF] hover:scale-110 transition-all duration-300 rounded-full w-6"
|
||||
>
|
||||
<img src="/free-tools/progress-report/close-icon.svg" alt="Close icon" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- map for each avatar -->
|
||||
<div class="flex flex-wrap justify-evenly gap-y-3 mt-3">
|
||||
{#each avatars as avatar, index}
|
||||
<button
|
||||
on:click={() => {
|
||||
selectAvatar(avatar);
|
||||
}}
|
||||
on:mouseenter={() => {
|
||||
hoveredIndex = index;
|
||||
isAddIcon = true;
|
||||
}}
|
||||
on:mouseleave={() => {
|
||||
hoveredIndex = null;
|
||||
isAddIcon = false;
|
||||
}}
|
||||
class="relative w-[17%] flex justify-center items-center shadow-sm rounded-full hover:scale-110 transition-all duration-300"
|
||||
>
|
||||
<!-- + icon overlay -->
|
||||
{#if isAddIcon && hoveredIndex === index}
|
||||
<div
|
||||
class="w-full h-full flex justify-center items-center bg-white border absolute rounded-full opacity-[0.7] blur-md"
|
||||
></div>
|
||||
<img src="/free-tools/progress-report/hover-plus-icon.svg" alt="" class="absolute" />
|
||||
{/if}
|
||||
<!-- avatar -->
|
||||
<img
|
||||
src="https://assets.cdn.clsrio.com/progress-report/avatar/{avatar.src}.svg"
|
||||
alt=""
|
||||
class="w-full"
|
||||
/>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<!-- -->
|
||||
</Modal>
|
||||
@@ -0,0 +1,87 @@
|
||||
<script lang="ts">
|
||||
import Modal from '$lib/Modal/Modal.svelte';
|
||||
import { htmlBody, openModal } from './store';
|
||||
|
||||
interface Background {
|
||||
src: string;
|
||||
}
|
||||
|
||||
let backgrounds: Background[] = [
|
||||
{
|
||||
src: 'blue_tetiary_background'
|
||||
},
|
||||
{
|
||||
src: 'blue_secondary_background'
|
||||
},
|
||||
{
|
||||
src: 'blue_primary_background'
|
||||
},
|
||||
{
|
||||
src: 'purple_tetiary_background'
|
||||
},
|
||||
{
|
||||
src: 'purple_secondary_background'
|
||||
},
|
||||
{
|
||||
src: 'purple_primary_background'
|
||||
},
|
||||
{
|
||||
src: 'black_tetiary_background'
|
||||
},
|
||||
{
|
||||
src: 'black_secondary_background'
|
||||
},
|
||||
{
|
||||
src: 'black_primary_background'
|
||||
},
|
||||
{
|
||||
src: 'yellow_tetiary_background'
|
||||
},
|
||||
{
|
||||
src: 'yellow_secondary_background'
|
||||
},
|
||||
{
|
||||
src: 'yellow_primary_background'
|
||||
}
|
||||
];
|
||||
|
||||
function selectBackground(background: Background) {
|
||||
$htmlBody.background = background.src;
|
||||
$openModal.background = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal className="h-full max-h-[60vh]" bind:open={$openModal.background}>
|
||||
<!-- -->
|
||||
<div class="flex justify-between">
|
||||
<h1 class="text-sm font-semibold">Choose your Background</h1>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => ($openModal.background = false)}
|
||||
class="p-2 bg-[#F1F6FF] hover:scale-110 transition-all duration-300 rounded-full w-6"
|
||||
>
|
||||
<img src="/free-tools/progress-report/close-icon.svg" alt="Close icon" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- -->
|
||||
<div
|
||||
class="flex flex-wrap justify-between gap-y-3 mt-3 overflow-y-auto overflow-x-hidden h-[85%]"
|
||||
>
|
||||
{#each backgrounds as background}
|
||||
<button
|
||||
on:click={() => {
|
||||
selectBackground(background);
|
||||
}}
|
||||
class="flex w-[30%] items-center shadow-sm hover:scale-110 transition-all duration-300"
|
||||
>
|
||||
<img
|
||||
src="https://assets.cdn.clsrio.com/progress-report/backgrounds/{background.src}.webp"
|
||||
alt=""
|
||||
class=""
|
||||
/>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<!-- -->
|
||||
</Modal>
|
||||
@@ -0,0 +1,52 @@
|
||||
<script lang="ts">
|
||||
import { toPng } from 'html-to-image';
|
||||
import { nodeStore, htmlBody, openModal } from './store';
|
||||
|
||||
export let isDisabled: boolean;
|
||||
export let isDownloading: boolean;
|
||||
export let text: string = 'Generate Progress Report';
|
||||
|
||||
function convertToPng() {
|
||||
isDownloading = true;
|
||||
$openModal.showFullscreenButton = false;
|
||||
|
||||
const fileName = `${$htmlBody.name} - ${$htmlBody.mood.text} (ClassroomIO_com)`;
|
||||
|
||||
if ($nodeStore) {
|
||||
setTimeout(() => {
|
||||
toPng($nodeStore, {
|
||||
width: 500,
|
||||
height: 500,
|
||||
quality: 1
|
||||
})
|
||||
.then((dataUrl) => {
|
||||
const link = document.createElement('a');
|
||||
link.download = fileName;
|
||||
link.href = dataUrl;
|
||||
link.click();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Oops, something went wrong!', error);
|
||||
})
|
||||
.finally(() => {
|
||||
isDownloading = false;
|
||||
$openModal.showFullscreenButton = true;
|
||||
});
|
||||
}, 300);
|
||||
} else {
|
||||
console.error('Node is not defined');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
disabled={isDownloading || !isDisabled ? true : false}
|
||||
on:click={convertToPng}
|
||||
class="{isDownloading || !isDisabled
|
||||
? 'bg-gray-200 cursor-not-allowed text-gray-600'
|
||||
: 'bg-[#0233BD] text-white'} {text === 'Generate Progress Report'
|
||||
? 'block md:hidden'
|
||||
: ''} mt-5 transition-all delay-100 text-white text-xs font-semibold w-full py-3 rounded-md"
|
||||
>{isDownloading ? 'Loading...' : text}</button
|
||||
>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import Modal from '$lib/Modal/Modal.svelte';
|
||||
import Report from './Report.svelte';
|
||||
import { openModal } from './store';
|
||||
</script>
|
||||
|
||||
<Modal bind:open={$openModal.fullscreen}>
|
||||
<!-- -->
|
||||
<Report />
|
||||
<!-- -->
|
||||
</Modal>
|
||||
@@ -0,0 +1,100 @@
|
||||
<script lang="ts">
|
||||
import Modal from '$lib/Modal/Modal.svelte';
|
||||
import { htmlBody, openModal } from './store';
|
||||
|
||||
interface Mood {
|
||||
text: string;
|
||||
iconSrc: string;
|
||||
}
|
||||
|
||||
let moods: Mood[] = [
|
||||
{
|
||||
text: 'Unmotivated',
|
||||
iconSrc: 'unmotivated'
|
||||
},
|
||||
{
|
||||
text: 'Feeling Enlightened',
|
||||
iconSrc: 'feeling-enlightened'
|
||||
},
|
||||
{
|
||||
text: 'Enthusiastic',
|
||||
iconSrc: 'enthusiastic'
|
||||
},
|
||||
{
|
||||
text: 'Confused',
|
||||
iconSrc: 'confused'
|
||||
},
|
||||
{
|
||||
text: 'Feeling stuck',
|
||||
iconSrc: 'feeling-stuck'
|
||||
},
|
||||
// {
|
||||
// text: 'Believing in the process',
|
||||
// iconSrc: 'believing-in-the-process'
|
||||
// },
|
||||
{
|
||||
text: 'Curious',
|
||||
iconSrc: 'curious'
|
||||
},
|
||||
{
|
||||
text: 'Achieving Mastery',
|
||||
iconSrc: 'achieving-mastery'
|
||||
},
|
||||
{
|
||||
text: 'Feeling Positive',
|
||||
iconSrc: 'feeling-positive'
|
||||
},
|
||||
{
|
||||
text: 'Reflecting',
|
||||
iconSrc: 'reflecting'
|
||||
},
|
||||
{
|
||||
text: 'Making progress',
|
||||
iconSrc: 'progress'
|
||||
},
|
||||
{
|
||||
text: 'Feeling Sad',
|
||||
iconSrc: 'sad'
|
||||
}
|
||||
];
|
||||
|
||||
function selectMood(mood: Mood) {
|
||||
$htmlBody.mood.text = mood.text;
|
||||
$htmlBody.mood.iconSrc = mood.iconSrc;
|
||||
$openModal.mood = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal bind:open={$openModal.mood}>
|
||||
<!-- header -->
|
||||
<div class="flex justify-between">
|
||||
<h1 class="text-sm font-semibold">Choose your Mood</h1>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => ($openModal.mood = false)}
|
||||
class="p-2 bg-[#F1F6FF] hover:scale-110 transition-all duration-300 rounded-full w-6"
|
||||
>
|
||||
<img src="/free-tools/progress-report/close-icon.svg" alt="Close icon" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- mapping -->
|
||||
<div class="flex flex-wrap justify-between gap-y-3 mt-3">
|
||||
{#each moods as mood}
|
||||
<button
|
||||
on:click={() => {
|
||||
selectMood(mood);
|
||||
}}
|
||||
class="flex gap-3 items-center shadow-sm rounded-full px-4 py-1 bg-[#F1F6FF] hover:bg-[#0233BD] hover:text-white transition-all duration-700"
|
||||
>
|
||||
<p class="text-xs md:text-sm font-semibold">{mood.text}</p>
|
||||
<img
|
||||
src="https://assets.cdn.clsrio.com/progress-report/emojis/{mood.iconSrc}.png"
|
||||
alt={mood.text}
|
||||
class="w-4"
|
||||
/>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<!-- -->
|
||||
</Modal>
|
||||
@@ -0,0 +1,142 @@
|
||||
<script lang="ts">
|
||||
import { htmlBody, nodeStore, openModal } from './store';
|
||||
|
||||
import { derived } from 'svelte/store';
|
||||
|
||||
const colorMap = {
|
||||
blue_tetiary_background: '#0542CC',
|
||||
blue_secondary_background: '#0542CC',
|
||||
blue_primary_background: '#0542CC',
|
||||
purple_tetiary_background: '#9D4EDD',
|
||||
purple_secondary_background: '#9D4EDD',
|
||||
purple_primary_background: '#9D4EDD',
|
||||
black_tetiary_background: '#252525',
|
||||
black_secondary_background: '#252525',
|
||||
black_primary_background: '#252525',
|
||||
yellow_tetiary_background: '#FFBC42',
|
||||
yellow_secondary_background: '#FFBC42',
|
||||
yellow_primary_background: '#FFBC42'
|
||||
};
|
||||
|
||||
type ColorMapKey = keyof typeof colorMap;
|
||||
|
||||
const backgroundColor = derived(htmlBody, ($htmlBody) => {
|
||||
return colorMap[$htmlBody.background as ColorMapKey] || '#1e5ed2';
|
||||
});
|
||||
|
||||
let node: any;
|
||||
|
||||
$: nodeStore.set(node);
|
||||
|
||||
$: rootBgImage = `https://assets.cdn.clsrio.com/progress-report/backgrounds/${
|
||||
$htmlBody.background || 'blue_tetiary_background'
|
||||
}.webp`;
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="h-full min-h-[500px] max-h-[500px] md:h-[60vh] w-full border relative flex items-center justify-center"
|
||||
style={`font-family: "Space Grotesk", sans-serif; background-image: url('${rootBgImage}'); background-size: cover; background-repeat: no-repeat`}
|
||||
bind:this={node}
|
||||
>
|
||||
<!-- fullscreen button -->
|
||||
{#if $openModal.showFullscreenButton}
|
||||
{#if $openModal.fullscreen}
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => ($openModal.fullscreen = !$openModal.fullscreen)}
|
||||
class="absolute top-4 right-4 p-1.5 rounded-full hover:scale-90 transition-all duration-300 bg-white"
|
||||
>
|
||||
<img src="/free-tools/progress-report/close-icon.svg" alt="" class="" />
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => ($openModal.fullscreen = !$openModal.fullscreen)}
|
||||
class="absolute top-4 right-4 w-7 hover:scale-90 transition-all duration-300"
|
||||
>
|
||||
<img src="/free-tools/progress-report/full-screen-icon.svg" alt="" class="" />
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<div class="mt-20">
|
||||
<!-- using both md & lg for the width here because the lib doesn't consider md to be medium screens and above, using md alone will make the output break on desktop so i had to also specify for large screens -->
|
||||
<div
|
||||
class="rounded-lg shadow-md bg-white border-4 border-gray-100 z-20 mx-auto flex justify-center items-center w-[16rem] h-[16rem]"
|
||||
>
|
||||
<div class="relative w-full h-full flex flex-col justify-center gap-3 items-center px-2">
|
||||
<!-- avatar -->
|
||||
<img
|
||||
src={`https://assets.cdn.clsrio.com/progress-report/avatar/${
|
||||
$htmlBody.avatar || 'avatar_a'
|
||||
}.svg`}
|
||||
alt=""
|
||||
class="absolute top-0 w-[25%] h-[25%] ml-2 -mt-[2.2rem]"
|
||||
/>
|
||||
|
||||
<!-- mood -->
|
||||
{#if $htmlBody.name || $htmlBody.mood.text}
|
||||
<div
|
||||
style="background-color: {$backgroundColor}; color: white; display: flex;"
|
||||
class="px-3 py-0.5 border border-[#EDEDED] rounded-2xl mt-6 md:mt-3 font-semibold text-[10px] md:text-[0.7rem] flex items-center justify-between"
|
||||
>
|
||||
<span class="mr-0.5">{$htmlBody.name}</span>
|
||||
|
||||
{#if $htmlBody.mood.text}
|
||||
<span class="flex gap-1 items-center">
|
||||
<p class="font-semibold text-[10px] md:text-[0.7rem]">
|
||||
is {$htmlBody.mood.text}
|
||||
</p>
|
||||
<img
|
||||
src="https://assets.cdn.clsrio.com/progress-report/emojis/{$htmlBody.mood
|
||||
.iconSrc}.png"
|
||||
alt={$htmlBody.mood.text}
|
||||
class="w-3"
|
||||
/>
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<p
|
||||
style="background-color: {$backgroundColor}"
|
||||
class="px-3 py-0.5 border border-[#EDEDED] text-white rounded-2xl mt-3 font-medium text-[9px]"
|
||||
>
|
||||
Add your name
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<!-- learning -->
|
||||
<span
|
||||
class="w-full md:my-2 p-1 overflow-hidden text-[0.7rem] md:text-[0.8rem] font-normal text-center outline-none h-[10vh] md:h-[12vh]"
|
||||
>
|
||||
{$htmlBody.learning}
|
||||
</span>
|
||||
|
||||
<!-- progress -->
|
||||
<div class="flex flex-col justify-center items-center mb-2 md:mb-0">
|
||||
<div class="border border-[#d9e0f5] w-full h-4 rounded-full p-0.5 bg-[#f1f6ff]">
|
||||
<div
|
||||
class="progress-range rounded-full w-full h-full"
|
||||
style="background: {$backgroundColor}; width: {$htmlBody.progress}%"
|
||||
/>
|
||||
</div>
|
||||
<p class="text-[12px] font-semibold mt-1">Progress Achieved: {$htmlBody.progress}%</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="display: flex;"
|
||||
class="border mt-20 bottom-5 w-[50%] mx-auto flex gap-1 items-center justify-center bg-white rounded-md px-2 py-1"
|
||||
>
|
||||
<img src="/logo-192.png" alt="classroomio logo" class="w-4" />
|
||||
<p class="text-[10px] font-bold">ClassroomIO.com</p>
|
||||
</div>
|
||||
<!-- -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- importing font family -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:[email protected]&display=swap');
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import type { Writable } from 'svelte/store';
|
||||
|
||||
interface OpenModal {
|
||||
avatar: boolean;
|
||||
background: boolean;
|
||||
fullscreen: boolean;
|
||||
showFullscreenButton: boolean;
|
||||
mood: boolean;
|
||||
}
|
||||
|
||||
export interface HtmlBody {
|
||||
name: string;
|
||||
learning: string;
|
||||
progress: number;
|
||||
avatar: string;
|
||||
background: string;
|
||||
mood: {
|
||||
text: string;
|
||||
iconSrc: string;
|
||||
};
|
||||
}
|
||||
|
||||
// store for the node binded to the report component for the component to image conversion
|
||||
export const nodeStore = writable(null);
|
||||
|
||||
export const openModal: Writable<OpenModal> = writable({
|
||||
avatar: false,
|
||||
background: false,
|
||||
fullscreen: false,
|
||||
showFullscreenButton: true,
|
||||
mood: false
|
||||
});
|
||||
|
||||
const placeholderLearning = 'Tell us what you are learning';
|
||||
|
||||
// report html
|
||||
export const htmlBody: Writable<HtmlBody> = writable({
|
||||
name: '',
|
||||
learning: placeholderLearning,
|
||||
progress: 10,
|
||||
avatar: '',
|
||||
background: '',
|
||||
mood: {
|
||||
text: '',
|
||||
iconSrc: ''
|
||||
}
|
||||
});
|
||||
|
||||
// a mini validation for the htmlBody store that ensures all fields are filled
|
||||
export const isFormComplete = derived(htmlBody, ($htmlBody) => {
|
||||
return !!(
|
||||
$htmlBody.name.trim() &&
|
||||
$htmlBody.learning.trim() !== placeholderLearning &&
|
||||
$htmlBody.progress > 0 &&
|
||||
$htmlBody.mood.text.trim() &&
|
||||
$htmlBody.mood.iconSrc.trim()
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,240 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { sineInOut } from 'svelte/easing';
|
||||
import Timer from './components/Timer.svelte';
|
||||
import ToolsHeader from '$lib/ToolsHeader/ToolsHeader.svelte';
|
||||
|
||||
let timer: NodeJS.Timeout;
|
||||
let buzzSound: HTMLAudioElement;
|
||||
let isNextStep: boolean = false;
|
||||
let isPaused: boolean = false;
|
||||
let soundOn: boolean = true;
|
||||
|
||||
let hours: number = 0;
|
||||
let minutes: number = 0;
|
||||
let seconds: number = 0;
|
||||
|
||||
let activityName: string = '';
|
||||
let displayTime: string = '00:00:00';
|
||||
let totalSeconds: number = 0;
|
||||
let formattedTime: string = '00:00';
|
||||
|
||||
export function toggleTimer() {
|
||||
if (isPaused) {
|
||||
// Start or resume the timer
|
||||
isPaused = false;
|
||||
if (totalSeconds <= 0) {
|
||||
totalSeconds = hours * 3600 + minutes * 60 + seconds;
|
||||
}
|
||||
if (totalSeconds <= 0) {
|
||||
alert('Please set a valid timer.');
|
||||
isPaused = true;
|
||||
return;
|
||||
}
|
||||
timer = setInterval(() => {
|
||||
if (totalSeconds <= 0) {
|
||||
if (soundOn) {
|
||||
buzzSound.play();
|
||||
}
|
||||
clearInterval(timer);
|
||||
isPaused = true;
|
||||
} else {
|
||||
totalSeconds--;
|
||||
updateDisplayTime();
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
// Pause the timer
|
||||
clearInterval(timer);
|
||||
isPaused = true;
|
||||
}
|
||||
isNextStep = true;
|
||||
}
|
||||
|
||||
export function startTimer() {
|
||||
toggleTimer();
|
||||
totalSeconds = hours * 3600 + minutes * 60 + seconds;
|
||||
updateDisplayTime();
|
||||
}
|
||||
|
||||
function toggleSound() {
|
||||
soundOn = !soundOn;
|
||||
}
|
||||
|
||||
function updateDisplayTime() {
|
||||
const hrs = Math.floor(totalSeconds / 3600);
|
||||
const mins = Math.floor((totalSeconds % 3600) / 60);
|
||||
const secs = totalSeconds % 60;
|
||||
displayTime = `${String(hrs).padStart(2, '0')}:${String(mins).padStart(2, '0')}:${String(
|
||||
secs
|
||||
).padStart(2, '0')}`;
|
||||
|
||||
if (formattedTime === '00:00') {
|
||||
formattedTime = `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
||||
}
|
||||
}
|
||||
|
||||
function restartTimer() {
|
||||
clearInterval(timer);
|
||||
totalSeconds = hours * 3600 + minutes * 60 + seconds;
|
||||
if (totalSeconds <= 0) {
|
||||
alert('Please set a valid timer.');
|
||||
return;
|
||||
}
|
||||
isPaused = false;
|
||||
timer = setInterval(() => {
|
||||
if (totalSeconds <= 0) {
|
||||
if (soundOn) {
|
||||
buzzSound.play();
|
||||
}
|
||||
clearInterval(timer);
|
||||
} else {
|
||||
totalSeconds--;
|
||||
updateDisplayTime();
|
||||
}
|
||||
}, 1000);
|
||||
updateDisplayTime();
|
||||
}
|
||||
|
||||
function resetTimer() {
|
||||
isNextStep = false;
|
||||
clearInterval(timer);
|
||||
isPaused = false;
|
||||
hours = 0;
|
||||
minutes = 0;
|
||||
seconds = 0;
|
||||
totalSeconds = 0;
|
||||
activityName = '';
|
||||
displayTime = '00:00:00';
|
||||
formattedTime = '00:00';
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
buzzSound = new Audio('https://assets.cdn.clsrio.com/beeping-sound.mp3');
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Activity Stopwatch | ClassroomIO</title>
|
||||
<meta
|
||||
property="og:image"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
<meta property="og:title" content="Activity Stopwatch | ClassroomIO" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Stay on track with a customizable stopwatch for timed tasks, quizzes, and study sessions"
|
||||
/>
|
||||
|
||||
<meta
|
||||
property="og:image:secure_url"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
|
||||
<meta name="twitter:title" content="Activity Stopwatch | ClassroomIO" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Stay on track with a customizable stopwatch for timed tasks, quizzes, and study sessions"
|
||||
/>
|
||||
<meta name="twitter:image" content="https://brand.cdn.clsrio.com/og/free-tools.png" />
|
||||
</svelte:head>
|
||||
|
||||
<section class="mt-[10%] md:mt-16 px-5 md:px-0 bg-white">
|
||||
<ToolsHeader>
|
||||
<img
|
||||
src="/free-tools/name-picker.svg"
|
||||
class="w-[15%] md:w-[5%] mx-auto border rounded-full"
|
||||
alt=""
|
||||
/>
|
||||
<h1 class="text-4xl md:text-6xl font-bold text-[#040F2D] my-3">Activity Stopwatch</h1>
|
||||
<p class="text-md text-[#656565] font-light md:font-normal md:w-[45%] mx-auto">
|
||||
Stay on track and enhance productivity with our customizable stopwatch for timed tasks,
|
||||
quizzes, and study sessions.
|
||||
</p>
|
||||
</ToolsHeader>
|
||||
|
||||
<div class="w-full md:w-2/4 my-10 mx-auto border rounded-md overflow-hidden bg-white">
|
||||
<!-- countdown setter -->
|
||||
{#if !isNextStep}
|
||||
<div transition:fly={{ y: -300, delay: 0, easing: sineInOut }} class="px-6 py-8 bg-white">
|
||||
<form on:submit|preventDefault={startTimer}>
|
||||
<div>
|
||||
<h1 class="font-bold text-sm">Name of activity</h1>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={activityName}
|
||||
class="w-full rounded-sm border py-2 mt-3 bg-[#F1F2F4] outline-none px-3 focus-within:border-[#0233BD] focus-within:border"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 bg-white">
|
||||
<h1 class="font-bold text-sm">Set an Activity</h1>
|
||||
<div class="flex flex-wrap justify-between gap-y-5 w-full mt-3 uppercase font-bold">
|
||||
<div class="bg-[#F1F2F4] w-full md:w-[30%] border px-4 py-5">
|
||||
<div class="w-2/4 md:w-full mx-auto flex items-end gap-2">
|
||||
<input
|
||||
type="number"
|
||||
bind:value={hours}
|
||||
class="w-[80%] md:w-[75%] outline-none text-center py-3 px-1.5 text-3xl placeholder:text-3xl placeholder:text-black"
|
||||
/>
|
||||
<p class="text-[10px]">hrs</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-[#F1F2F4] w-full md:w-[30%] border px-4 py-5">
|
||||
<div class="w-2/4 md:w-full mx-auto flex items-end gap-2">
|
||||
<input
|
||||
type="number"
|
||||
bind:value={minutes}
|
||||
class="w-[80%] md:w-[75%] outline-none text-center py-3 px-1.5 text-3xl placeholder:text-3xl placeholder:text-black"
|
||||
/>
|
||||
<p class="text-[10px]">mins</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-[#F1F2F4] w-full md:w-[30%] border px-4 py-5">
|
||||
<div class="w-2/4 md:w-full mx-auto flex items-end gap-2">
|
||||
<input
|
||||
type="number"
|
||||
bind:value={seconds}
|
||||
class="w-[80%] md:w-[75%] outline-none text-center py-3 px-1.5 text-3xl placeholder:text-3xl placeholder:text-black"
|
||||
/>
|
||||
<p class="text-[10px]">sec</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end mt-10">
|
||||
<button
|
||||
type="submit"
|
||||
class="bg-[#0F62FE] text-white text-sm px-5 py-3 rounded-md flex gap-3 items-center"
|
||||
>
|
||||
<img src="/free-tools/stopwatch/loading-timer.svg" alt="" />
|
||||
Start Timer</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- countdown -->
|
||||
{#if isNextStep}
|
||||
<Timer
|
||||
{activityName}
|
||||
{formattedTime}
|
||||
{displayTime}
|
||||
{resetTimer}
|
||||
{toggleTimer}
|
||||
{toggleSound}
|
||||
{restartTimer}
|
||||
{isPaused}
|
||||
{soundOn}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script lang="ts">
|
||||
import { sineInOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
|
||||
export let activityName: string;
|
||||
export let formattedTime: string;
|
||||
export let displayTime: string;
|
||||
export let resetTimer: () => void;
|
||||
export let toggleSound: () => void;
|
||||
export let toggleTimer: () => void;
|
||||
export let restartTimer: () => void;
|
||||
export let isPaused: boolean;
|
||||
export let soundOn: boolean;
|
||||
</script>
|
||||
|
||||
<div transition:fly={{ y: 100, delay: 0, easing: sineInOut }}>
|
||||
<div class="px-6 pt-8 text-center">
|
||||
<button
|
||||
type="button"
|
||||
on:click={resetTimer}
|
||||
class="text-[10px] text-[#656565] font-semibold uppercase underline"
|
||||
>set timer for another activity</button
|
||||
>
|
||||
|
||||
<button
|
||||
class="border mx-auto mt-7 mb-3 px-2 py-0.5 rounded-full flex items-center gap-1 text-sm text-[#656565] font-semibold border-[#C2D2FF] bg-[#DCE5FF]"
|
||||
>
|
||||
{activityName}:
|
||||
<span class="text-[#0233BD]">{formattedTime}</span>
|
||||
</button>
|
||||
|
||||
<!-- countdown -->
|
||||
<h1 class="text-[#040F2D] mb-14 text-6xl font-bold">{displayTime}</h1>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<button
|
||||
type="button"
|
||||
on:click={toggleSound}
|
||||
class="bg-[#F7F7F7] w-[34%] flex flex-col gap-1 items-center uppercase text-[10px] py-5 md:py-10 rounded-bl-md hover:bg-[#F1F6FF] transition-all duration-500"
|
||||
>
|
||||
{#if soundOn}
|
||||
<img src="/free-tools/stopwatch/speaker-icon.svg" alt="" class="w-7 md:w-12" />
|
||||
{:else}
|
||||
<img src="/free-tools/stopwatch/no-speaker-icon.svg" alt="" class="w-7 md:w-12" />
|
||||
{/if}
|
||||
buzzer</button
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={toggleTimer}
|
||||
class="bg-[#0F62FE] text-white w-[34%] flex flex-col gap-1 items-center uppercase text-[10px] py-5 md:py-10"
|
||||
>
|
||||
{#if isPaused}
|
||||
<img src="/free-tools/stopwatch/play-icon.svg" alt="" class="w-7 md:w-12" />
|
||||
{:else}
|
||||
<img src="/free-tools/stopwatch/pause-icon.svg" alt="" class="w-7 md:w-12" />
|
||||
{/if}
|
||||
{isPaused ? 'play' : 'pause'}</button
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={restartTimer}
|
||||
class="bg-[#F7F7F7] w-[34%] flex flex-col gap-1 items-center uppercase text-[10px] py-5 md:py-10 rounded-br-md hover:bg-[#F1F6FF] transition-all duration-500"
|
||||
>
|
||||
<img src="/free-tools/stopwatch/reset-icon.svg" alt="" class="w-7 md:w-12" />
|
||||
restart</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,236 @@
|
||||
<script lang="ts">
|
||||
import { fly } from 'svelte/transition';
|
||||
import { sineInOut } from 'svelte/easing';
|
||||
import Board from './components/Board.svelte';
|
||||
import { TicTacToe } from './components/board';
|
||||
import { scores, changeToComputer } from './components/store';
|
||||
import ToolsHeader from '$lib/ToolsHeader/ToolsHeader.svelte';
|
||||
|
||||
let startGame = false;
|
||||
let message: string | null = null;
|
||||
let winner: Winner | null = null;
|
||||
let game = createGame();
|
||||
|
||||
interface Winner {
|
||||
symbol?: string;
|
||||
}
|
||||
|
||||
function createGame() {
|
||||
message = '';
|
||||
winner = null;
|
||||
|
||||
return TicTacToe({
|
||||
onWin(winnerInfo) {
|
||||
console.log('winner object', winnerInfo);
|
||||
winner = winnerInfo;
|
||||
|
||||
scores.update((currentScores) => {
|
||||
if (winner!.symbol === 'X') {
|
||||
return { ...currentScores, X: currentScores.X + 1 };
|
||||
} else if (winner!.symbol === 'O') {
|
||||
return { ...currentScores, O: currentScores.O + 1 };
|
||||
}
|
||||
return currentScores;
|
||||
});
|
||||
|
||||
if (winner!.symbol === 'O') {
|
||||
message = `Winner: Player 2 wins the round`;
|
||||
} else if (winner!.symbol === 'X') {
|
||||
message = `Winner: Player 1 wins the round`;
|
||||
}
|
||||
},
|
||||
|
||||
onTie() {
|
||||
message = `Tie game!`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function newGame() {
|
||||
// reset scores to zero
|
||||
scores.update(() => ({
|
||||
X: 0,
|
||||
O: 0,
|
||||
draw: 0
|
||||
}));
|
||||
|
||||
// disable ai
|
||||
$changeToComputer = { change: false };
|
||||
|
||||
// create a new game instance
|
||||
game = createGame();
|
||||
}
|
||||
|
||||
function playAgain() {
|
||||
message = '';
|
||||
// create a new game instance
|
||||
game = createGame();
|
||||
}
|
||||
|
||||
function changePlayer() {
|
||||
changeToComputer.update((value) => ({ change: !value.change }));
|
||||
}
|
||||
|
||||
function startTicTac() {
|
||||
startGame = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Tic Tac Toe | ClassroomIO</title>
|
||||
<meta
|
||||
property="og:image"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
<meta property="og:title" content="Tic Tac Toe | ClassroomIO" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="A simple and free tic tac toe game to play to your friends in class or outside the classroom."
|
||||
/>
|
||||
|
||||
<meta
|
||||
property="og:image:secure_url"
|
||||
itemprop="image"
|
||||
content="https://brand.cdn.clsrio.com/og/free-tools.png"
|
||||
/>
|
||||
|
||||
<meta name="twitter:title" content="Tic Tac Toe | ClassroomIO" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="A simple and free tic tac toe game to play to your friends in class or outside the classroom."
|
||||
/>
|
||||
<meta name="twitter:image" content="https://brand.cdn.clsrio.com/og/free-tools.png" />
|
||||
</svelte:head>
|
||||
|
||||
<section class="mt-[10%] md:mt-16 px-5 md:px-0 bg-white">
|
||||
<ToolsHeader className="mb-10">
|
||||
<img
|
||||
src="/free-tools/tic-tac.svg"
|
||||
class="w-14 md:w-[5%] mx-auto border rounded-full"
|
||||
alt="Tic Tac Icon"
|
||||
/>
|
||||
<h1 class="text-4xl md:text-6xl font-bold text-[#040F2D] my-3">Tic-Tac game</h1>
|
||||
<p class="text-md text-[#656565] font-light md:font-normal md:w-[45%] mx-auto">
|
||||
More than just a game; it's an educational tool that teaches pattern recognition, and
|
||||
decision-making.
|
||||
</p>
|
||||
</ToolsHeader>
|
||||
|
||||
<div
|
||||
class="overflow-hidden relative tic-tac-bg text-white w-full h-[55vh] md:w-[59%] md:h-[82vh] border-8 border-black mx-auto flex justify-center items-center bg-white"
|
||||
>
|
||||
<!-- congratulatory message -->
|
||||
{#if message}
|
||||
<div
|
||||
transition:fly={{ x: -100, delay: 600, easing: sineInOut }}
|
||||
class="absolute w-full top-[43%] flex flex-col justify-center items-center z-[150]"
|
||||
>
|
||||
<div
|
||||
class="flex gap-10 justify-center py-1 h-[8vh] md:h-[13vh] w-full items-center bg-white font-bold text-[#0233BD]"
|
||||
>
|
||||
{#if message != 'Tie game!'}
|
||||
<img src="/free-tools/tic-tac/winner-star-icon.svg" alt="Star icon" class="h-full" />
|
||||
{/if}
|
||||
<h2 class="md:text-base text-xs">{message}</h2>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
on:click={playAgain}
|
||||
class="px-16 pt-1 pb-1.5 md:text-base text-xs border border-white font-bold rounded-md mt-10 bg-[#0F62FE]"
|
||||
>Play Again</button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- this condition renders the game -->
|
||||
{#if startGame}
|
||||
<div class="w-full h-full p-5 flex flex-col border justify-between items-center">
|
||||
<header class="flex w-full items-center justify-between">
|
||||
<button
|
||||
on:click={changePlayer}
|
||||
class="text-[10px] md:text-xs w-[35%] gap-2 md:w-28 flex flex-row items-center leading-3 font-medium"
|
||||
>
|
||||
<img
|
||||
src="/free-tools/tic-tac/computer-icon.svg"
|
||||
alt="Computer icon"
|
||||
class="w-4 md:w-6"
|
||||
/>
|
||||
{#if $changeToComputer.change}
|
||||
Play two players
|
||||
{:else}
|
||||
Change to computer
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
on:click={newGame}
|
||||
class="text-[10px] w-24 flex flex-col gap-1 p-2 shadow-md rounded-md items-center leading-3 font-medium border text-[#0542CC] bg-white"
|
||||
>
|
||||
<img src="/free-tools/tic-tac/restart-icon.svg" alt="Restart icon" class="w-3 md:w-4" />
|
||||
Reset Score</button
|
||||
>
|
||||
</header>
|
||||
|
||||
<!-- board -->
|
||||
<Board {game} {winner} />
|
||||
|
||||
<!-- scores -->
|
||||
<div
|
||||
class="flex justify-between md:justify-center items-center gap-10 w-full text-white font-semibold"
|
||||
>
|
||||
<div class="md:text-3xl text-2xl flex items-center md:gap-5 gap-2">
|
||||
<span class="px-1 md:p-1 bg-[#FE28CB99] md:text-sm text-[10px]">Player 1</span>
|
||||
{$scores.X}
|
||||
</div>
|
||||
<div class="md:text-3xl text-2xl flex items-center md:gap-5 gap-2">
|
||||
<span class="px-1 md:p-1 bg-[#0F62FE] md:text-sm text-[10px]">Draw</span>
|
||||
{$scores.draw}
|
||||
</div>
|
||||
<div class="md:text-3xl text-2xl flex items-center md:gap-5 gap-2">
|
||||
<span class="px-1 md:p-1 bg-[#94F7FFB2] md:text-sm text-[10px]">Player 2</span>
|
||||
{$scores.O}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- this condition renders the homepage -->
|
||||
{:else}
|
||||
<div class="flex flex-col items-center gap-5">
|
||||
<img
|
||||
src="/free-tools/tic-tac/tic-tac-start-icon.svg"
|
||||
alt="Tic tac toe game icon"
|
||||
class="w-[50%] md:w-[70%]"
|
||||
/>
|
||||
<div class="flex flex-col gap-3">
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => {
|
||||
changePlayer();
|
||||
startTicTac();
|
||||
}}
|
||||
class="mt-5 px-[3.3rem] pt-1 pb-1.5 border border-white text-sm font-bold rounded-md bg-[#0F62FE]"
|
||||
>
|
||||
Play with computer</button
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => {
|
||||
startTicTac();
|
||||
}}
|
||||
class="px-16 pt-1 pb-1.5 border border-white text-sm font-bold rounded-md bg-[#0F62FE]"
|
||||
>Play two players</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.tic-tac-bg {
|
||||
background: url('/free-tools/tic-tac/tic-tac-bg.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,99 @@
|
||||
<script lang="ts">
|
||||
import { sineInOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
import WinningLine from './WinningLine.svelte';
|
||||
import { changeToComputer } from './store';
|
||||
|
||||
interface Game {
|
||||
board: Array<Array<string>>;
|
||||
click: (rowIndex: number, columnIndex: number) => Game;
|
||||
}
|
||||
|
||||
export let game: Game;
|
||||
export let winner = null;
|
||||
|
||||
let customDelay: number;
|
||||
|
||||
$: {
|
||||
if ($changeToComputer.change) {
|
||||
customDelay = 400;
|
||||
} else {
|
||||
customDelay = 0;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="relative">
|
||||
<table>
|
||||
<tbody>
|
||||
{#each game.board as row, rowIndex}
|
||||
<tr>
|
||||
{#each row as column, columnIndex}
|
||||
<td
|
||||
class="cursor-pointer text-center h-25 w-[1.5em] border-r-10 border-b-10 border-white last:border-r-0"
|
||||
on:click={() => {
|
||||
game = game.click(rowIndex, columnIndex);
|
||||
}}
|
||||
>
|
||||
{#if column === 'X'}
|
||||
<img
|
||||
transition:fly={{ y: 100, delay: 0, easing: sineInOut }}
|
||||
src="/free-tools/tic-tac/tic-tac-x.svg"
|
||||
alt="X icon"
|
||||
/>
|
||||
{:else if column === 'O'}
|
||||
<img
|
||||
transition:fly={{ y: 100, delay: customDelay, easing: sineInOut }}
|
||||
src="/free-tools/tic-tac/tic-tac-o.svg"
|
||||
alt="O icon"
|
||||
/>
|
||||
{:else}
|
||||
<!-- empty cell -->
|
||||
{/if}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<WinningLine {winner} />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
table {
|
||||
overflow: hidden;
|
||||
border-collapse: collapse;
|
||||
font-size: 4em;
|
||||
color: white;
|
||||
border: 0px;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
td {
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
border-right: 10px solid white;
|
||||
border-bottom: 10px solid white;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
td {
|
||||
width: 16vw;
|
||||
height: 16vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition';
|
||||
export let winner: Winner | null = null;
|
||||
|
||||
interface Winner {
|
||||
direction: 'horizontal' | 'vertical' | 'diagonal';
|
||||
row?: number;
|
||||
column?: number;
|
||||
diagonal?: 'top-left-to-bottom-right' | 'top-right-to-bottom-left';
|
||||
}
|
||||
|
||||
$: if (winner) {
|
||||
if (winner.direction === 'vertical' && winner.column !== undefined) {
|
||||
document.documentElement.style.setProperty('--col-index', winner.column.toString());
|
||||
} else if (winner.direction === 'horizontal' && winner.row !== undefined) {
|
||||
document.documentElement.style.setProperty('--row-index', winner.row.toString());
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if winner}
|
||||
<div
|
||||
transition:fade={{ delay: 500, duration: 2 }}
|
||||
class="winning-line absolute bg-[#ffc300] z-[100]"
|
||||
class:horizontal-line={winner.direction === 'horizontal'}
|
||||
class:vertical-line={winner.direction === 'vertical'}
|
||||
class:diagonal-line-1={winner.direction === 'diagonal' &&
|
||||
winner.diagonal === 'top-left-to-bottom-right'}
|
||||
class:diagonal-line-2={winner.direction === 'diagonal' &&
|
||||
winner.diagonal === 'top-right-to-bottom-left'}
|
||||
></div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.horizontal-line {
|
||||
top: calc(var(--row-index) * 100px + 50px - 5px);
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.vertical-line {
|
||||
top: 0;
|
||||
left: calc(var(--col-index) * 100px + 50px - 5px);
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.diagonal-line-1 {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 140%;
|
||||
height: 100%;
|
||||
background: none;
|
||||
border-top: 10px solid #ffc300;
|
||||
transform: rotate(45deg);
|
||||
transform-origin: top left;
|
||||
}
|
||||
|
||||
.diagonal-line-2 {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 140%;
|
||||
height: 100%;
|
||||
background: none;
|
||||
border-top: 10px solid #ffc300;
|
||||
transform: rotate(-45deg);
|
||||
transform-origin: top right;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.horizontal-line {
|
||||
top: calc(var(--row-index) * 16vw + 8vw - 5px);
|
||||
}
|
||||
|
||||
.vertical-line {
|
||||
left: calc(var(--col-index) * 16vw + 8vw - 5px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,178 @@
|
||||
import { scores, changeToComputer } from './store';
|
||||
|
||||
let activateComp = false;
|
||||
|
||||
changeToComputer.subscribe((value) => {
|
||||
if (value && value.change === true) {
|
||||
activateComp = true;
|
||||
} else {
|
||||
activateComp = false;
|
||||
}
|
||||
});
|
||||
|
||||
export function TicTacToe({ onWin, onTie }: { onWin: (winner: any) => void, onTie: () => void }) {
|
||||
const board = [
|
||||
['', '', ''],
|
||||
['', '', ''],
|
||||
['', '', '']
|
||||
];
|
||||
|
||||
let turn = 'X';
|
||||
let done = false;
|
||||
|
||||
return {
|
||||
board,
|
||||
|
||||
click(rowIndex:number, columnIndex:number) {
|
||||
if (!done && !board[rowIndex][columnIndex]) {
|
||||
board[rowIndex][columnIndex] = turn;
|
||||
turn = turn === 'X' ? 'O' : 'X';
|
||||
|
||||
const winner = getWinner(board);
|
||||
|
||||
if (winner) {
|
||||
onWin(winner);
|
||||
done = true;
|
||||
} else if (isBoardFull(board)) {
|
||||
onTie();
|
||||
scores.update((currentScores) => {
|
||||
return { ...currentScores, draw: currentScores.draw + 1 };
|
||||
});
|
||||
done = true;
|
||||
} else {
|
||||
if (activateComp) {
|
||||
const aiMove = getBestMove(board);
|
||||
if (aiMove) {
|
||||
board[aiMove.row][aiMove.column] = 'O';
|
||||
turn = 'X';
|
||||
|
||||
const aiWinner = getWinner(board);
|
||||
if (aiWinner) {
|
||||
onWin(aiWinner);
|
||||
done = true;
|
||||
} else if (isBoardFull(board)) {
|
||||
onTie();
|
||||
scores.update((currentScores) => {
|
||||
return { ...currentScores, draw: currentScores.draw + 1 };
|
||||
});
|
||||
done = true;
|
||||
}
|
||||
} else {
|
||||
console.error("AI could not find a valid move.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getWinner(board: string[][]) {
|
||||
// check rows
|
||||
for (let row = 0; row < 3; row++) {
|
||||
if (board[row][0] === board[row][1] && board[row][0] === board[row][2] && board[row][0]) {
|
||||
return { symbol: board[row][0], direction: 'horizontal', row };
|
||||
}
|
||||
}
|
||||
|
||||
// check columns
|
||||
for (let column = 0; column < 3; column++) {
|
||||
if (
|
||||
board[0][column] === board[1][column] &&
|
||||
board[0][column] === board[2][column] &&
|
||||
board[0][column]
|
||||
) {
|
||||
return { symbol: board[0][column], direction: 'vertical', column };
|
||||
}
|
||||
}
|
||||
|
||||
// check diagonals
|
||||
if (board[0][0] === board[1][1] && board[0][0] == board[2][2] && board[0][0]) {
|
||||
return { symbol: board[0][0], direction: 'diagonal', diagonal: 'top-left-to-bottom-right' };
|
||||
}
|
||||
|
||||
if (board[0][2] === board[1][1] && board[0][2] == board[2][0] && board[0][2]) {
|
||||
return { symbol: board[0][2], direction: 'diagonal', diagonal: 'top-right-to-bottom-left' };
|
||||
}
|
||||
|
||||
// no winner
|
||||
return null;
|
||||
}
|
||||
|
||||
function isBoardFull(board: string[][]) {
|
||||
for (let row = 0; row < 3; row++) {
|
||||
for (let column = 0; column < 3; column++) {
|
||||
if (!board[row][column]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getBestMove(board: string[][]) {
|
||||
let bestScore = -Infinity;
|
||||
let move;
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (let j = 0; j < 3; j++) {
|
||||
// check if cell is empty
|
||||
if (board[i][j] === '') {
|
||||
board[i][j] = 'O'; // make the move
|
||||
let score = minimax(board, 0, false); // call minimax on the new board
|
||||
board[i][j] = ''; // undo the move
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
move = { row: i, column: j };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
function minimax(board: string[][], depth: number, isMaximizing: boolean) {
|
||||
const result = getWinner(board);
|
||||
if (result !== null) {
|
||||
if (result.symbol === 'O') {
|
||||
return 10 - depth; // ai wins
|
||||
} else if (result.symbol === 'X') {
|
||||
return depth - 10; // player wins
|
||||
} else {
|
||||
return 0; // draw
|
||||
}
|
||||
}
|
||||
|
||||
if (isMaximizing) {
|
||||
let bestScore = -Infinity;
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (let j = 0; j < 3; j++) {
|
||||
if (board[i][j] === '') {
|
||||
board[i][j] = 'O';
|
||||
let score = minimax(board, depth + 1, false);
|
||||
board[i][j] = '';
|
||||
bestScore = Math.max(score, bestScore);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestScore;
|
||||
} else {
|
||||
let bestScore = Infinity;
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (let j = 0; j < 3; j++) {
|
||||
if (board[i][j] === '') {
|
||||
board[i][j] = 'X';
|
||||
let score = minimax(board, depth + 1, true);
|
||||
board[i][j] = '';
|
||||
bestScore = Math.min(score, bestScore);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestScore;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import type {Writable} from 'svelte/store'
|
||||
|
||||
interface Scores {
|
||||
X: number;
|
||||
O: number;
|
||||
draw: number;
|
||||
}
|
||||
|
||||
interface ChangeToComputer {
|
||||
change: boolean;
|
||||
}
|
||||
|
||||
export const scores: Writable<Scores> = writable({
|
||||
X: 0,
|
||||
O: 0,
|
||||
draw: 0
|
||||
});
|
||||
|
||||
export const changeToComputer: Writable<ChangeToComputer> = writable({
|
||||
change: false
|
||||
});
|
||||
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 261 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.534 10.3476C17.6489 10.2326 17.7202 10.0738 17.72 9.89838V8.10162C17.72 7.75035 17.4356 7.46598 17.0848 7.46643L10.5329 7.46643L10.5329 0.914537C10.5329 0.563268 10.2486 0.278901 9.89773 0.27935L8.10097 0.27935C7.7497 0.27935 7.46533 0.563717 7.46578 0.914537L7.46578 7.46643H0.913887C0.563067 7.46598 0.278251 7.7508 0.2787 8.10162V9.89838C0.2787 10.2497 0.563067 10.534 0.913887 10.5336H7.46578L7.46578 17.0855C7.46533 17.4363 7.75015 17.7211 8.10097 17.7206L9.89773 17.7206C10.249 17.7206 10.5334 17.4363 10.5329 17.0855L10.5329 10.5336L17.0848 10.5336C17.2604 10.5336 17.4191 10.4625 17.534 10.3476Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 736 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.5 0.0820312C4.46165 0.0820312 3.44662 0.389938 2.58326 0.966816C1.7199 1.54369 1.04699 2.36363 0.649635 3.32294C0.252275 4.28226 0.148307 5.33785 0.35088 6.35626C0.553452 7.37466 1.05347 8.31012 1.78769 9.04434C2.52192 9.77857 3.45738 10.2786 4.47578 10.4812C5.49418 10.6837 6.54978 10.5798 7.50909 10.1824C8.4684 9.78504 9.28834 9.11213 9.86522 8.24877C10.4421 7.38542 10.75 6.37038 10.75 5.33203C10.75 3.93964 10.1969 2.60429 9.21231 1.61972C8.22775 0.635155 6.89239 0.0820313 5.5 0.0820312ZM4.75 7.42858L2.875 5.55358L3.47148 4.95703L4.75 6.23548L7.52875 3.45703L8.12714 4.05174L4.75 7.42858Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 727 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="11" height="12" viewBox="0 0 11 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.4738 6C10.4742 6.15354 10.4348 6.30456 10.3596 6.43838C10.2843 6.57219 10.1757 6.68425 10.0442 6.76366L1.90008 11.7458C1.76278 11.8299 1.60551 11.8758 1.44453 11.8788C1.28356 11.8817 1.1247 11.8417 0.984376 11.7627C0.845386 11.685 0.729603 11.5717 0.648934 11.4344C0.568266 11.2971 0.525623 11.1408 0.525391 10.9816V1.01843C0.525623 0.859191 0.568266 0.702887 0.648934 0.565591C0.729603 0.428296 0.845386 0.314965 0.984376 0.237253C1.1247 0.158314 1.28356 0.118268 1.44453 0.121249C1.60551 0.12423 1.76278 0.170131 1.90008 0.25421L10.0442 5.23634C10.1757 5.31575 10.2843 5.42781 10.3596 5.56162C10.4348 5.69544 10.4742 5.84646 10.4738 6Z" fill="#0D4CFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 772 B |
@@ -0,0 +1,12 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_7053_33834)">
|
||||
<path d="M12 8.16797C12.8284 8.16797 13.5 7.4964 13.5 6.66797C13.5 5.83954 12.8284 5.16797 12 5.16797C11.1716 5.16797 10.5 5.83954 10.5 6.66797C10.5 7.4964 11.1716 8.16797 12 8.16797Z" fill="black"/>
|
||||
<path d="M12 14.168C12.8284 14.168 13.5 13.4964 13.5 12.668C13.5 11.8395 12.8284 11.168 12 11.168C11.1716 11.168 10.5 11.8395 10.5 12.668C10.5 13.4964 11.1716 14.168 12 14.168Z" fill="black"/>
|
||||
<path d="M12 20.168C12.8284 20.168 13.5 19.4964 13.5 18.668C13.5 17.8395 12.8284 17.168 12 17.168C11.1716 17.168 10.5 17.8395 10.5 18.668C10.5 19.4964 11.1716 20.168 12 20.168Z" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7053_33834">
|
||||
<rect width="24" height="24" fill="white" transform="translate(0 0.667969)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 871 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.625 3.70703C5.32663 3.70703 5.04048 3.82556 4.82951 4.03654C4.61853 4.24751 4.5 4.53366 4.5 4.83203V13.832C4.5 14.1304 4.61853 14.4165 4.82951 14.6275C5.04048 14.8385 5.32663 14.957 5.625 14.957H6.75C7.04837 14.957 7.33452 14.8385 7.5455 14.6275C7.75647 14.4165 7.875 14.1304 7.875 13.832V4.83203C7.875 4.53366 7.75647 4.24751 7.5455 4.03654C7.33452 3.82556 7.04837 3.70703 6.75 3.70703H5.625ZM11.25 3.70703C10.9516 3.70703 10.6655 3.82556 10.4545 4.03654C10.2435 4.24751 10.125 4.53366 10.125 4.83203V13.832C10.125 14.1304 10.2435 14.4165 10.4545 14.6275C10.6655 14.8385 10.9516 14.957 11.25 14.957H12.375C12.6734 14.957 12.9595 14.8385 13.1705 14.6275C13.3815 14.4165 13.5 14.1304 13.5 13.832V4.83203C13.5 4.53366 13.3815 4.24751 13.1705 4.03654C12.9595 3.82556 12.6734 3.70703 12.375 3.70703H11.25Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 973 B |
@@ -0,0 +1,11 @@
|
||||
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="26" height="22" transform="translate(0.166992 2.66797)" fill="white"/>
|
||||
<g clip-path="url(#clip0_7053_31561)">
|
||||
<path d="M21.3333 7.83724C22 7.17057 22 6.17057 21.3333 5.50391L18.3333 2.50391C17.6667 1.83724 16.6667 1.83724 16 2.50391L3.5 15.0039V20.3372H8.83333L21.3333 7.83724ZM17.1667 3.67057L20.1667 6.67057L17.6667 9.17057L14.6667 6.17057L17.1667 3.67057ZM5.16667 18.6706V15.6706L13.5 7.33724L16.5 10.3372L8.16667 18.6706H5.16667Z" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7053_31561">
|
||||
<rect width="26.6667" height="26.6667" fill="white" transform="translate(0.166992 0.335938)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 726 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="43" height="44" viewBox="0 0 43 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.42891 6.98399C9.60172 4.91159 12.2157 3.319 15.1044 2.3425C19.8714 0.73103 25.0616 0.907233 29.7084 2.83829C34.3552 4.76934 38.1419 8.3236 40.3635 12.8392C42.5851 17.3548 43.0902 22.524 41.7849 27.3843C40.4795 32.2446 37.4525 36.4649 33.2675 39.2593C29.0825 42.0537 24.0247 43.2317 19.0359 42.5739C14.0471 41.9161 9.4674 39.4674 6.14947 35.6838C2.83154 31.9001 1.00153 27.0395 1.0001 22.0069L1 21.6659C0.999872 21.2138 1.17934 20.7802 1.49893 20.4604C1.81851 20.1406 2.25204 19.9609 2.70413 19.9608L3.38597 19.9606C4.3274 19.9603 5.0908 20.7233 5.09107 21.6647L5.09116 22.0057C5.09231 26.0463 6.56159 29.9487 9.22534 32.9863C11.8891 36.0239 15.5658 37.9898 19.5707 38.5178C23.5757 39.0459 27.636 38.1002 30.9958 35.8568C34.3556 33.6135 36.7858 30.2253 37.8338 26.3231C38.8819 22.4209 38.4763 18.2707 36.6927 14.6453C34.909 11.0199 31.8689 8.16651 28.1385 6.61626C24.408 5.06601 20.2414 4.92456 16.4145 6.21824C13.796 7.10339 11.4587 8.61914 9.59481 10.608H15.0753C16.0167 10.608 16.7799 11.3712 16.7799 12.3126V12.9946C16.7799 13.936 16.0167 14.6992 15.0753 14.6992H6.24976C6.20993 14.713 6.16946 14.7255 6.12843 14.7364C5.77351 14.8309 5.3999 14.8077 5.06247 14.6742C4.085 14.5202 3.33785 13.6739 3.33785 12.6536V2.95994C3.33785 2.01851 4.10103 1.25533 5.04246 1.25533H5.7243C6.66573 1.25533 7.42891 2.01851 7.42891 2.95994V6.98399Z" fill="white" stroke="white" stroke-linecap="square" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="42" height="42" viewBox="0 0 42 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M41.9882 20.3343C41.9667 19.5391 41.8893 18.7525 41.769 17.9831L37.6125 17.304L36.2027 13.4269L38.9708 10.2978C38.1326 8.92231 37.1311 7.65431 36.0006 6.51096L32.231 8.37642L28.7795 6.06393L29.1534 1.92036C27.7221 1.32289 26.2048 0.87587 24.6316 0.609375L22.6759 4.29733L18.4979 4.39189L16.3531 0.807097C14.7455 1.16816 13.211 1.70544 11.7711 2.40177L12.3857 6.51525L9.06313 9.01687L5.19465 7.37062C4.13297 8.56985 3.20453 9.88943 2.44373 11.3122L5.38807 14.278L4.20174 18.2239L0.0882535 19.1351C0.0151822 19.9518 -0.0192044 20.7856 0.0108838 21.6324C0.040972 22.4061 0.109745 23.1669 0.217203 23.9148L4.37367 24.6068L5.77062 28.4882L2.98102 31.6174C3.82349 32.9972 4.82069 34.278 5.95115 35.4214L9.72937 33.5688L13.1766 35.8942L12.7855 40.0378C14.2641 40.6524 15.8244 41.1167 17.4448 41.3918L19.392 37.6995L23.5699 37.5877L25.7234 41.1682C27.3267 40.7986 28.8612 40.257 30.3011 39.5564L29.6735 35.4472L32.9832 32.9284L36.856 34.566C37.9177 33.3582 38.8418 32.0386 39.5983 30.6159L36.6368 27.6587L37.8102 23.6999L41.928 22.7801C41.9882 21.9677 42.0183 21.1553 41.9882 20.3343ZM27.2063 27.9552C23.3077 31.3294 17.3589 30.9726 13.9202 27.1085C10.4988 23.2486 10.877 17.3986 14.7885 14.0244C18.6827 10.633 24.6316 11.0113 28.0617 14.8583C31.5132 18.7139 31.1178 24.5811 27.2063 27.9552Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="43" height="42" viewBox="0 0 43 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M39.8701 5.25H37.2451V36.75H39.8701V5.25Z" fill="white"/>
|
||||
<path d="M7.05762 36.7497C6.70952 36.7497 6.37568 36.6114 6.12954 36.3653C5.8834 36.1191 5.74512 35.7853 5.74512 35.4372V6.56218C5.74517 6.33168 5.80593 6.10527 5.92127 5.90571C6.03661 5.70615 6.20247 5.54049 6.40216 5.42538C6.60186 5.31028 6.82834 5.24979 7.05884 5.25C7.28933 5.25021 7.5157 5.31112 7.71518 5.4266L32.6527 19.8641C32.8516 19.9795 33.0167 20.1451 33.1314 20.3443C33.2462 20.5436 33.3066 20.7695 33.3066 20.9994C33.3066 21.2293 33.2462 21.4552 33.1314 21.6545C33.0167 21.8537 32.8516 22.0194 32.6527 22.1347L7.71518 36.5722C7.51549 36.6883 7.28862 36.7496 7.05762 36.7497Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 775 B |
|
After Width: | Height: | Size: 148 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.2183 2.15689L13.0419 0.980469L7.49587 6.52648L1.94986 0.980469L0.773438 2.15689L6.31945 7.7029L0.773438 13.2489L1.94986 14.4253L7.49587 8.87933L13.0419 14.4253L14.2183 13.2489L8.6723 7.7029L14.2183 2.15689Z" fill="#0233BD"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 341 B |
@@ -0,0 +1,12 @@
|
||||
<svg width="51" height="51" viewBox="0 0 51 51" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="25.7975" cy="25.2545" r="25.1647" fill="#FDFDFF"/>
|
||||
<g clip-path="url(#clip0_297_1480)">
|
||||
<path d="M29.285 13.2773V15.0467H35.1116L27.5156 22.6392L28.7666 23.8937L36.3626 16.2977V22.1243H38.132V13.2773H29.285Z" fill="black"/>
|
||||
<path d="M23.9757 28.6824L22.7301 27.4297L15.1288 35.0257V29.1991H13.3594V38.046H22.2063V36.2767H16.3797L23.9757 28.6824Z" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_297_1480">
|
||||
<rect width="28.3103" height="28.3103" fill="white" transform="translate(11.5938 11.5078)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 633 B |
@@ -0,0 +1,12 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6421_20692)">
|
||||
<path d="M2.94726 12.6619L3.75164 11.8631C2.87088 11.0723 2.17887 10.0939 1.72664 9C2.86851 6.14812 6.01851 3.9375 8.99976 3.9375C9.76695 3.94763 10.5272 4.08447 11.2498 4.3425L12.1216 3.465C11.1331 3.04724 10.0728 2.82563 8.99976 2.8125C7.1663 2.88145 5.39323 3.48612 3.89969 4.5518C2.40614 5.61747 1.2576 7.09743 0.596011 8.80875C0.55133 8.93234 0.55133 9.06766 0.596011 9.19125C1.09565 10.5171 1.90125 11.7062 2.94726 12.6619Z" fill="white"/>
|
||||
<path d="M6.75023 8.84906C6.78934 8.31002 7.02118 7.80307 7.40334 7.42091C7.78549 7.03876 8.29244 6.80692 8.83148 6.76781L9.8496 5.74406C9.27909 5.59384 8.67917 5.59579 8.10965 5.74971C7.54013 5.90364 7.02091 6.20417 6.60375 6.62133C6.18659 7.03849 5.88606 7.55771 5.73214 8.12723C5.57821 8.69675 5.57626 9.29667 5.72648 9.86718L6.75023 8.84906Z" fill="white"/>
|
||||
<path d="M17.4037 8.80875C16.7587 7.12868 15.6364 5.67395 14.175 4.62375L16.875 1.91813L16.0819 1.125L1.125 16.0819L1.91813 16.875L4.78688 14.0062C6.06593 14.7566 7.51727 15.1635 9 15.1875C10.8335 15.1186 12.6065 14.5139 14.1001 13.4482C15.5936 12.3825 16.7422 10.9026 17.4037 9.19125C17.4484 9.06766 17.4484 8.93234 17.4037 8.80875ZM11.25 9C11.2476 9.39381 11.1419 9.7801 10.9435 10.1203C10.7451 10.4604 10.4608 10.7425 10.1192 10.9384C9.77751 11.1343 9.39044 11.2371 8.99662 11.2365C8.60281 11.2359 8.21605 11.1319 7.875 10.935L10.935 7.875C11.1372 8.21572 11.2459 8.60381 11.25 9ZM9 14.0625C7.81991 14.0419 6.66219 13.737 5.625 13.1737L7.05375 11.745C7.70363 12.1959 8.49124 12.4043 9.27907 12.3336C10.0669 12.263 10.8049 11.9179 11.3642 11.3586C11.9235 10.7993 12.2686 10.0613 12.3393 9.27345C12.4099 8.48561 12.2015 7.698 11.7506 7.04812L13.365 5.43375C14.6557 6.31968 15.665 7.55743 16.2731 9C15.1313 11.8519 11.9812 14.0625 9 14.0625Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_6421_20692">
|
||||
<rect width="18" height="18" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.5" y="0.5" width="32" height="32" rx="16" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.6759 25.9343C15.4493 25.9343 15.2656 25.7506 15.2656 25.524V7.47276C15.2656 7.24618 15.4493 7.0625 15.6759 7.0625H17.3169C17.5435 7.0625 17.7272 7.24618 17.7272 7.47276V25.524C17.7272 25.7506 17.5435 25.9343 17.3169 25.9343H15.6759Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.6759 25.9343C15.4493 25.9343 15.2656 25.7506 15.2656 25.524V7.47276C15.2656 7.24618 15.4493 7.0625 15.6759 7.0625H17.3169C17.5435 7.0625 17.7272 7.24618 17.7272 7.47276V25.524C17.7272 25.7506 17.5435 25.9343 17.3169 25.9343H15.6759Z" fill="black" fill-opacity="0.2"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.0657 15.6759C7.0657 15.4493 7.24938 15.2656 7.47596 15.2656L25.5272 15.2656C25.7538 15.2656 25.9375 15.4493 25.9375 15.6759L25.9375 17.3169C25.9375 17.5435 25.7538 17.7272 25.5272 17.7272L7.47596 17.7272C7.24938 17.7272 7.0657 17.5435 7.0657 17.3169L7.0657 15.6759Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.0657 15.6759C7.0657 15.4493 7.24938 15.2656 7.47596 15.2656L25.5272 15.2656C25.7538 15.2656 25.9375 15.4493 25.9375 15.6759L25.9375 17.3169C25.9375 17.5435 25.7538 17.7272 25.5272 17.7272L7.47596 17.7272C7.24938 17.7272 7.0657 17.5435 7.0657 17.3169L7.0657 15.6759Z" fill="black" fill-opacity="0.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="19" height="14" viewBox="0 0 19 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.9635 7.20591C18.2537 9.04182 17.0216 10.6295 15.4193 11.7728C13.817 12.916 11.9149 13.5647 9.94795 13.6387C7.98102 13.5647 6.07888 12.916 4.47661 11.7728C2.87434 10.6295 1.64219 9.04182 0.932435 7.20591C0.884501 7.07333 0.884501 6.92815 0.932435 6.79557C1.64219 4.95967 2.87434 3.37197 4.47661 2.22872C6.07888 1.08547 7.98102 0.436776 9.94795 0.36281C11.9149 0.436776 13.817 1.08547 15.4193 2.22872C17.0216 3.37197 18.2537 4.95967 18.9635 6.79557C19.0114 6.92815 19.0114 7.07333 18.9635 7.20591ZM9.94795 1.56971C6.74968 1.56971 3.37037 3.94126 2.14537 7.00074C3.37037 10.0602 6.74968 12.4318 9.94795 12.4318C13.1462 12.4318 16.5255 10.0602 17.7505 7.00074C16.5255 3.94126 13.1462 1.56971 9.94795 1.56971Z" fill="white"/>
|
||||
<path d="M9.94686 10.6211C9.23076 10.6211 8.53073 10.4087 7.93532 10.0109C7.3399 9.61305 6.87582 9.04758 6.60178 8.38598C6.32774 7.72439 6.25604 6.99639 6.39574 6.29404C6.53545 5.5917 6.88029 4.94655 7.38665 4.44019C7.89301 3.93383 8.53816 3.58899 9.2405 3.44928C9.94285 3.30958 10.6708 3.38128 11.3324 3.65532C11.994 3.92936 12.5595 4.39344 12.9574 4.98886C13.3552 5.58428 13.5676 6.2843 13.5676 7.0004C13.5676 7.96067 13.1861 8.88161 12.5071 9.56062C11.8281 10.2396 10.9071 10.6211 9.94686 10.6211ZM9.94686 4.58661C9.46946 4.58661 9.00278 4.72818 8.60583 4.99341C8.20889 5.25864 7.8995 5.63562 7.71681 6.07669C7.53411 6.51775 7.48631 7.00308 7.57945 7.47131C7.67259 7.93954 7.90248 8.36964 8.24005 8.70721C8.57763 9.04479 9.00773 9.27468 9.47596 9.36782C9.94419 9.46095 10.4295 9.41315 10.8706 9.23046C11.3116 9.04776 11.6886 8.73838 11.9539 8.34144C12.2191 7.94449 12.3607 7.47781 12.3607 7.0004C12.3607 6.36023 12.1063 5.74627 11.6537 5.2936C11.201 4.84092 10.587 4.58661 9.94686 4.58661Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="41" height="41" viewBox="0 0 41 41" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="20.0508" cy="20.5" r="20" fill="#FDFDFF"/>
|
||||
<path d="M17.4535 22.4545V22.1136C17.4535 21.3324 17.515 20.7098 17.6381 20.2457C17.7612 19.7817 17.9435 19.41 18.185 19.1307C18.4265 18.8466 18.7224 18.5909 19.0728 18.3636C19.3758 18.1648 19.6457 17.973 19.8825 17.7884C20.1239 17.6037 20.3133 17.4072 20.4506 17.1989C20.5927 16.9905 20.6637 16.7538 20.6637 16.4886C20.6637 16.2519 20.6069 16.0436 20.4933 15.8636C20.3796 15.6837 20.2257 15.544 20.0316 15.4446C19.8375 15.3452 19.622 15.2955 19.3853 15.2955C19.1296 15.2955 18.8929 15.3546 18.6751 15.473C18.462 15.5914 18.2892 15.7547 18.1566 15.9631C18.0288 16.1714 17.9648 16.4129 17.9648 16.6875H14.3285C14.3379 15.6458 14.5747 14.8007 15.0387 14.152C15.5027 13.4986 16.1183 13.0204 16.8853 12.7173C17.6523 12.4096 18.4951 12.2557 19.4137 12.2557C20.427 12.2557 21.3313 12.4048 22.1268 12.7031C22.9222 12.9967 23.5496 13.4418 24.0089 14.0384C24.4682 14.6302 24.6978 15.3712 24.6978 16.2614C24.6978 16.8343 24.5984 17.3385 24.3995 17.7741C24.2054 18.205 23.9331 18.5862 23.5827 18.9176C23.2371 19.2443 22.8323 19.5426 22.3683 19.8125C22.0273 20.0114 21.7409 20.2173 21.5089 20.4304C21.2769 20.6387 21.1017 20.8778 20.9833 21.1477C20.8649 21.4129 20.8058 21.7348 20.8058 22.1136V22.4545H17.4535ZM19.1864 27.2273C18.6372 27.2273 18.1661 27.0355 17.7731 26.652C17.3848 26.2637 17.1931 25.7926 17.1978 25.2386C17.1931 24.6989 17.3848 24.2372 17.7731 23.8537C18.1661 23.4702 18.6372 23.2784 19.1864 23.2784C19.7073 23.2784 20.1665 23.4702 20.5643 23.8537C20.9667 24.2372 21.1703 24.6989 21.1751 25.2386C21.1703 25.608 21.0733 25.9441 20.8839 26.2472C20.6992 26.5455 20.4577 26.7846 20.1594 26.9645C19.8612 27.1397 19.5368 27.2273 19.1864 27.2273Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.79167 10.5417C8.15634 10.5417 8.50608 10.3968 8.76394 10.1389C9.0218 9.88108 9.16667 9.53134 9.16667 9.16667C9.16667 8.80199 9.0218 8.45226 8.76394 8.1944C8.50608 7.93653 8.15634 7.79167 7.79167 7.79167C7.42699 7.79167 7.07726 7.93653 6.81939 8.1944C6.56153 8.45226 6.41667 8.80199 6.41667 9.16667C6.41667 9.53134 6.56153 9.88108 6.81939 10.1389C7.07726 10.3968 7.42699 10.5417 7.79167 10.5417ZM7.58267 14.0562C7.50273 13.9652 7.40557 13.891 7.29679 13.8378C7.188 13.7846 7.06976 13.7535 6.94888 13.7462C6.82801 13.739 6.70689 13.7558 6.59254 13.7956C6.47818 13.8354 6.37286 13.8975 6.28264 13.9783C6.19242 14.0591 6.1191 14.1569 6.06691 14.2662C6.01472 14.3755 5.9847 14.494 5.97858 14.6149C5.97247 14.7359 5.99037 14.8568 6.03126 14.9708C6.07216 15.0848 6.13523 15.1895 6.21683 15.279C6.81887 15.9517 7.55608 16.4899 8.38031 16.8582C9.20453 17.2266 10.0972 17.4169 11 17.4167C11.9028 17.4169 12.7955 17.2266 13.6197 16.8582C14.4439 16.4899 15.1811 15.9517 15.7832 15.279C15.9427 15.0975 16.0241 14.8603 16.0096 14.6191C15.9952 14.3779 15.8861 14.1522 15.706 13.991C15.526 13.8298 15.2896 13.7462 15.0483 13.7584C14.8069 13.7706 14.5802 13.8776 14.4173 14.0562C13.9872 14.5368 13.4605 14.9213 12.8717 15.1845C12.2828 15.4477 11.645 15.5836 11 15.5833C9.64333 15.5833 8.42417 14.9948 7.58267 14.0562ZM15.5833 9.16667C15.5833 9.53134 15.4385 9.88108 15.1806 10.1389C14.9227 10.3968 14.573 10.5417 14.2083 10.5417C13.8437 10.5417 13.4939 10.3968 13.2361 10.1389C12.9782 9.88108 12.8333 9.53134 12.8333 9.16667C12.8333 8.80199 12.9782 8.45226 13.2361 8.1944C13.4939 7.93653 13.8437 7.79167 14.2083 7.79167C14.573 7.79167 14.9227 7.93653 15.1806 8.1944C15.4385 8.45226 15.5833 8.80199 15.5833 9.16667ZM22 11C22 9.55546 21.7155 8.12506 21.1627 6.79048C20.6099 5.4559 19.7996 4.24327 18.7782 3.22183C17.7567 2.20038 16.5441 1.39013 15.2095 0.837325C13.8749 0.284523 12.4445 0 11 0C9.55546 0 8.12506 0.284523 6.79048 0.837325C5.4559 1.39013 4.24327 2.20038 3.22183 3.22183C2.20038 4.24327 1.39013 5.4559 0.837325 6.79048C0.284523 8.12506 -2.15253e-08 9.55546 0 11C4.34724e-08 13.9174 1.15893 16.7153 3.22183 18.7782C5.28473 20.8411 8.08262 22 11 22C13.9174 22 16.7153 20.8411 18.7782 18.7782C20.8411 16.7153 22 13.9174 22 11ZM1.83333 11C1.83333 8.56885 2.7991 6.23727 4.51819 4.51819C6.23727 2.7991 8.56885 1.83333 11 1.83333C13.4312 1.83333 15.7627 2.7991 17.4818 4.51819C19.2009 6.23727 20.1667 8.56885 20.1667 11C20.1667 13.4312 19.2009 15.7627 17.4818 17.4818C15.7627 19.2009 13.4312 20.1667 11 20.1667C8.56885 20.1667 6.23727 19.2009 4.51819 17.4818C2.7991 15.7627 1.83333 13.4312 1.83333 11Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5" d="M5.11101 3.67971C6.26216 2.91054 7.61553 2.5 9 2.5C9.91926 2.5 10.8295 2.68106 11.6788 3.03284C12.5281 3.38463 13.2997 3.90024 13.9497 4.55025C14.5998 5.20026 15.1154 5.97194 15.4672 6.82122C15.8189 7.67049 16 8.58075 16 9.5C16 10.8845 15.5895 12.2378 14.8203 13.389C14.0511 14.5401 12.9579 15.4373 11.6788 15.9672C10.3997 16.497 8.99224 16.6356 7.63437 16.3655C6.2765 16.0954 5.02922 15.4287 4.05026 14.4497C3.07129 13.4708 2.4046 12.2235 2.13451 10.8656C1.86441 9.50776 2.00303 8.1003 2.53285 6.82122C3.06266 5.54213 3.95987 4.44888 5.11101 3.67971ZM5.3888 14.9046C6.45772 15.6188 7.71442 16 9 16C10.7239 16 12.3772 15.3152 13.5962 14.0962C14.8152 12.8772 15.5 11.2239 15.5 9.5C15.5 8.21442 15.1188 6.95771 14.4046 5.88879C13.6903 4.81987 12.6752 3.98675 11.4874 3.49478C10.2997 3.00281 8.99279 2.87409 7.73192 3.1249C6.47104 3.3757 5.31285 3.99476 4.40381 4.90381C3.49477 5.81285 2.8757 6.97104 2.6249 8.23191C2.3741 9.49279 2.50282 10.7997 2.99479 11.9874C3.48676 13.1752 4.31988 14.1903 5.3888 14.9046Z" fill="#F5F5F5" stroke="white"/>
|
||||
<path d="M15 9.5H16.5C16.5 8.51509 16.306 7.53982 15.9291 6.62987C15.5522 5.71993 14.9997 4.89314 14.3033 4.1967C13.6069 3.50026 12.7801 2.94781 11.8701 2.5709C10.9602 2.19399 9.98491 2 9 2V3.5C10.5913 3.5 12.1174 4.13214 13.2426 5.25736C14.3679 6.38258 15 7.9087 15 9.5Z" fill="#F5F5F5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_283_457)">
|
||||
<path d="M40.5 11.2498C40.5 10.8072 40.3694 10.3745 40.1247 10.0058C39.88 9.6371 39.532 9.34873 39.1242 9.17678C38.7165 9.00484 38.267 8.95696 37.8322 9.03913C37.3974 9.12131 36.9964 9.32989 36.6795 9.63878L23.508 22.4638H15.75C13.9598 22.4638 12.2429 23.1749 10.977 24.4408C9.71116 25.7067 9 27.4236 9 29.2138V42.6688C9 44.459 9.71116 46.1759 10.977 47.4417C12.2429 48.7076 13.9598 49.4188 15.75 49.4188H23.5035L36.675 62.3563C36.9914 62.6664 37.3924 62.8762 37.8275 62.9594C38.2627 63.0426 38.7128 62.9955 39.1213 62.8239C39.5298 62.6523 39.8785 62.364 40.1238 61.995C40.3691 61.626 40.4999 61.1928 40.5 60.7498V11.2498ZM45.4995 23.3503C45.6835 23.1188 45.9113 22.9258 46.1699 22.7824C46.4285 22.639 46.7128 22.548 47.0066 22.5145C47.3004 22.4811 47.598 22.5059 47.8822 22.5875C48.1664 22.6692 48.4317 22.806 48.663 22.9903L48.672 22.9948L48.681 23.0038L48.7035 23.0218L48.771 23.0803L48.978 23.2603C49.14 23.4133 49.3605 23.6203 49.617 23.8993C50.1255 24.4528 50.787 25.2583 51.4395 26.3293C52.749 28.4893 54.018 31.6978 54.018 35.9953C54.018 40.2883 52.749 43.5013 51.4395 45.6613C50.9145 46.5314 50.304 47.3469 49.617 48.0958C49.3308 48.4066 49.0274 48.7011 48.708 48.9778L48.672 49.0093H48.6675C48.6675 49.0093 46.656 50.1028 45.504 48.6583C45.1336 48.1948 44.9612 47.6038 45.0244 47.0138C45.0876 46.4239 45.3813 45.8828 45.8415 45.5083L45.8505 45.4993L45.9315 45.4273C46.0125 45.3508 46.1475 45.2248 46.314 45.0448C46.7959 44.5155 47.224 43.9397 47.592 43.3258C48.537 41.7733 49.518 39.3568 49.518 35.9908C49.518 32.6293 48.537 30.2173 47.592 28.6693C47.1293 27.9055 46.573 27.2026 45.936 26.5768C45.6899 26.3978 45.4827 26.1707 45.327 25.9093C45.1712 25.6479 45.07 25.3576 45.0296 25.056C44.9892 24.7544 45.0105 24.4477 45.092 24.1545C45.1735 23.8613 45.3137 23.5877 45.504 23.3503M53.163 13.9903C52.9327 13.7996 52.6666 13.6568 52.3804 13.5702C52.0943 13.4836 51.7937 13.4548 51.4963 13.4857C51.1989 13.5165 50.9106 13.6064 50.6483 13.7499C50.386 13.8934 50.155 14.0878 49.9687 14.3217C49.7824 14.5555 49.6445 14.8242 49.5632 15.1119C49.4819 15.3997 49.4588 15.7007 49.4952 15.9975C49.5316 16.2943 49.6268 16.5808 49.7752 16.8404C49.9236 17.1 50.1222 17.3274 50.3595 17.5093L50.409 17.5543L50.643 17.7568C50.8545 17.9458 51.165 18.2383 51.5475 18.6343C52.3125 19.4308 53.3475 20.6278 54.3825 22.2073C56.4525 25.3618 58.5225 30.0058 58.5225 36.0178C58.5341 40.9231 57.0936 45.7222 54.3825 49.8103C53.3475 51.3853 52.3125 52.5733 51.5475 53.3653C51.1857 53.7419 50.8073 54.1022 50.4135 54.4453L50.364 54.4903H50.3595C49.9054 54.8661 49.6169 55.4052 49.556 55.9915C49.4952 56.5778 49.6669 57.1646 50.0342 57.6257C50.4015 58.0867 50.9351 58.3852 51.5202 58.4569C52.1053 58.5287 52.6952 58.3679 53.163 58.0093L53.3115 57.8878L53.649 57.5953C53.9325 57.3388 54.324 56.9743 54.7875 56.4928C56.0348 55.196 57.1587 53.7859 58.1445 52.2808C61.3357 47.4583 63.0312 41.8005 63.018 36.0178C63.0294 30.2297 61.3342 24.5667 58.1445 19.7368C57.159 18.2298 56.0367 16.8169 54.792 15.5158C54.3216 15.027 53.8291 14.56 53.316 14.1163L53.2125 14.0308L53.181 14.0038L53.172 13.9948L53.163 13.9903Z" fill="#282828"/>
|
||||
<path d="M81 85L-1 0" stroke="black" stroke-width="5"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_283_457">
|
||||
<rect width="72" height="72" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.5 13.5C21.3065 13.5 20.1619 13.9741 19.318 14.818C18.4741 15.6619 18 16.8065 18 18V54C18 55.1935 18.4741 56.3381 19.318 57.182C20.1619 58.0259 21.3065 58.5 22.5 58.5H27C28.1935 58.5 29.3381 58.0259 30.182 57.182C31.0259 56.3381 31.5 55.1935 31.5 54V18C31.5 16.8065 31.0259 15.6619 30.182 14.818C29.3381 13.9741 28.1935 13.5 27 13.5H22.5ZM45 13.5C43.8065 13.5 42.6619 13.9741 41.818 14.818C40.9741 15.6619 40.5 16.8065 40.5 18V54C40.5 55.1935 40.9741 56.3381 41.818 57.182C42.6619 58.0259 43.8065 58.5 45 58.5H49.5C50.6935 58.5 51.8381 58.0259 52.682 57.182C53.5259 56.3381 54 55.1935 54 54V18C54 16.8065 53.5259 15.6619 52.682 14.818C51.8381 13.9741 50.6935 13.5 49.5 13.5H45Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 849 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M56.0751 29.249C56.0765 29.8367 55.9259 30.4146 55.6377 30.9268C55.3496 31.4389 54.9339 31.8678 54.4309 32.1717L23.2613 51.2396C22.7358 51.5613 22.1339 51.737 21.5178 51.7484C20.9017 51.7598 20.2937 51.6066 19.7566 51.3045C19.2247 51.007 18.7816 50.5733 18.4728 50.0478C18.1641 49.5224 18.0009 48.9241 18 48.3147V10.1834C18.0009 9.5739 18.1641 8.97569 18.4728 8.45022C18.7816 7.92476 19.2247 7.49102 19.7566 7.19359C20.2937 6.89148 20.9017 6.73821 21.5178 6.74962C22.1339 6.76103 22.7358 6.9367 23.2613 7.25849L54.4309 26.3263C54.9339 26.6302 55.3496 27.0591 55.6377 27.5712C55.9259 28.0834 56.0765 28.6614 56.0751 29.249Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 751 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.257 7.16867C22.0204 8.60083 18.1867 10.9365 15 13.9759V8.07422C15 6.69351 13.8807 5.57422 12.5 5.57422H11.5C10.1193 5.57422 9 6.69351 9 8.07422V22.291C9 23.7875 10.0958 25.0286 11.5293 25.2544C12.0242 25.4503 12.5722 25.4843 13.0927 25.3457C13.1529 25.3297 13.2122 25.3115 13.2706 25.2911H26.2143C27.595 25.2911 28.7143 24.1718 28.7143 22.7911V21.791C28.7143 20.4102 27.595 19.291 26.2143 19.291H18.1765C20.9101 16.3741 24.3381 14.1511 28.1784 12.8529C33.791 10.9556 39.9018 11.163 45.3729 13.4366C50.844 15.7102 55.3026 19.8951 57.9185 25.2121C60.5344 30.5291 61.1292 36.6158 59.5922 42.3388C58.0551 48.0619 54.4909 53.031 49.5634 56.3212C44.636 59.6113 38.681 60.9982 32.8073 60.2238C26.9336 59.4493 21.5413 56.5662 17.6347 52.1112C13.728 47.6562 11.5731 41.9329 11.5714 36.0069L11.5713 35.5068C11.5709 34.1261 10.4513 33.0072 9.07058 33.0075L8.07058 33.0078C7.40754 33.008 6.77173 33.2716 6.30302 33.7406C5.83431 34.2095 5.5711 34.8455 5.57129 35.5085L5.57143 36.0086C5.57353 43.3895 8.25745 50.5182 13.1236 56.0673C17.9897 61.6164 24.7063 65.2078 32.023 66.1725C39.3396 67.1372 46.7574 65.4095 52.8952 61.3113C59.0329 57.213 63.4723 51.0235 65.3868 43.8952C67.3013 36.767 66.5604 29.1858 63.3022 22.5632C60.044 15.9406 54.4904 10.7279 47.6753 7.89581C40.8603 5.0637 33.2484 4.80528 26.257 7.16867Z" fill="#282828"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M40.5 11.2498C40.5 10.8072 40.3694 10.3745 40.1247 10.0058C39.88 9.6371 39.532 9.34873 39.1242 9.17678C38.7165 9.00484 38.267 8.95696 37.8322 9.03913C37.3974 9.12131 36.9964 9.32989 36.6795 9.63878L23.508 22.4638H15.75C13.9598 22.4638 12.2429 23.1749 10.977 24.4408C9.71116 25.7067 9 27.4236 9 29.2138V42.6688C9 44.459 9.71116 46.1759 10.977 47.4417C12.2429 48.7076 13.9598 49.4188 15.75 49.4188H23.5035L36.675 62.3563C36.9914 62.6664 37.3924 62.8762 37.8275 62.9594C38.2627 63.0426 38.7128 62.9955 39.1213 62.8239C39.5298 62.6523 39.8785 62.364 40.1238 61.995C40.3691 61.626 40.4999 61.1928 40.5 60.7498V11.2498ZM45.4995 23.3503C45.6835 23.1188 45.9113 22.9258 46.1699 22.7824C46.4285 22.639 46.7128 22.548 47.0066 22.5145C47.3004 22.4811 47.598 22.5059 47.8822 22.5875C48.1664 22.6692 48.4317 22.806 48.663 22.9903L48.672 22.9948L48.681 23.0038L48.7035 23.0218L48.771 23.0803L48.978 23.2603C49.14 23.4133 49.3605 23.6203 49.617 23.8993C50.1255 24.4528 50.787 25.2583 51.4395 26.3293C52.749 28.4893 54.018 31.6978 54.018 35.9953C54.018 40.2883 52.749 43.5013 51.4395 45.6613C50.9145 46.5314 50.304 47.3469 49.617 48.0958C49.3308 48.4066 49.0274 48.7011 48.708 48.9778L48.672 49.0093H48.6675C48.6675 49.0093 46.656 50.1028 45.504 48.6583C45.1336 48.1948 44.9612 47.6038 45.0244 47.0138C45.0876 46.4239 45.3813 45.8828 45.8415 45.5083L45.8505 45.4993L45.9315 45.4273C46.0125 45.3508 46.1475 45.2248 46.314 45.0448C46.7959 44.5155 47.224 43.9397 47.592 43.3258C48.537 41.7733 49.518 39.3568 49.518 35.9908C49.518 32.6293 48.537 30.2173 47.592 28.6693C47.1293 27.9055 46.573 27.2026 45.936 26.5768C45.6899 26.3978 45.4827 26.1707 45.327 25.9093C45.1712 25.6479 45.07 25.3576 45.0296 25.056C44.9893 24.7544 45.0105 24.4477 45.092 24.1545C45.1735 23.8613 45.3137 23.5877 45.504 23.3503M53.163 13.9903C52.9327 13.7996 52.6666 13.6568 52.3804 13.5702C52.0943 13.4836 51.7937 13.4548 51.4963 13.4857C51.1989 13.5165 50.9106 13.6064 50.6483 13.7499C50.386 13.8934 50.155 14.0878 49.9687 14.3217C49.7824 14.5555 49.6445 14.8242 49.5632 15.1119C49.4819 15.3997 49.4588 15.7007 49.4952 15.9975C49.5316 16.2943 49.6268 16.5808 49.7752 16.8404C49.9236 17.1 50.1222 17.3274 50.3595 17.5093L50.409 17.5543L50.643 17.7568C50.8545 17.9458 51.165 18.2383 51.5475 18.6343C52.3125 19.4308 53.3475 20.6278 54.3825 22.2073C56.4525 25.3618 58.5225 30.0058 58.5225 36.0178C58.5341 40.9231 57.0936 45.7222 54.3825 49.8103C53.3475 51.3853 52.3125 52.5733 51.5475 53.3653C51.1857 53.7419 50.8073 54.1022 50.4135 54.4453L50.364 54.4903H50.3595C49.9054 54.8661 49.6169 55.4052 49.556 55.9915C49.4952 56.5778 49.6669 57.1646 50.0342 57.6257C50.4015 58.0867 50.9351 58.3852 51.5202 58.4569C52.1053 58.5287 52.6952 58.3679 53.163 58.0093L53.3115 57.8878L53.649 57.5953C53.9325 57.3388 54.324 56.9743 54.7875 56.4928C56.0348 55.196 57.1587 53.7859 58.1445 52.2808C61.3357 47.4583 63.0312 41.8005 63.018 36.0178C63.0294 30.2297 61.3342 24.5667 58.1445 19.7368C57.159 18.2298 56.0367 16.8169 54.792 15.5158C54.3216 15.027 53.8291 14.56 53.316 14.1163L53.2125 14.0308L53.181 14.0038L53.172 13.9948L53.163 13.9903Z" fill="#282828"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="94" height="96" viewBox="0 0 94 96" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="93.1343" height="96" rx="46.5672" fill="white"/>
|
||||
<path d="M71.7842 60.8119H72.5905L72.4956 60.0111C72.2614 58.0348 71.3411 56.2441 69.7506 54.9532C68.1627 53.6644 65.956 52.9125 63.2067 52.9125C57.3617 52.9125 53.0844 57.4271 53.0844 63.3554C53.0844 69.3147 57.4192 73.8518 63.3135 73.8518C65.9904 73.8518 68.1887 73.2032 69.8059 71.9598C71.4326 70.7091 72.4042 68.9074 72.7074 66.7415L72.8216 65.9257H71.9979H68.925H68.3792L68.2343 66.452C68.0086 67.2715 67.6094 68.0183 66.89 68.568C66.1694 69.1188 65.0473 69.5331 63.2601 69.5331C59.9754 69.5331 57.51 67.0562 57.51 63.3822C57.51 59.6775 59.9791 57.2045 63.2334 57.2045C64.9601 57.2045 66.039 57.622 66.7332 58.1719C67.4299 58.7238 67.8202 59.4732 68.048 60.2882L68.1943 60.8119H68.7379H71.7842Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.43284"/>
|
||||
<path d="M34.7111 72.459L34.353 73.4246H35.3828H38.6161H39.1214L39.2909 72.9486L41.4728 66.8244H46.9172L49.3049 72.9677L49.4824 73.4246H49.9726H53.1792H54.2256L53.8471 72.449L46.5789 53.7174L46.4015 53.2601H45.911H42.3303H41.8319L41.6586 53.7274L34.7111 72.459ZM42.4221 63.0401L44.1238 59.0128L45.8633 63.0401H42.4221Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.43284"/>
|
||||
<path d="M29.6689 73.4525H30.3853V72.7361V57.5267H34.8528H35.5692V56.8103V54.0312V53.3148H34.8528H21.4922H20.7758V54.0312V56.8103V57.5267H21.4922H25.9597V72.7361V73.4525H26.6761H29.6689Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.43284"/>
|
||||
<path d="M72.7172 34.8214H73.5235L73.4286 34.0207C73.1334 31.5296 71.9748 29.2775 69.9744 27.6539C67.9766 26.0324 65.1884 25.0766 61.6918 25.0766C54.2987 25.0766 48.8851 30.7808 48.8851 38.2953C48.8851 45.8484 54.3715 51.5828 61.8292 51.5828C65.238 51.5828 68.016 50.7569 70.0498 49.1932C72.093 47.6222 73.3182 45.3572 73.7015 42.6194L73.8157 41.8036H72.992H69.0421H68.4962L68.3513 42.3298C68.0532 43.4125 67.5205 44.4166 66.5505 45.158C65.5792 45.9003 64.0891 46.4405 61.7605 46.4405C57.4158 46.4405 54.1649 43.1552 54.1649 38.3297C54.1649 33.4659 57.4195 30.1845 61.7261 30.1845C63.979 30.1845 65.4144 30.7298 66.3518 31.4723C67.2915 32.2167 67.8114 33.2234 68.1116 34.2978L68.2579 34.8214H68.8016H72.7172Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.43284"/>
|
||||
<path d="M42.057 50.3516V51.068H42.7734H46.6547H47.3711V50.3516V26.3086V25.5922H46.6547H42.7734H42.057V26.3086V50.3516Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.43284"/>
|
||||
<path d="M32.0024 51.068H32.7188V50.3516V30.5971H38.6658H39.3822V29.8807V26.3086V25.5922H38.6658H21.4922H20.7758V26.3086V29.8807V30.5971H21.4922H27.4391V50.3516V51.068H28.1555H32.0024Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.43284"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_5546_24649)">
|
||||
<path opacity="0.3" d="M5.83398 8.00098H27.1673V21.3343H5.83398V8.00098Z" fill="#0F62FE"/>
|
||||
<path d="M27.1667 24.0007C28.6333 24.0007 29.82 22.8007 29.82 21.334L29.8333 8.00065C29.8333 6.53398 28.6333 5.33398 27.1667 5.33398H5.83333C4.36667 5.33398 3.16667 6.53398 3.16667 8.00065V21.334C3.16667 22.8007 4.36667 24.0007 5.83333 24.0007H0.5V26.6673H32.5V24.0007H27.1667ZM5.83333 8.00065H27.1667V21.334H5.83333V8.00065Z" fill="#F1F6FF"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_5546_24649">
|
||||
<rect width="32" height="32" fill="white" transform="translate(0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 713 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="27" height="26" viewBox="0 0 27 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.65833 1.63178C7.98784 2.19648 6.47621 3.11745 5.2197 4.31589V1.98883C5.2197 1.44442 4.77837 1.00308 4.23395 1.00308H3.83965C3.29523 1.00308 2.8539 1.44442 2.8539 1.98883V7.59454C2.8539 8.18459 3.28597 8.67395 3.85122 8.76301C4.04635 8.84024 4.2624 8.85365 4.46765 8.79899C4.49138 8.79267 4.51478 8.78549 4.53782 8.77748H9.64151C10.1859 8.77748 10.6273 8.33614 10.6273 7.79173V7.39736C10.6273 6.85294 10.1859 6.4116 9.64151 6.4116H6.47221C7.55005 5.26147 8.90173 4.38493 10.4159 3.87306C12.629 3.12495 15.0385 3.20675 17.1958 4.10323C19.353 4.99972 21.1111 6.64981 22.1425 8.74631C23.174 10.8428 23.4085 13.2428 22.8024 15.4994C22.1964 17.756 20.791 19.7153 18.8481 21.0127C16.9052 22.31 14.5571 22.8568 12.2411 22.5515C9.92512 22.2461 7.79896 21.1093 6.25855 19.3527C4.71814 17.596 3.86848 15.3393 3.86782 13.0027L3.86776 12.8055C3.8676 12.2611 3.42614 11.8199 2.88173 11.8201L2.48743 11.8202C2.22599 11.8203 1.97529 11.9242 1.79048 12.1091C1.60566 12.294 1.50188 12.5448 1.50195 12.8062L1.50201 13.0034C1.50284 15.9137 2.56111 18.7245 4.47982 20.9126C6.39853 23.1006 9.04692 24.5166 11.9319 24.897C14.8168 25.2774 17.7417 24.5962 20.1618 22.9803C22.5819 21.3643 24.3324 18.9238 25.0873 16.1131C25.8422 13.3024 25.55 10.3132 24.2653 7.70186C22.9806 5.09056 20.7908 3.03519 18.1036 1.91848C15.4164 0.801783 12.415 0.699887 9.65833 1.63178Z" fill="#0542CC" stroke="#0542CC" stroke-width="1.125" stroke-linecap="square" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,98 @@
|
||||
<svg width="852" height="736" viewBox="0 0 852 736" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="850" height="734.13" fill="#0542CC"/>
|
||||
<path d="M851 1H1V730H851V1Z" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 16.0898H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 31.4043H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 46.4941H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 61.8066H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 76.8984H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 92.207H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 107.297H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 122.391H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 137.699H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 152.793H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 168.102H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 183.195H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 198.508H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 213.598H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 228.688H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 244H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 259.09H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 274.406H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 289.496H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 304.809H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 319.895H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 334.984H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 350.297H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 365.391H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 380.699H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 395.793H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 411.105H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 426.191H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 441.285H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 456.598H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 471.688H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 487H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 502.09H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 517.402H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 532.492H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 547.582H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 562.895H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 577.984H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 593.301H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 608.391H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 623.703H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 638.793H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 653.883H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 669.195H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 684.285H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 699.594H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M851 714.684H1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M18.7305 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M36.4531 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M54.1797 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M71.7812 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M89.5039 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M107.234 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M124.961 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M142.688 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M160.414 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M178.145 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M195.738 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M213.469 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M231.199 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M248.918 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M266.648 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M284.379 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M302.102 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M319.703 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M337.43 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M355.156 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M372.883 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M390.609 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M408.336 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M425.938 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M443.664 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M461.387 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M479.117 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M496.844 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M514.57 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M532.297 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M549.898 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M567.625 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M585.352 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M603.078 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M620.805 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M638.531 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M656.262 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M673.855 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M691.586 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M709.312 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M727.039 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M744.766 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M762.496 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M780.219 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M797.82 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M815.547 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M833.27 730V1" stroke="#040F2D" stroke-opacity="0.1" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="109" height="108" viewBox="0 0 109 108" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.76" d="M19.6973 54.948C19.6973 33.3228 34.9804 17 55.0461 17C75.1118 17 90.3949 34.0506 90.3949 54.948C90.3949 75.8454 75.1118 93 55.0461 93C34.9804 93 19.6973 76.4692 19.6973 54.948ZM31.3416 54.948C31.3416 68.2558 39.7629 81.7715 55.0461 81.7715C70.3293 81.7715 78.6466 68.2558 78.6466 54.948C78.6466 41.5362 70.3293 28.2285 55.0461 28.2285C39.7629 28.2285 31.3416 41.5362 31.3416 54.948Z" fill="#26EFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 532 B |
@@ -0,0 +1,21 @@
|
||||
<svg width="212" height="212" viewBox="0 0 212 212" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="71.5029" y="69.1201" width="77.4624" height="79.8459" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M67.929 211.333L67.9291 -5.27867e-07L77.4629 0L77.4629 211.333L67.929 211.333Z" fill="#F1F6FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M144.2 211.333L144.2 -5.27867e-07L153.733 0L153.733 211.333L144.2 211.333Z" fill="#F1F6FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-0.00129605 67.5326L211.332 67.5326L211.332 77.0664L-0.001297 77.0664L-0.00129605 67.5326Z" fill="#F1F6FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-0.00129605 143.803L211.332 143.803L211.332 153.337L-0.001297 153.337L-0.00129605 143.803Z" fill="#F1F6FF"/>
|
||||
<path d="M30.4925 41.7792L22.7818 52.9247H14.3701L27.7587 34.3489L15.2113 17.876H23.623L30.4925 27.5494C31.3337 28.7411 31.1234 30.4935 31.1234 31.9656H32.5254C32.5254 30.4935 32.4553 28.7411 33.2264 27.6195L40.4464 17.876H48.8581L36.0303 35.0499L49.6993 52.9247H41.2876L33.2964 41.7792C32.4553 40.5175 32.5254 38.6949 32.5254 37.2229H31.1234C31.1234 38.765 31.3337 40.5175 30.4925 41.7792Z" fill="#FE28CB"/>
|
||||
<path d="M15.4922 108.686C15.4922 96.7875 23.901 87.8066 34.9412 87.8066C45.9814 87.8066 54.3902 97.1879 54.3902 108.686C54.3902 120.184 45.9814 129.622 34.9412 129.622C23.901 129.622 15.4922 120.527 15.4922 108.686ZM21.8989 108.686C21.8989 116.008 26.5324 123.444 34.9412 123.444C43.3501 123.444 47.9263 116.008 47.9263 108.686C47.9263 101.307 43.3501 93.9846 34.9412 93.9846C26.5324 93.9846 21.8989 101.307 21.8989 108.686Z" fill="#3EF1FF"/>
|
||||
<path d="M171.399 108.686C171.399 96.7875 179.808 87.8066 190.848 87.8066C201.889 87.8066 210.297 97.1879 210.297 108.686C210.297 120.184 201.889 129.622 190.848 129.622C179.808 129.622 171.399 120.527 171.399 108.686ZM177.806 108.686C177.806 116.008 182.44 123.444 190.848 123.444C199.257 123.444 203.834 116.008 203.834 108.686C203.834 101.307 199.257 93.9846 190.848 93.9846C182.44 93.9846 177.806 101.307 177.806 108.686Z" fill="#3EF1FF"/>
|
||||
<path d="M92.9541 35.1799C92.9541 23.2817 101.363 14.3008 112.403 14.3008C123.443 14.3008 131.852 23.6821 131.852 35.1799C131.852 46.6777 123.443 56.1162 112.403 56.1162C101.363 56.1162 92.9541 47.0209 92.9541 35.1799ZM99.3608 35.1799C99.3608 42.5019 103.994 49.9383 112.403 49.9383C120.812 49.9383 125.388 42.5019 125.388 35.1799C125.388 27.8007 120.812 20.4787 112.403 20.4787C103.994 20.4787 99.3608 27.8007 99.3608 35.1799Z" fill="#3EF1FF"/>
|
||||
<path d="M95.1289 182.572C95.1289 170.674 103.538 161.693 114.578 161.693C125.618 161.693 134.027 171.075 134.027 182.572C134.027 194.07 125.618 203.509 114.578 203.509C103.538 203.509 95.1289 194.413 95.1289 182.572ZM101.536 182.572C101.536 189.894 106.169 197.331 114.578 197.331C122.987 197.331 127.563 189.894 127.563 182.572C127.563 175.193 122.987 167.871 114.578 167.871C106.169 167.871 101.536 175.193 101.536 182.572Z" fill="#3EF1FF"/>
|
||||
<path d="M191.306 41.7792L183.595 52.9247H175.184L188.572 34.3489L176.025 17.876H184.436L191.306 27.5494C192.147 28.7411 191.937 30.4935 191.937 31.9656H193.339C193.339 30.4935 193.269 28.7411 194.04 27.6195L201.26 17.876H209.672L196.844 35.0499L210.513 52.9247H202.101L194.11 41.7792C193.269 40.5175 193.339 38.6949 193.339 37.2229H191.937C191.937 38.765 192.147 40.5175 191.306 41.7792Z" fill="#FE28CB"/>
|
||||
<path d="M30.4925 189.064L22.7818 200.21H14.3701L27.7587 181.634L15.2113 165.161H23.623L30.4925 174.835C31.3337 176.026 31.1234 177.779 31.1234 179.251H32.5254C32.5254 177.779 32.4553 176.026 33.2264 174.905L40.4464 165.161H48.8581L36.0303 182.335L49.6993 200.21H41.2876L33.2964 189.064C32.4553 187.803 32.5254 185.98 32.5254 184.508H31.1234C31.1234 186.05 31.3337 187.803 30.4925 189.064Z" fill="#FE28CB"/>
|
||||
<path d="M192.568 195.023L184.857 206.169H176.445L189.834 187.593L177.286 171.12H185.698L192.568 180.794C193.409 181.985 193.199 183.738 193.199 185.21H194.601C194.601 183.738 194.53 181.985 195.302 180.864L202.522 171.12H210.933L198.105 188.294L211.774 206.169H203.363L195.372 195.023C194.53 193.762 194.601 191.939 194.601 190.467H193.199C193.199 192.009 193.409 193.762 192.568 195.023Z" fill="#FE28CB"/>
|
||||
<path d="M131.208 119.697H131.879L131.8 119.031C131.605 117.387 130.84 115.898 129.517 114.824C128.196 113.752 126.361 113.127 124.074 113.127C119.213 113.127 115.655 116.882 115.655 121.812C115.655 126.769 119.261 130.543 124.163 130.543C126.389 130.543 128.218 130.003 129.563 128.969C130.916 127.929 131.724 126.43 131.976 124.629L132.071 123.95H131.386H128.83H128.376L128.256 124.388C128.068 125.07 127.736 125.691 127.138 126.148C126.538 126.606 125.605 126.951 124.119 126.951C121.387 126.951 119.336 124.89 119.336 121.835C119.336 118.753 121.39 116.697 124.096 116.697C125.532 116.697 126.43 117.044 127.007 117.501C127.587 117.96 127.911 118.584 128.101 119.261L128.222 119.697H128.675H131.208Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.19173"/>
|
||||
<path d="M100.375 129.384L100.077 130.187H100.934H103.623H104.043L104.184 129.791L105.999 124.698H110.527L112.513 129.807L112.661 130.187H113.068H115.735H116.606L116.291 129.376L110.246 113.796L110.098 113.416H109.69H106.712H106.298L106.153 113.805L100.375 129.384ZM106.788 121.55L108.204 118.201L109.65 121.55H106.788Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.19173"/>
|
||||
<path d="M96.1807 130.209H96.7765V129.613V116.963H100.492H101.088V116.367V114.056V113.46H100.492H89.3799H88.784V114.056V116.367V116.963H89.3799H93.0956V129.613V130.209H93.6915H96.1807Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.19173"/>
|
||||
<path d="M131.987 98.0805H132.657L132.578 97.4145C132.333 95.3426 131.369 93.4694 129.705 92.1191C128.044 90.7705 125.725 89.9754 122.816 89.9754C116.667 89.9754 112.165 94.7198 112.165 100.97C112.165 107.252 116.728 112.021 122.931 112.021C125.766 112.021 128.077 111.335 129.768 110.034C131.468 108.727 132.487 106.843 132.805 104.566L132.9 103.888H132.215H128.93H128.476L128.355 104.325C128.108 105.226 127.664 106.061 126.858 106.678C126.05 107.295 124.81 107.744 122.874 107.744C119.26 107.744 116.556 105.012 116.556 100.998C116.556 96.9531 119.263 94.2239 122.845 94.2239C124.719 94.2239 125.913 94.6774 126.692 95.2949C127.474 95.9141 127.906 96.7514 128.156 97.645L128.278 98.0805H128.73H131.987Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.19173"/>
|
||||
<path d="M106.483 110.997V111.593H107.079H110.307H110.903V110.997V91V90.4041H110.307H107.079H106.483V91V110.997Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.19173"/>
|
||||
<path d="M98.1215 111.593H98.7174V110.997V94.5669H103.664H104.259V93.971V91V90.4041H103.664H89.3799H88.784V91V93.971V94.5669H89.3799H94.3261V110.997V111.593H94.922H98.1215Z" fill="#9747FF" stroke="#9747FF" stroke-width="1.19173"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.6 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="108" height="108" viewBox="0 0 108 108" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M51.1359 68.1903L34.329 92.484H15.9941L45.1771 51.9946L17.8276 16.0889H36.1624L51.1359 37.1739C52.9694 39.7713 52.511 43.5911 52.511 46.7997H55.5668C55.5668 43.5911 55.414 39.7713 57.0947 37.3267L72.8321 16.0889H91.1669L63.2063 53.5225L93.0004 92.484H74.6656L57.2475 68.1903C55.414 65.4401 55.5668 61.4676 55.5668 58.259H52.511C52.511 61.6203 52.9694 65.4401 51.1359 68.1903Z" fill="#FE28CB"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 510 B |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,10 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_5040_22067)">
|
||||
<path d="M7.49997 7H11V8.181L8.65097 11H11V12H7.49997V10.819L9.84897 8H7.49997V7ZM11 1.75V5H9.99997V3.5H8.49997V5H7.49997V1.75C7.49997 0.785 8.28497 0 9.24997 0C10.215 0 11 0.785 11 1.75ZM9.99997 2.5V1.75C9.99997 1.3365 9.66347 1 9.24997 1C8.83647 1 8.49997 1.3365 8.49997 1.75V2.5H9.99997ZM3.49997 10.5V0H2.49997V10.5L0.749969 8.75L0.0429688 9.457L2.29297 11.707C2.48797 11.902 2.74397 11.9995 2.99997 11.9995C3.25597 11.9995 3.51197 11.902 3.70697 11.707L5.95697 9.457L5.24997 8.75L3.49997 10.5Z" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_5040_22067">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 765 B |
|
After Width: | Height: | Size: 9.3 KiB |
@@ -0,0 +1,10 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_5040_22071)">
|
||||
<path d="M9 0C7.343 0 6 1.343 6 3C6 4.657 7.343 6 9 6C10.657 6 12 4.657 12 3C12 1.343 10.657 0 9 0ZM10.768 4.0605L10.061 4.7675L9.0005 3.707L7.94 4.7675L7.233 4.0605L8.2935 3L7.233 1.9395L7.94 1.2325L9.0005 2.293L10.061 1.2325L10.768 1.9395L9.7075 3L10.768 4.0605ZM7.448 6.686L7.0005 7.1895V11.9995L4.0005 9.7495V7.1895L0 2.69V1.5C0 0.673 0.673 0 1.5 0H6.363C5.5295 0.7335 5 1.805 5 3C5 4.6555 6.0115 6.0785 7.448 6.686Z" fill="#040F2D"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_5040_22071">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 690 B |
@@ -12,7 +12,7 @@
|
||||
|
||||
## ✨ About ClassroomIO
|
||||
|
||||
<img alt="ClassroomIO Courses page" src="https://classroomio.com/classroomio-courses.png" />
|
||||
<img alt="ClassroomIO Courses page" src="https://brand.cdn.clsrio.com/classroomio-courses.png" />
|
||||
|
||||
Streamline training for everyone with ClassroomIO.com. Our all-in-one platform empowers bootcamps, educators, and businesses to manage training programs easily. With our platform, anyone can run multiple classes and cohorts all from one UI. The application is mobile-first, which means that students can access your lesson materials from any device.
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<script lang="ts">
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
||||
import { supabase } from '$lib/utils/functions/supabase';
|
||||
import { capturePosthogEvent } from '$lib/utils/services/posthog';
|
||||
import { currentOrg, orgs, defaultCurrentOrgState } from '$lib/utils/store/org';
|
||||
import { user, profile, defaultProfileState, defaultUserState } from '$lib/utils/store/user';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import posthog from 'posthog-js';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
async function logout() {
|
||||
const { error } = await supabase.auth.signOut();
|
||||
|
||||
if (error) {
|
||||
console.error('Error logging out: ', error);
|
||||
}
|
||||
|
||||
currentOrg.set(defaultCurrentOrgState);
|
||||
orgs.set([]);
|
||||
user.set(defaultUserState);
|
||||
profile.set(defaultProfileState);
|
||||
|
||||
capturePosthogEvent('user_logged_out');
|
||||
posthog.reset();
|
||||
goto('/login');
|
||||
}
|
||||
</script>
|
||||
|
||||
<PrimaryButton variant={VARIANTS.OUTLINED} label={$t('settings.profile.logout')} onClick={logout} />
|
||||
@@ -3,16 +3,17 @@
|
||||
import HelpIcon from 'carbon-icons-svelte/lib/Help.svelte';
|
||||
import LicenseDraft from 'carbon-icons-svelte/lib/LicenseDraft.svelte';
|
||||
import Explore from 'carbon-icons-svelte/lib/Explore.svelte';
|
||||
import Settings from 'carbon-icons-svelte/lib/Settings.svelte';
|
||||
import HomeIcon from '$lib/components/Icons/HomeIcon.svelte';
|
||||
import CourseIcon from '$lib/components/Icons/CourseIcon.svelte';
|
||||
import CommunityIcon from '$lib/components/Icons/CommunityIcon.svelte';
|
||||
import Avatar from '$lib/components/Avatar/index.svelte';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { NavClasses } from '$lib/utils/constants/reusableClass';
|
||||
import { sideBar } from '$lib/components/Org/store';
|
||||
import { profileMenu, sideBar } from '$lib/components/Org/store';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { currentOrg } from '$lib/utils/store/org';
|
||||
import { ChevronRight } from 'carbon-icons-svelte';
|
||||
import ProfileMenu from '$lib/components/Org/ProfileMenu/index.svelte';
|
||||
|
||||
interface SideLinks {
|
||||
name: string;
|
||||
@@ -73,11 +74,12 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<div bind:this={$profileMenu.ref} class="static md:relative">
|
||||
<aside
|
||||
class={`${
|
||||
$sideBar.hidden
|
||||
? '-translate-x-[100%] absolute md:translate-x-0 md:relative z-40'
|
||||
: 'translate-x-0 absolute md:relative z-40'
|
||||
? '-translate-x-[100%] absolute md:translate-x-0 md:relative z-40 top-[48px] md:top-0'
|
||||
: 'translate-x-0 absolute md:relative z-40 top-[48px] md:top-0'
|
||||
} overflow-y-auto transition w-[250px] min-w-[250px] bg-gray-100 dark:bg-neutral-900 h-[calc(100vh-48px)]`}
|
||||
>
|
||||
<div class="h-full flex flex-col">
|
||||
@@ -101,7 +103,7 @@
|
||||
</div>
|
||||
|
||||
<ul class="my-5">
|
||||
{#each sideLinks as item (item.link)}
|
||||
{#each sideLinks as item (item.name)}
|
||||
<a href={item.link} class="text-black" on:click={toggleSidebar}>
|
||||
<li
|
||||
class="flex items-center py-3 px-4 mb-2 {NavClasses.item} {isActive(
|
||||
@@ -126,17 +128,33 @@
|
||||
<p class="dark:text-white ml-2">{$t('lms_navigation.help')}</p>
|
||||
</li>
|
||||
</a>
|
||||
<a href="/lms/settings" class="text-black" on:click={toggleSidebar}>
|
||||
<li
|
||||
class="flex items-center py-3 px-4 mb-2 {NavClasses.item} {isActive(
|
||||
$page.url.pathname,
|
||||
`/lms/settings`
|
||||
) && NavClasses.active}"
|
||||
<button
|
||||
class="w-full"
|
||||
on:click={() => {
|
||||
$profileMenu.open = !$profileMenu.open;
|
||||
$sideBar.hidden = true;
|
||||
}}
|
||||
>
|
||||
<Settings size={20} class="carbon-icon dark:text-white" />
|
||||
<p class="dark:text-white ml-2">{$t('lms_navigation.settings')}</p>
|
||||
</li>
|
||||
</a>
|
||||
<div
|
||||
class="text-black no-underline cursor-pointer flex items-center justify-between mb-2 px-2.5 py-1.5 w-full {NavClasses.item}"
|
||||
>
|
||||
<div class="flex text-start items-center justify-start space-x-1">
|
||||
<Avatar
|
||||
src={$profile.avatar_url}
|
||||
name={$profile.username}
|
||||
width="w-[1.2rem]"
|
||||
height="h-[1.2rem]"
|
||||
/>
|
||||
<p class="text-sm font-medium truncate max-w-full">{$profile.fullname}</p>
|
||||
</div>
|
||||
<div>
|
||||
<ChevronRight />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<ProfileMenu />
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
import { supabase } from '$lib/utils/functions/supabase';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { snackbar } from '$lib/components/Snackbar/store';
|
||||
import LogoutButton from '$lib/components/Buttons/Logout/index.svelte';
|
||||
import generateUUID from '$lib/utils/functions/generateUUID';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import LanguagePicker from '$lib/components/Org/Settings/LanguagePicker.svelte';
|
||||
@@ -120,6 +119,5 @@
|
||||
isDisabled={loading}
|
||||
onClick={handleUpdate}
|
||||
/>
|
||||
<LogoutButton />
|
||||
</Row>
|
||||
</Grid>
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
<script>
|
||||
import { globalStore } from '$lib/utils/store/app';
|
||||
import { user, profile, defaultProfileState, defaultUserState } from '$lib/utils/store/user';
|
||||
import {
|
||||
currentOrg,
|
||||
orgs,
|
||||
defaultCurrentOrgState,
|
||||
currentOrgDomain,
|
||||
currentOrgPath
|
||||
} from '$lib/utils/store/org';
|
||||
import { ChevronDown, Settings } from 'carbon-icons-svelte';
|
||||
import Logout from 'carbon-icons-svelte/lib/Logout.svelte';
|
||||
import Rocket from 'carbon-icons-svelte/lib/Rocket.svelte';
|
||||
import NewTab from 'carbon-icons-svelte/lib/NewTab.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { profileMenu } from '../store';
|
||||
import { supabase } from '$lib/utils/functions/supabase';
|
||||
import { capturePosthogEvent } from '$lib/utils/services/posthog';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import posthog from 'posthog-js';
|
||||
|
||||
async function logout() {
|
||||
const { error } = await supabase.auth.signOut();
|
||||
|
||||
if (error) {
|
||||
console.error('Error logging out: ', error);
|
||||
}
|
||||
|
||||
currentOrg.set(defaultCurrentOrgState);
|
||||
orgs.set([]);
|
||||
user.set(defaultUserState);
|
||||
profile.set(defaultProfileState);
|
||||
|
||||
capturePosthogEvent('user_logged_out');
|
||||
posthog.reset();
|
||||
|
||||
closeMenu();
|
||||
|
||||
goto('/login');
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
$profileMenu.open = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="md:px-4 md:py-4 py-2 px-2 rounded-md cursor-pointer">
|
||||
<div class="border-b py-3 space-y-4">
|
||||
<p class="text-xs font-semibold text-gray-500">{$t('profileMenu.profile')}</p>
|
||||
<a
|
||||
href={`${!$globalStore.isOrgSite ? $currentOrgPath : '/lms'}/settings`}
|
||||
class="flex items-center justify-between hover:no-underline"
|
||||
on:click={closeMenu}
|
||||
>
|
||||
<span class="flex items-center gap-2 max-w-[70%]">
|
||||
<img src={$profile.avatar_url} alt="profile" class="h-8 w-8 rounded-full" />
|
||||
<div>
|
||||
<p class="text-sm font-semibold w-[80%] truncate">{$profile.fullname}</p>
|
||||
<p class="text-xs w-[80%] truncate">{$profile.email}</p>
|
||||
</div>
|
||||
</span>
|
||||
<div>
|
||||
<Settings size={20} />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{#if !$globalStore.isOrgSite}
|
||||
<div class="border-b py-3 space-y-4">
|
||||
<p class="text-xs font-semibold text-gray-500">{$t('profileMenu.current_org')}</p>
|
||||
<a
|
||||
href={`${$currentOrgPath}/settings?tab=org`}
|
||||
class="flex items-center justify-between hover:no-underline"
|
||||
on:click={closeMenu}
|
||||
>
|
||||
<span class="flex items-center gap-2 max-w-[70%]">
|
||||
<div
|
||||
class="flex items-center justify-center h-8 w-8 p-4 bg-blue-900 text-white font-semibold rounded-lg"
|
||||
>
|
||||
{$currentOrg.shortName}
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-semibold w-[80%] truncate">{$currentOrg.name}</p>
|
||||
<p class="text-xs w-[80%] truncate">
|
||||
{$currentOrgDomain}
|
||||
</p>
|
||||
</div>
|
||||
</span>
|
||||
<div>
|
||||
<Settings size={20} />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="border-b py-3 space-y-4">
|
||||
<p class="text-xs font-semibold text-gray-500">{$t('profileMenu.free_tools')}</p>
|
||||
<a
|
||||
href="https://classroomio.com/tools/progress"
|
||||
target="_blank"
|
||||
class="flex items-center gap-2"
|
||||
on:click={closeMenu}
|
||||
>
|
||||
<img src="/progress.svg" alt="progress" class="h-6 w-6 rounded-full" />
|
||||
<p class="text-sm font-semibold">{$t('profileMenu.progress')}</p>
|
||||
</a>
|
||||
<a
|
||||
href="https://classroomio.com/tools/activity-stopwatch"
|
||||
target="_blank"
|
||||
class=" flex items-center gap-2"
|
||||
on:click={closeMenu}
|
||||
>
|
||||
<img src="/timer.svg" alt="timer" class="h-6 w-6 rounded-full" />
|
||||
<p class="text-sm font-semibold">{$t('profileMenu.timer')}</p>
|
||||
</a>
|
||||
<a
|
||||
href="https://classroomio.com/tools/tic-tac-toe"
|
||||
target="_blank"
|
||||
class=" flex items-center gap-2"
|
||||
on:click={closeMenu}
|
||||
>
|
||||
<img src="/tictac.svg" alt="tic_tac_toe" class="h-6 w-6 rounded-full" />
|
||||
<p class="text-sm font-semibold">{$t('profileMenu.tic_tac')}</p>
|
||||
</a>
|
||||
<a
|
||||
href="https://classroomio.com/tools"
|
||||
on:click={closeMenu}
|
||||
target="_blank"
|
||||
class="flex ml-auto w-fit items-center justify-end"
|
||||
>
|
||||
<div class="text-blue-900 font-semibold text-xs flex items-center gap-1">
|
||||
{$t('profileMenu.see_more')}
|
||||
<ChevronDown class="text-blue-900" />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{#if !$globalStore.isOrgSite}
|
||||
<div class="border-b py-3 space-y-4">
|
||||
<a
|
||||
href="https://classroomio.com/roadmap"
|
||||
target="_blank"
|
||||
on:click={closeMenu}
|
||||
class="hover:no-underline flex items-center gap-2"
|
||||
>
|
||||
<NewTab />
|
||||
<p class="text-sm font-semibold">{$t('profileMenu.whats_new')}</p>
|
||||
</a>
|
||||
<a
|
||||
href="https://classroomio.com/blog/launch-week"
|
||||
target="_blank"
|
||||
on:click={closeMenu}
|
||||
class="hover:no-underline flex items-center gap-2"
|
||||
>
|
||||
<Rocket />
|
||||
<p class="text-sm font-semibold">{$t('profileMenu.launch_week')}</p>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<button on:click={logout} class="w-full pt-3 space-y-4">
|
||||
<span class="flex items-center gap-2">
|
||||
<Logout />
|
||||
<p class="text-sm font-semibold">{$t('settings.profile.logout')}</p>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { Popover } from 'carbon-components-svelte';
|
||||
import Menu from './Menu.svelte';
|
||||
import Modal from '$lib/components/Modal/index.svelte';
|
||||
import { isMobile } from '$lib/utils/store/useMobile';
|
||||
import { profileMenu } from '../store';
|
||||
</script>
|
||||
|
||||
{#if $isMobile}
|
||||
<Modal
|
||||
bind:open={$profileMenu.open}
|
||||
onClose={() => ($profileMenu.open = false)}
|
||||
width="w-4/5"
|
||||
containerClass="h-full !max-h-[70vh] pt-0 pb-2"
|
||||
headerClass="py-1"
|
||||
>
|
||||
<Menu />
|
||||
</Modal>
|
||||
{:else}
|
||||
<Popover
|
||||
bind:open={$profileMenu.open}
|
||||
align="right-bottom"
|
||||
caret={true}
|
||||
on:click:outside={({ detail }) => {
|
||||
console.log('on:click:outside');
|
||||
$profileMenu.open = !!$profileMenu.ref?.contains(detail.target);
|
||||
}}
|
||||
>
|
||||
<Menu />
|
||||
</Popover>
|
||||
{/if}
|
||||
@@ -8,7 +8,6 @@
|
||||
import { supabase } from '$lib/utils/functions/supabase';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { snackbar } from '$lib/components/Snackbar/store';
|
||||
import LogoutButton from '$lib/components/Buttons/Logout/index.svelte';
|
||||
import generateUUID from '$lib/utils/functions/generateUUID';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import LanguagePicker from './LanguagePicker.svelte';
|
||||
@@ -129,6 +128,5 @@
|
||||
isDisabled={loading}
|
||||
onClick={handleUpdate}
|
||||
/>
|
||||
<LogoutButton />
|
||||
</Row>
|
||||
</Grid>
|
||||
|
||||
@@ -21,24 +21,21 @@
|
||||
|
||||
function getSelectedByTab(tabKey = '') {
|
||||
const tab = tabs.find((t) => t.tabKey === tabKey);
|
||||
|
||||
return tab ? tab.key : 0;
|
||||
}
|
||||
function changeRouteOnTabChange(key = 0) {
|
||||
|
||||
function onTabChange(e) {
|
||||
const key = e.detail;
|
||||
const tab = tabs.find((t) => t.key === key);
|
||||
if (tab) {
|
||||
return goto(tab.href);
|
||||
goto(tab.href);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
$: if (browser) {
|
||||
query = new URLSearchParams($page.url.search);
|
||||
tabKey = query.get('tab') || '';
|
||||
selected = getSelectedByTab(tabKey);
|
||||
});
|
||||
|
||||
$: {
|
||||
if (browser) {
|
||||
changeRouteOnTabChange(selected);
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
@@ -82,7 +79,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Tabs autoWidth bind:selected>
|
||||
<Tabs autoWidth bind:selected on:change={onTabChange}>
|
||||
{#each tabs as tab}
|
||||
<Tab label={tab.label} href={tab.href} disabled={tab.disabled} />
|
||||
{/each}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { page } from '$app/stores';
|
||||
import HelpIcon from 'carbon-icons-svelte/lib/Help.svelte';
|
||||
import ForumIcon from 'carbon-icons-svelte/lib/Forum.svelte';
|
||||
import { SettingsAdjust } from 'carbon-icons-svelte';
|
||||
import { ChevronRight, SettingsAdjust } from 'carbon-icons-svelte';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import OrgSelector from '$lib/components/OrgSelector/OrgSelector.svelte';
|
||||
import HomeIcon from '$lib/components/Icons/HomeIcon.svelte';
|
||||
@@ -11,13 +11,15 @@
|
||||
import SiteSettingsIcon from '$lib/components/Icons/SiteSettingsIcon.svelte';
|
||||
import AudienceIcon from '$lib/components/Icons/AudienceIcon.svelte';
|
||||
import Avatar from '$lib/components/Avatar/index.svelte';
|
||||
import { currentOrgPath, currentOrgPlan, isFreePlan } from '$lib/utils/store/org';
|
||||
import { currentOrgPath, isFreePlan } from '$lib/utils/store/org';
|
||||
|
||||
import { isOrgAdmin } from '$lib/utils/store/org';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { NavClasses } from '$lib/utils/constants/reusableClass';
|
||||
import { sideBar } from './store';
|
||||
import { sideBar, profileMenu } from './store';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { goto } from '$app/navigation';
|
||||
import ProfileMenu from '$lib/components/Org/ProfileMenu/index.svelte';
|
||||
|
||||
interface menuItems {
|
||||
label: string;
|
||||
@@ -45,43 +47,6 @@
|
||||
goto(window.location.pathname + '?upgrade=true');
|
||||
};
|
||||
|
||||
// $: {
|
||||
// menuItems = [
|
||||
// {
|
||||
// path: '',
|
||||
// label: 'Dashboard',
|
||||
// show: true
|
||||
// },
|
||||
// // {
|
||||
// // path: '/quiz',
|
||||
// // label: 'Quizzes'
|
||||
// // },
|
||||
// {
|
||||
// path: '/courses',
|
||||
// label: 'Courses',
|
||||
// show: true
|
||||
// },
|
||||
// {
|
||||
// path: '/community',
|
||||
// label: 'Community',
|
||||
// show: true
|
||||
// },
|
||||
// // {
|
||||
// // path: '/site',
|
||||
// // label: 'Site settings',
|
||||
// // },
|
||||
// {
|
||||
// path: '/audience',
|
||||
// label: 'Audience',
|
||||
// show: true
|
||||
// },
|
||||
// {
|
||||
// path: '/setup',
|
||||
// label: 'Setup',
|
||||
// show: $isOrgAdmin
|
||||
// }
|
||||
// ];
|
||||
// }
|
||||
$: menuItems = [
|
||||
{
|
||||
path: '',
|
||||
@@ -111,11 +76,12 @@
|
||||
];
|
||||
</script>
|
||||
|
||||
<div bind:this={$profileMenu.ref} class="static md:relative">
|
||||
<aside
|
||||
class={`${
|
||||
$sideBar.hidden
|
||||
? 'absolute z-40 -translate-x-[100%] md:relative md:translate-x-0'
|
||||
: 'absolute z-40 translate-x-0 md:relative'
|
||||
? 'absolute z-40 -translate-x-[100%] md:relative md:translate-x-0 top-[48px] md:top-0'
|
||||
: 'absolute z-40 translate-x-0 md:relative top-[48px] md:top-0'
|
||||
} border-r-1 h-[calc(100vh-48px)] w-[250px] min-w-[250px] overflow-y-auto border border-b-0 border-l-0 border-t-0 border-gray-100 dark:border-neutral-600 bg-gray-100 transition dark:bg-neutral-900`}
|
||||
>
|
||||
<div class="flex h-full flex-col">
|
||||
@@ -186,24 +152,34 @@
|
||||
<p class="ml-2.5 dark:text-white text-sm font-medium">{$t('org_navigation.help')}</p>
|
||||
</li>
|
||||
</a>
|
||||
<a href="{$currentOrgPath}/settings" class="text-black no-underline" on:click={toggleSidebar}>
|
||||
<li
|
||||
class="mb-2 flex items-center px-2.5 py-1.5 {NavClasses.item} {isActive(
|
||||
$page.url.pathname,
|
||||
`${$currentOrgPath}/settings`
|
||||
)
|
||||
? NavClasses.active
|
||||
: 'dark:text-white'}"
|
||||
|
||||
<button
|
||||
class="w-full"
|
||||
on:click={() => {
|
||||
$profileMenu.open = !$profileMenu.open;
|
||||
$sideBar.hidden = true;
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="text-black no-underline cursor-pointer flex items-center justify-between gap-2.5 px-2.5 py-2 mb-2 {NavClasses.item}"
|
||||
>
|
||||
<div class="flex text-start items-center justify-start space-x-1 w-full">
|
||||
<Avatar
|
||||
src={$profile.avatar_url}
|
||||
name={$profile.username}
|
||||
width="w-[1.2rem]"
|
||||
height="h-[1.2rem]"
|
||||
/>
|
||||
<p class="ml-2.5 text-sm font-medium">{$t('org_navigation.settings')}</p>
|
||||
</li>
|
||||
</a>
|
||||
<p class="text-sm font-medium truncate max-w-full">{$profile.fullname}</p>
|
||||
</div>
|
||||
<div>
|
||||
<ChevronRight />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<ProfileMenu />
|
||||
</div>
|
||||
|
||||
@@ -7,3 +7,11 @@ export const newOrgModal = writable({
|
||||
export const sideBar = writable({
|
||||
hidden: true
|
||||
});
|
||||
|
||||
export const profileMenu = writable<{
|
||||
ref?: HTMLDivElement;
|
||||
open: boolean;
|
||||
}>({
|
||||
ref: undefined,
|
||||
open: false
|
||||
});
|
||||
@@ -1326,6 +1326,17 @@
|
||||
"specialization": {
|
||||
"course_tag": "Spezialisierung"
|
||||
},
|
||||
"profileMenu": {
|
||||
"profile": "PROFIL",
|
||||
"current_org": "AKTUELLE ORGANISATION",
|
||||
"free_tools": "KOSTENLOSE WERKZEUGE",
|
||||
"progress": "Fortschrittsbericht",
|
||||
"timer": "Aktivitätstimer",
|
||||
"tic_tac": "Tictac-Zehe",
|
||||
"see_more": "Mehr sehen",
|
||||
"whats_new": "Was ist neu",
|
||||
"launch_week": "Startwoche"
|
||||
},
|
||||
"validations": {
|
||||
"invalid_type_error": "Darf nicht leer sein",
|
||||
"email": {
|
||||
|
||||
@@ -49,7 +49,18 @@
|
||||
"forgot": "Forgot password?",
|
||||
"login": "Log In"
|
||||
},
|
||||
"profileMenu": {
|
||||
"profile": "PROFILE",
|
||||
"current_org": "CURRENT ORGANIZATION",
|
||||
"free_tools": "FREE TOOLS",
|
||||
"progress": "Progress report",
|
||||
"timer": "Activity timer",
|
||||
"tic_tac": "Tictac toe",
|
||||
"see_more": "See more",
|
||||
|
||||
"whats_new": "What's new",
|
||||
"launch_week": "Launch week"
|
||||
},
|
||||
"settings": {
|
||||
"heading": "Settings",
|
||||
"subheadings": {
|
||||
|
||||
@@ -1326,6 +1326,17 @@
|
||||
"specialization": {
|
||||
"course_tag": "Especialización"
|
||||
},
|
||||
"profileMenu": {
|
||||
"profile": "PERFIL",
|
||||
"current_org": "ORGANIZACIÓN ACTUAL",
|
||||
"free_tools": "HERRAMIENTAS GRATUITAS",
|
||||
"progress": "Informe de progreso",
|
||||
"timer": "Temporizador de actividad",
|
||||
"tic_tac": "dedo del pie tres en raya",
|
||||
"see_more": "Ver más",
|
||||
"whats_new": "Qué hay de nuevo",
|
||||
"launch_week": "Semana de lanzamiento"
|
||||
},
|
||||
"validations": {
|
||||
"invalid_type_error": "No debe estar vacío",
|
||||
"email": {
|
||||
|
||||
@@ -1326,6 +1326,17 @@
|
||||
"specialization": {
|
||||
"course_tag": "Spécialisation"
|
||||
},
|
||||
"profileMenu": {
|
||||
"profile": "PROFIL",
|
||||
"current_org": "ORGANISATION ACTUELLE",
|
||||
"free_tools": "OUTILS GRATUITS",
|
||||
"progress": "Rapport d'étape",
|
||||
"timer": "Minuterie d'activité",
|
||||
"tic_tac": "Tic-tac",
|
||||
"see_more": "Voir plus",
|
||||
"whats_new": "Quoi de neuf",
|
||||
"launch_week": "Semaine de lancement"
|
||||
},
|
||||
"validations": {
|
||||
"invalid_type_error": "Ne doit pas être vide",
|
||||
"email": {
|
||||
|
||||
@@ -1326,6 +1326,17 @@
|
||||
"specialization": {
|
||||
"course_tag": "विशेषज्ञता"
|
||||
},
|
||||
"profileMenu": {
|
||||
"profile": "प्रोफ़ाइल",
|
||||
"current_org": "वर्तमान संघ",
|
||||
"free_tools": "मुफ़्त उपकरण",
|
||||
"progress": "प्रगति रिपोर्ट",
|
||||
"timer": "गतिविधि टाइमर",
|
||||
"tic_tac": "टिक टीएसी को पैर की अंगुली",
|
||||
"see_more": "और देखें",
|
||||
"whats_new": "नया क्या है",
|
||||
"launch_week": "लॉन्च सप्ताह"
|
||||
},
|
||||
"validations": {
|
||||
"invalid_type_error": "खाली नहीं होना चाहिए",
|
||||
"email": {
|
||||
|
||||
@@ -1326,6 +1326,17 @@
|
||||
"specialization": {
|
||||
"course_tag": "Especialização"
|
||||
},
|
||||
"profileMenu": {
|
||||
"profile": "PERFIL",
|
||||
"current_org": "ORGANIZAÇÃO ATUAL",
|
||||
"free_tools": "FERRAMENTAS GRATUITAS",
|
||||
"progress": "Relatório de progresso",
|
||||
"timer": "Temporizador de atividade",
|
||||
"tic_tac": "Jogo da velha",
|
||||
"see_more": "Ver mais",
|
||||
"whats_new": "O que há de novo",
|
||||
"launch_week": "Semana de lançamento"
|
||||
},
|
||||
"validations": {
|
||||
"invalid_type_error": "Não deve estar vazio",
|
||||
"email": {
|
||||
|
||||
@@ -1326,6 +1326,17 @@
|
||||
"specialization": {
|
||||
"course_tag": "Специализация"
|
||||
},
|
||||
"profileMenu": {
|
||||
"profile": "ПРОФИЛЬ",
|
||||
"current_org": "ТЕКУЩАЯ ОРГАНИЗАЦИЯ",
|
||||
"free_tools": "БЕСПЛАТНЫЕ ИНСТРУМЕНТЫ",
|
||||
"progress": "Отчет о ходе работы",
|
||||
"timer": "Таймер активности",
|
||||
"tic_tac": "Крестики-нолики",
|
||||
"see_more": "Узнать больше",
|
||||
"whats_new": "Что нового",
|
||||
"launch_week": "Неделя запуска"
|
||||
},
|
||||
"validations": {
|
||||
"invalid_type_error": "Не должно быть пустым",
|
||||
"email": {
|
||||
|
||||
@@ -1326,6 +1326,17 @@
|
||||
"specialization": {
|
||||
"course_tag": "Chuyên môn"
|
||||
},
|
||||
"profileMenu": {
|
||||
"profile": "HỒ SƠ",
|
||||
"current_org": "TỔ CHỨC HIỆN TẠI",
|
||||
"free_tools": "CÔNG CỤ MIỄN PHÍ",
|
||||
"progress": "Báo cáo tiến trình",
|
||||
"timer": "Hẹn giờ hoạt động",
|
||||
"tic_tac": "TIC Tac Toe",
|
||||
"see_more": "Xem thêm",
|
||||
"whats_new": "Có gì mới",
|
||||
"launch_week": "Tuần ra mắt"
|
||||
},
|
||||
"validations": {
|
||||
"invalid_type_error": "Không được để trống",
|
||||
"email": {
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
export let data;
|
||||
|
||||
let ref = null;
|
||||
|
||||
$: if ($currentOrg.id && data.orgName === '*') {
|
||||
const newUrl = $page.url.pathname.replace('*', $currentOrg.siteName);
|
||||
goto(newUrl + $page.url.search);
|
||||
|
||||