Skip to content

Commit

Permalink
Feat: Pomodoro. (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
luanbt21 authored Nov 30, 2022
1 parent bce6a2b commit 1549d1d
Show file tree
Hide file tree
Showing 16 changed files with 213 additions and 30 deletions.
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"cSpell.words": ["pocketbase", "Tiptap", "unfollow", "webpush"],
"cSpell.words": ["pocketbase", "pomodoro", "Tiptap", "unfollow", "webpush"],
"svelte.plugin.svelte.compilerWarnings": {
"a11y-missing-attribute": "ignore",
"a11y-label-has-associated-control": "ignore",
"a11y-no-noninteractive-tabindex": "ignore"
"a11y-no-noninteractive-tabindex": "ignore",
"a11y-click-events-have-key-events": "ignore"
}
}
2 changes: 0 additions & 2 deletions prisma/dbml/schema.dbml
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,6 @@ Table LearnLevel {
postId String [not null]
user User [not null]
userId String [not null]
description String [not null]
icon String [not null]
level Int [not null]
repeating Boolean [not null, default: false]
createdAt DateTime [default: `now()`, not null]
Expand Down
20 changes: 9 additions & 11 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,15 @@ model Comment {
}

model LearnLevel {
id String @id @default(auto()) @map("_id") @db.ObjectId
post Post @relation(fields: [postId], references: [id])
postId String @db.ObjectId
user User @relation(fields: [userId], references: [id])
userId String @db.ObjectId
description String
icon String
level Int
repeating Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
id String @id @default(auto()) @map("_id") @db.ObjectId
post Post @relation(fields: [postId], references: [id])
postId String @db.ObjectId
user User @relation(fields: [userId], references: [id])
userId String @db.ObjectId
level Int
repeating Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model Tag {
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const en: Translation = {
seeMore: 'See more',
haveCommentedOnYourPost: 'have commented on your post.',
postTitle: 'Post title',
start: 'start',
stop: 'stop',
pomodoroReminder: "You've been finished studying, take a break!",
}

export default en
24 changes: 24 additions & 0 deletions src/i18n/i18n-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ type RootTranslation = {
* P​o​s​t​ ​t​i​t​l​e
*/
postTitle: string
/**
* s​t​a​r​t
*/
start: string
/**
* s​t​o​p
*/
stop: string
/**
* Y​o​u​'​v​e​ ​b​e​e​n​ ​f​i​n​i​s​h​e​d​ ​s​t​u​d​y​i​n​g​,​ ​t​a​k​e​ ​a​ ​b​r​e​a​k​!
*/
pomodoroReminder: string
}

export type TranslationFunctions = {
Expand Down Expand Up @@ -338,6 +350,18 @@ export type TranslationFunctions = {
* Post title
*/
postTitle: () => LocalizedString
/**
* start
*/
start: () => LocalizedString
/**
* stop
*/
stop: () => LocalizedString
/**
* You've been finished studying, take a break!
*/
pomodoroReminder: () => LocalizedString
}

export type Formatters = {}
3 changes: 3 additions & 0 deletions src/i18n/vi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const vi: BaseTranslation = {
seeMore: 'Xem thêm',
haveCommentedOnYourPost: 'đã bình luận về bài viết của bạn.',
postTitle: 'Tiêu đề bài đăng',
start: 'bắt đầu',
stop: 'dừng',
pomodoroReminder: 'Bạn đã hoàn thành thời gian học, hãy nghỉ chút nhé!',
}

export default vi
10 changes: 7 additions & 3 deletions src/lib/components/CreatePostModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@
import Tiptap from '$components/Tiptap'
import CreateQuestion from '$components/CreateQuestion.svelte'
import { locale, LL } from '$i18n/i18n-svelte'
import { user } from '$stores/auth'
import { enhance } from '$app/forms'
import { showLoginModal, user } from '$stores/auth'
import { fileListToUrl } from '$utils'
import PostMedia from './PostMedia.svelte'
import InputTag from './InputTag.svelte'
import type { LocalizedString } from 'typesafe-i18n'
import { showCreatePostModal } from '$stores'
export let id: string
if (!$user) {
$showLoginModal = true
$showCreatePostModal = false
}
let title = ''
let value = ''
let addQuestion = false
Expand Down Expand Up @@ -106,7 +111,6 @@
action={`/${$locale}/post?/create`}
method="POST"
enctype="multipart/form-data"
use:enhance
>
<InputTag />

Expand Down
6 changes: 3 additions & 3 deletions src/lib/components/Exercise.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
value={option.value}
class="radio"
/>
<span class="label-text ml-4">
<span class="ml-4">
{option.value}
</span>
</label>
{/each}
{#if checked}
<div class="mb-2 text-sm text-gray-700 break-all">
<div class="mb-2 break-words">
{@html post.description}
</div>
{/if}
Expand All @@ -54,7 +54,7 @@
</button>
{/if}
{:else}
<div class="mb-2 text-sm text-gray-700 break-all">
<div class="mb-2 break-words">
{@html post.description}
</div>
{/if}
4 changes: 2 additions & 2 deletions src/lib/components/LocaleSwitcher.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box">
{#each locales as l}
<li>
<button class:active={l === $locale} on:click={() => switchLocale(l)}>
<a class:active={l === $locale} on:click={() => switchLocale(l)}>
{l}
</button>
</a>
</li>
{/each}
</ul>
Expand Down
6 changes: 4 additions & 2 deletions src/lib/components/NavbarMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import LocaleSwitcher from '$components/LocaleSwitcher.svelte'
import FirebaseUI from './FirebaseUI.svelte'
import { CreatePostModalId } from '$lib/constant'
import Pomodoro from './Pomodoro.svelte'
type MenuItem = { icon: string; title: string; id: string }
const titles = ['note', 'timer', 'message', 'noti']
const titles = ['note', 'message', 'noti']
const menu: MenuItem[] = titles.map((title) => ({
title,
Expand All @@ -16,8 +17,9 @@
}))
</script>

<Pomodoro />
{#each menu as item}
<label for={item.id} class="btn btn-md btn-ghost btn-square" title={item.title}>
<label tabindex="0" for={item.id} class="btn btn-md btn-ghost btn-square" title={item.title}>
<img class="w-5 md:w-6" src={item.icon} alt={item.title} />
</label>
{/each}
Expand Down
135 changes: 135 additions & 0 deletions src/lib/components/Pomodoro.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<script lang="ts">
import { browser } from '$app/environment'
import LL from '$i18n/i18n-svelte'
let isCounting = false
let minuteInput: number | null = null
const min = 0
const max = 99
$: {
minuteInput = minuteInput ? (minuteInput = (minuteInput + max + 1) % (max + 1)) : null
}
let minute: number
let second: number
let percent: number
let showCongratulation = false
$: if (browser) {
localStorage.setItem('showCongratulation', showCongratulation.toString())
}
const Due = 'Due'
const MiniSec = 'MiniSec'
const setup = () => {
if (!minuteInput) return
const miniSec = minuteInput * 60 * 1000
const due = Date.now() + miniSec
localStorage.setItem(Due, due.toString())
localStorage.setItem(MiniSec, miniSec.toString())
}
if (browser) {
window.setInterval(() => {
showCongratulation = localStorage.getItem('showCongratulation') === 'true'
const due = Number(localStorage.getItem(Due)) || 0
if (!due) {
isCounting = false
return
}
isCounting = true
const remaining = due - Date.now()
const miniSec = Number(localStorage.getItem(MiniSec)) || 0
percent = (remaining / miniSec) * 100
minute = Math.floor(remaining / (60 * 1000))
second = Math.floor(remaining / 1000) % 60
if (second === 0) {
if (minute === 0) {
stop()
showCongratulation = true
return
}
second = 59
minute--
}
second--
}, 200)
}
const stop = () => {
localStorage.removeItem(Due)
localStorage.removeItem(MiniSec)
}
</script>

{#if !isCounting}
<div class="dropdown">
<label
tabindex="0"
on:focus={() => (minuteInput = 0)}
class="btn btn-md btn-ghost btn-square"
title="Timer"
>
<img class="w-5 md:w-6" src="/timer-icon.svg" />
</label>
<div
tabindex="0"
class="flex flex-col justify-center gap-5 text-center dropdown-content p-2 shadow bg-base-100 rounded-box w-64 h-56 mt-4"
>
<h2 class="text-lg font-bold">Pomodoro</h2>
<div class="flex justify-center align-middle gap-1">
<button class="btn btn-square" on:click={() => (minuteInput -= 1)}>-</button>
<input
type="number"
class="input input-bordered text-xl w-full max-w-xs text-center"
{min}
{max}
bind:value={minuteInput}
/>
<button class="btn btn-square" on:click={() => (minuteInput += 1)}>+</button>
</div>

<a class="btn rounded" on:click={setup}>{$LL.start()}</a>
</div>
</div>
{:else}
<div class="dropdown">
<div class="w-12">
<label
tabindex="0"
class="radial-progress text-primary cursor-pointer"
style="--value:{percent}; --size:3rem;"
>
{minute}:{second}
</label>
</div>
<div tabindex="0" class="dropdown-content p-2 shadow bg-base-100 rounded-box mt-4">
<a class="btn rounded btn-error" on:click={stop}>{$LL.stop()}</a>
</div>
</div>
{/if}

{#if showCongratulation}
<input
type="checkbox"
id="pomodoro-modal"
class="modal-toggle"
bind:checked={showCongratulation}
/>
<div class="modal bg-base-300">
<div class="modal-box">
<h3 class="font-bold text-lg">{$LL.congratulation()}!</h3>
<p class="py-4">
{$LL.pomodoroReminder()}
</p>
<div class="modal-action">
<label for="pomodoro-modal" class="btn">Yay!</label>
</div>
</div>
</div>
{/if}
7 changes: 6 additions & 1 deletion src/lib/components/PostInteractive.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@
<form
method="POST"
action={isLiked ? `/${$locale}/post?/dislike` : `/${$locale}/post?/like`}
use:enhance={() => {
use:enhance={({ cancel }) => {
if (!$user) {
$showLoginModal = true
cancel()
return
}
isSending = true
return async ({ update }) => {
await update()
Expand Down
6 changes: 3 additions & 3 deletions src/lib/components/PostMedia.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
const target = carousel.querySelector<HTMLDivElement>(href)
if (target) {
const left = target.offsetLeft
carousel.scrollTo({ left: left })
carousel.scrollTo({ left: left, behavior: 'smooth' })
}
}
</script>
Expand Down Expand Up @@ -57,7 +57,7 @@
{/if}

{#if videos.length + images.length > 0}
<div bind:this={mediaCarousel} class="carousel w-full">
<div bind:this={mediaCarousel} class="carousel">
{#each videos as src, i}
<div id={genId('media', i)} class="carousel-item w-full">
<video class="w-full my-auto" controls>
Expand All @@ -69,7 +69,7 @@
{/each}
{#each images as src, i}
<div id={genId('media', i + videos.length)} class="carousel-item w-full">
<img {src} alt="" class="mx-auto my-auto" />
<img {src} alt="" class="max-h-[30rem] mx-auto my-auto" />
</div>
{/each}
</div>
Expand Down
1 change: 1 addition & 0 deletions src/lib/constant.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const hostURL = 'https://beelearn.social'
export const logoPath = '/logo512x512.png'
export const CreatePostModalId = 'create-post-modal'
export const TimerModalId = 'create-timer-modal'
Loading

0 comments on commit 1549d1d

Please sign in to comment.