Skip to content

Commit

Permalink
feat(app): add QuestionsSidebar (#392)
Browse files Browse the repository at this point in the history
* feat(app): add QuestionsSidebar

* chore(app): remove clsx

* feat(app): add mobile action buttons

* refactor(app): change colors notation to oklch

* feat(app): add label to mobile action buttons

* feat(app): create questions page layout

* refactor(app): refactor shadows

* refactor(app): refactor LevelButton styles

* refactor(app): remove unused classes

* fix(app): fix z-index values

* refactor(app): close QuestionsSidebar by default

Co-authored-by: Michał Miszczyszyn <michal@mmiszy.pl>
  • Loading branch information
xStrixU and typeofweb committed Dec 10, 2022
1 parent 3cd0025 commit fca0cc1
Show file tree
Hide file tree
Showing 32 changed files with 540 additions and 66 deletions.
1 change: 1 addition & 0 deletions apps/app/public/icons/action-icon-add.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions apps/app/public/icons/action-icon-filter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions apps/app/public/icons/angularjs-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions apps/app/public/icons/css3-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions apps/app/public/icons/git-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions apps/app/public/icons/html5-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions apps/app/public/icons/javascript-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions apps/app/public/icons/other-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions apps/app/public/icons/reactjs-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions apps/app/src/app/questions/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ReactNode } from "react";
import { Container } from "../../components/Container";
import { MobileActionButtons } from "../../components/MobileActionButtons/MobileActionButtons";
import { QuestionsSidebar } from "../../components/QuestionsSidebar/QuestionsSidebar";

const QuestionsPageLayout = ({ children }: { readonly children: ReactNode }) => (
<>
<Container className="flex">
<QuestionsSidebar />
<main className="grow">{children}</main>
</Container>
<MobileActionButtons />
</>
);

export default QuestionsPageLayout;
5 changes: 5 additions & 0 deletions apps/app/src/app/questions/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const QuestionsPage = () => {
return <strong>Questions</strong>;
};

export default QuestionsPage;
4 changes: 2 additions & 2 deletions apps/app/src/components/AddQuestionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import { ComponentProps } from "react";
import type { FormEvent } from "react";
import { useModalContext } from "../providers/ModalProvider";
import { useUIContext } from "../providers/UIProvider";
import { BaseModal } from "./BaseModal";
import { Button } from "./Button/Button";
import { Select } from "./Select/Select";

