Skip to content

Commit

Permalink
Add pomodoro timer
Browse files Browse the repository at this point in the history
  • Loading branch information
matt765 committed Jul 27, 2024
1 parent 272a2e9 commit d0f47ac
Show file tree
Hide file tree
Showing 17 changed files with 582 additions and 31 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,11 @@
- fix mobile navigation bug
- add sources modal in navigation
- improve navigation styles
- adjust pdf export button
- adjust pdf export button

## 1.0.3 (27-07-2024)

- add estimated time display
- add group actions button
- add translate question option
- add pomodoro timer
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "front-end-questions",
"version": "1.0.2",
"version": "1.0.3",
"private": true,
"license": "CC-BY-NC-ND-4.0",
"description": "Open source application that contains base of front-end related interview questions.",
Expand Down
9 changes: 9 additions & 0 deletions src/assets/icons/PauseIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const PauseIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M6 3H8V21H6V3ZM16 3H18V21H16V3Z"></path>
</svg>
);
11 changes: 11 additions & 0 deletions src/assets/icons/PinIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const PinIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
width="20"
height="20"
>
<path d="M13.8273 1.69L22.3126 10.1753L20.8984 11.5895L20.1913 10.8824L15.9486 15.125L15.2415 18.6606L13.8273 20.0748L9.58466 15.8321L4.63492 20.7819L3.2207 19.3677L8.17045 14.4179L3.92781 10.1753L5.34202 8.76107L8.87756 8.05396L13.1202 3.81132L12.4131 3.10422L13.8273 1.69ZM14.5344 5.22554L9.86358 9.89637L7.0417 10.4607L13.5418 16.9609L14.1062 14.139L18.7771 9.46818L14.5344 5.22554Z"></path>
</svg>
);
9 changes: 9 additions & 0 deletions src/assets/icons/PlayIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const PlayIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M6 20.1957V3.80421C6 3.01878 6.86395 2.53993 7.53 2.95621L20.6432 11.152C21.2699 11.5436 21.2699 12.4563 20.6432 12.848L7.53 21.0437C6.86395 21.46 6 20.9812 6 20.1957Z"></path>
</svg>
);
16 changes: 16 additions & 0 deletions src/assets/icons/ResetIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const ResetIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M4.05 11a8 8 0 1 1 .5 4m-.5 5v-5h5" />
</svg>
);
11 changes: 11 additions & 0 deletions src/assets/icons/SwapIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const SwapIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
width="25"
height="25"
>
<path d="M16 16V12L21 17L16 22V18H4V16H16ZM8 2V5.999L20 6V8H8V12L3 7L8 2Z"></path>
</svg>
);
12 changes: 10 additions & 2 deletions src/components/common/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ interface DropdownProps {
items: DropdownItem[];
onClose: () => void;
dropdownRef: React.RefObject<HTMLDivElement>;
closeOnClick?: boolean;
}