export const AddQuestionModal = (props: ComponentProps<typeof BaseModal>) => {
const { closeModal } = useModalContext();
const { closeModal } = useUIContext();

const handleFormSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
Expand Down
6 changes: 3 additions & 3 deletions apps/app/src/components/AppModals.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import type { ComponentProps, ComponentType } from "react";
import { useModalContext } from "../providers/ModalProvider";
import type { Modal } from "../providers/ModalProvider";
import { useUIContext } from "../providers/UIProvider";
import type { Modal } from "../providers/UIProvider";
import { AddQuestionModal } from "./AddQuestionModal";
import { BaseModal } from "./BaseModal";

Expand All @@ -11,7 +11,7 @@ const modals: Record<Modal, ComponentType<ComponentProps<typeof BaseModal>>> = {
};

export const AppModals = () => {
const { openedModal, closeModal } = useModalContext();
const { openedModal, closeModal } = useUIContext();

return (
<>
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/components/BaseModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const BaseModal = ({ isOpen, onClose, children }: BaseModalProps) => {

return (
<Transition
className="fixed top-0 left-0 z-[99] flex h-full w-full items-center justify-center overflow-y-auto bg-black/50 sm:px-2"
className="fixed top-0 left-0 z-50 flex h-full w-full items-center justify-center overflow-y-auto bg-black/50 sm:px-2"
onClick={onClose}
show={isOpen}
enter="transition-opacity duration-200"
Expand Down
4 changes: 2 additions & 2 deletions apps/app/src/components/CtaHeader/AddQuestionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use client";

import { useModalContext } from "../../providers/ModalProvider";
import { useUIContext } from "../../providers/UIProvider";
import { Button } from "../Button/Button";

export const AddQuestionButton = () => {
const { openModal } = useModalContext();
const { openModal } = useUIContext();

return (
<>
Expand Down
4 changes: 2 additions & 2 deletions apps/app/src/components/CtaHeader/CtaHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ const CtaHeaderActiveLink = (props: CtaHeaderActiveLinkProps) => (
);

export const CtaHeader = () => (
<div className="sticky top-0 bg-primary">
<div className="sticky top-0 z-20 bg-primary">
<Container as="header" className="flex h-14 items-center justify-between">
<nav className="flex grow gap-4 text-sm text-white sm:grow-0">
<CtaHeaderActiveLink href="/">Lista pytań</CtaHeaderActiveLink>
<CtaHeaderActiveLink href="/questions">Lista pytań</CtaHeaderActiveLink>
<CtaHeaderActiveLink href="/foo">Wybrane pytania</CtaHeaderActiveLink>
</nav>
<AddQuestionButton />
Expand Down
4 changes: 2 additions & 2 deletions apps/app/src/components/Header/HeaderNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const HeaderNavigation = ({ children }: { children: ReactNode }) => {
<nav
id="header-navigation"
className={twMerge(
"fixed top-0 left-0 z-10 h-full w-full flex-col items-center justify-center gap-10 bg-primary text-xl uppercase sm:gap-5 sm:text-sm",
"fixed top-0 left-0 z-30 h-full w-full flex-col items-center justify-center gap-10 bg-primary text-xl uppercase sm:gap-5 sm:text-sm",
"sm:relative sm:flex sm:h-fit sm:w-fit sm:flex-row",
isOpen ? "flex" : "hidden",
)}
Expand All @@ -30,7 +30,7 @@ export const HeaderNavigation = ({ children }: { children: ReactNode }) => {
</nav>
<button
className={twMerge(
"right-4 z-50 flex h-8 w-8 flex-col items-center justify-center gap-1.5 sm:hidden",
"right-4 z-40 flex h-8 w-8 flex-col items-center justify-center gap-1.5 sm:hidden",
isOpen ? "fixed" : "absolute",
)}
onClick={handleButtonClick}
Expand Down
14 changes: 14 additions & 0 deletions apps/app/src/components/MobileActionButtons/MobileActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ReactNode } from "react";

type MobileActionButtonProps = Readonly<{
children: ReactNode;
"aria-label": string;
onClick: () => void;
}>;

export const MobileActionButton = (props: MobileActionButtonProps) => (
<button
className="flex h-11 w-11 appearance-none items-center justify-center rounded-full bg-primary shadow-md shadow-neutral-600 dark:shadow-neutral-900"
{...props}
/>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use client";

import ActionIconFilter from "../../../public/icons/action-icon-filter.svg";
import ActionIconAdd from "../../../public/icons/action-icon-add.svg";
import { useUIContext } from "../../providers/UIProvider";
import { MobileActionButton } from "./MobileActionButton";

export const MobileActionButtons = () => {
const { openSidebar, openModal } = useUIContext();

return (
<div className="sticky bottom-0 left-1/2 flex w-full justify-center gap-4 pb-7 sm:hidden">
<MobileActionButton aria-label="Otwórz sidebar" onClick={openSidebar}>
<ActionIconFilter />
</MobileActionButton>
<MobileActionButton
aria-label="Dodaj nowe pytanie"
onClick={() => openModal("AddQuestionModal")}
>
<ActionIconAdd />
</MobileActionButton>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ReactNode } from "react";
import { twMerge } from "tailwind-merge";

type LevelButtonProps = Readonly<{
variant: "junior" | "mid" | "senior";
isActive: boolean;
children: ReactNode;
}>;

export const LevelButton = ({ variant, isActive, children }: LevelButtonProps) => (
<button
className={twMerge(
"h-20 w-20 transition-colors duration-100 sm:h-8 sm:w-full small-filters:h-14 small-filters:w-14",
"rounded-md text-sm text-neutral-500 active:translate-y-px dark:text-neutral-200",
!isActive &&
"level-button bg-white shadow-[0px_1px_4px] shadow-neutral-400 dark:shadow-neutral-900",
isActive && "level-button-active text-white",
variant === "junior" && "level-button-junior",
variant === "mid" && "level-button-mid",
variant === "senior" && "level-button-senior",
)}
>
{children}
</button>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { QuestionsSidebarSection } from "../QuestionsSidebarSection";
import { LevelButton } from "./LevelButton";

export const LevelFilter = () => {
return (
<QuestionsSidebarSection title="Wybierz poziom">
<div className="flex justify-center gap-3 sm:flex-col small-filters:flex-row">
<LevelButton variant="junior" isActive={true}>
Junior
</LevelButton>
<LevelButton variant="mid" isActive={false}>
Mid
</LevelButton>
<LevelButton variant="senior" isActive={false}>
Senior
</LevelButton>
</div>
</QuestionsSidebarSection>
);
};
30 changes: 30 additions & 0 deletions apps/app/src/components/QuestionsSidebar/QuestionsSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"use client";

import { twMerge } from "tailwind-merge";
import { useUIContext } from "../../providers/UIProvider";
import { Button } from "../Button/Button";
import { CloseButton } from "../CloseButton/CloseButton";
import { LevelFilter } from "./LevelFilter/LevelFilter";
import { TechnologyFilter } from "./TechnologyFilter/TechnologyFilter";

export const QuestionsSidebar = () => {
const { isSidebarOpen, closeSidebar } = useUIContext();

return (
<aside
className={twMerge(
"fixed top-0 left-0 bottom-0 right-0 z-50 flex -translate-x-full transform-gpu flex-col bg-gray-50 px-2.5 pb-4 transition-transform duration-200 dark:bg-neutral-800",
"after:absolute after:top-0 after:bottom-0 after:right-0 after:hidden after:w-px after:shadow-[4px_0px_4px_rgba(0,0,0,0.23)]",
"sm:sticky sm:top-[56px] sm:z-auto sm:h-screen sm:w-60 sm:translate-x-0 sm:p-0 sm:pr-10 sm:transition-none sm:after:inline",
isSidebarOpen && "translate-x-0",
)}
>
<TechnologyFilter />
<LevelFilter />
<Button variant="brandingInverse" className="mt-auto sm:hidden">
Pokaż wyniki
</Button>
<CloseButton className="absolute top-1 right-1 sm:hidden" onClick={closeSidebar} />
</aside>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ReactNode } from "react";

type QuestionsSidebarSection = Readonly<{
title: string;
children: ReactNode;
}>;

export const QuestionsSidebarSection = ({ title, children }: QuestionsSidebarSection) => (
<section className="mt-6">
<h2 className="mb-6 border-b border-violet-700 pb-2 text-sm text-violet-700 dark:border-neutral-200 dark:text-neutral-200">
{title}
</h2>
{children}
</section>
);
Loading

0 comments on commit fca0cc1

Please sign in to comment.