export const Dropdown = ({ items, onClose, dropdownRef }: DropdownProps) => {
export const Dropdown = ({
items,
onClose,
dropdownRef,
closeOnClick = true,
}: DropdownProps) => {
return (
<div ref={dropdownRef} className={styles.dropdownWrapper}>
{items.map((item, idx) => (
Expand All @@ -24,7 +30,9 @@ export const Dropdown = ({ items, onClose, dropdownRef }: DropdownProps) => {
onClick={(e) => {
e.stopPropagation();
item.handler();
onClose();
if (closeOnClick) {
onClose();
}
}}
>
{item.icon && (
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/styles/Modal.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
z-index: 9999999;
@media (max-width: 768px) {
align-items: flex-start;
}
Expand Down Expand Up @@ -37,7 +37,7 @@
font-size: 1.5rem;
cursor: pointer;
transition: 0.1s;
color: white;
color: var(--content-text-primary);
&:hover {
transform: scale(1.1);
}
Expand Down
32 changes: 31 additions & 1 deletion src/components/layout/topBar/TopBar.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
.buttonsWrapper {
display: flex;
gap: 1.5rem;

align-items: center;
& svg {
&:hover {
box-shadow: rgba(50, 50, 93, 0.25) 0px 50px 100px -20px,
Expand Down Expand Up @@ -155,3 +155,33 @@
align-items: center;
justify-content: center;
}

.miniTimer {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.1rem;
font-size: 1rem;
cursor: pointer;
transition: 0.2s;
&:hover {
background-color: var(--bg-transparent-hover);
}
padding: 0.5rem;
border-radius: 6px;
@media (max-width: 480px) {
display: none;
}
}

.timerDisplay {
display: flex;
align-items: center;
width: 2.5rem;
gap: 0.1rem;
color: white;
@media (max-width: 480px) {
display: none;
}
}
37 changes: 34 additions & 3 deletions src/components/layout/topBar/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,48 @@ import { MoonIcon } from "@/assets/icons/MoonIcon";
import styles from "./TopBar.module.scss";
import { firaSans, inter, roboto } from "@/styles/fonts";
import { useEffect, useState } from "react";
import { useTimerStore } from "@/store/timerStore";

export const TopBar = () => {
const { toggleNavVisibility, toggleMobileNavVisibility } = useLayoutStore();
const { toggleNavVisibility, toggleMobileNavVisibility } = useLayoutStore();
const { theme, setTheme } = useTheme();
const { setMobileFirstLoad } = useLayoutStore();

const [hydrated, setHydrated] = useState(false);

const { time, isTimerPinned, openPomodoroModal } = useTimerStore();

useEffect(() => {
setHydrated(true);
}, []);

useEffect(() => {
setHydrated(true);
setShowMiniTimer(isTimerPinned);
}, [isTimerPinned]);

const [showMiniTimer, setShowMiniTimer] = useState(false);

const formatTime = (timeInSeconds: number) => {
const minutes = Math.floor(timeInSeconds / 60)
.toString()
.padStart(2, "0");
const seconds = (timeInSeconds % 60).toString().padStart(2, "0");
return { minutes, seconds };
};

const handleMiniTimerClick = () => {
openPomodoroModal();
};

return (
<div className={styles.topBarWrapper}>
<div className={styles.leftSection}>
<div
onClick={() => {
toggleNavVisibility();
setMobileFirstLoad(true);
toggleMobileNavVisibility()
toggleMobileNavVisibility();
}}
className={styles.hamburger}
>
Expand All @@ -45,10 +67,19 @@ export const TopBar = () => {
</Link>
</div>
<div className={styles.buttonsWrapper}>
{hydrated && showMiniTimer && (
<div className={styles.miniTimer} onClick={handleMiniTimerClick}>
<div className={styles.timerDisplay}>
<div className={styles.minutes}>{formatTime(time).minutes}</div>
<div className={styles.colon}>:</div>
<div className={styles.seconds}>{formatTime(time).seconds}</div>
</div>
</div>
)}
<div
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
className={styles.themeButton}
>
>
{hydrated && theme === "dark" ? <MoonIcon /> : ""}
{hydrated && theme === "light" ? <SunIcon /> : ""}
</div>
Expand Down
21 changes: 11 additions & 10 deletions src/components/questions/Question.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ export const Question = ({
icon: <CopyIcon />,
handler: () => navigator.clipboard.writeText(item.question),
},
{
text: "Translate",
icon: <LanguageIcon />,
handler: () => {
const textToTranslate = encodeURIComponent(
`Question: ${item.question}\n\nAnswer: ${item.answer}`
);
const url = `https://translate.google.com/?sl=auto&tl=en&text=${textToTranslate}&op=translate`;
window.open(url, "_blank");
},
},
{
text: "Start a discussion",
icon: <MessageIcon />,
Expand All @@ -115,16 +126,6 @@ export const Question = ({
const url = `https://github.com/matt765/front-end-questions/issues/new?title=${issueTitle}&body=${issueBody}`;
window.open(url, "_blank");
},

},
{
text: "Translate",
icon: <LanguageIcon />,
handler: () => {
const textToTranslate = encodeURIComponent(`Question: ${item.question}\n\nAnswer: ${item.answer}`);
const url = `https://translate.google.com/?sl=auto&tl=en&text=${textToTranslate}&op=translate`;
window.open(url, "_blank");
},
},
],
[item.question, item.answer]
Expand Down
Loading

0 comments on commit d0f47ac

Please sign in to comment.