1
0

feat: add modal for editing title and description

This commit is contained in:
Rokas Puzonas 2022-04-09 14:35:09 +00:00
parent 6b22bf8431
commit cc350e4bf2
14 changed files with 283 additions and 18 deletions

View File

@ -0,0 +1,5 @@
module.exports = {
'fontawesome-svg-core': {
'license': 'free'
}
}

5
babel.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = function (api) {
return {
plugins: ['macros'],
}
}

View File

@ -3,6 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-fontawesome": "^0.1.18",
"@reduxjs/toolkit": "^1.8.1",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.4",
@ -12,10 +15,12 @@
"@types/react": "^17.0.43",
"@types/react-dom": "^17.0.14",
"@types/react-redux": "^7.1.23",
"babel-plugin-macros": "^3.1.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-redux": "^7.2.8",
"react-scripts": "5.0.0",
"react-tooltip": "^4.2.21",
"typescript": "^4.6.3",
"web-vitals": "^2.1.4"
},

View File

@ -5,7 +5,7 @@ main {
/* flex-direction: column; */
/* align-items: center; */
/* justify-content: center; */
/* font-size: calc(10px + 2vmin); */
font-size: calc(10px + 2vmin);
/* color: white; */
}

View File

@ -1,6 +1,8 @@
import React from 'react';
import './App.css';
import DiscRow from './components/DiscRow';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { solid } from '@fortawesome/fontawesome-svg-core/import.macro'
import { selectDiscs, useAppSelector } from './store';
function App() {
@ -9,7 +11,10 @@ function App() {
return (
<div className="app">
<header>
<button>Generate resource pack</button>
<button>
<FontAwesomeIcon className="margin-right-1" icon={solid("gears")} />
Generate resource pack
</button>
</header>
<main>
{ discs.discs.map((disc, idx) => { return <DiscRow key={idx} discId={idx} /> }) }

View File

@ -1,11 +1,16 @@
.disc-row {
display: flex;
align-items: center;
margin-top: 1rem;
}
.disc-row > button {
font-size: 1.25rem;
}
.disc-row__icon {
width: 2.5em;
height: 2.5em;
width: 1.5em;
height: 1.5em;
/* IE, only works on <img> tags */
-ms-interpolation-mode: nearest-neighbor;
@ -14,3 +19,9 @@
/* Chromium + Safari */
image-rendering: pixelated;
}
.disc-preview {
display: flex;
flex: 1 0 auto;
align-items: center;
}

View File

@ -1,6 +1,12 @@
import DiscTooltip from "./DiscTooltip"
import { selectDiscs, useAppSelector } from '../store';
import { selectDiscs, useAppSelector } from "../store"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { solid } from "@fortawesome/fontawesome-svg-core/import.macro"
import ReactTooltip from "react-tooltip"
import EditNameModal from "./EditNameModal"
import "./DiscRow.css"
import { useState } from "react"
interface DiscRowProps {
discId: number
@ -10,10 +16,32 @@ function DiscRow({ discId }: DiscRowProps) {
const discs = useAppSelector(selectDiscs)
const disc = discs.discs[discId]
const [showEditName, setShowEditName] = useState(false);
return (
<div className="disc-row">
<button data-tip="Reset">
<FontAwesomeIcon icon={solid("arrow-rotate-right")} />
</button>
<button data-tip="Edit name" onClick={() => setShowEditName(true)}>
<FontAwesomeIcon icon={solid("pen")} />
</button>
<button data-tip="Upload new audio">
<FontAwesomeIcon icon={solid("file-audio")} />
</button>
<div className="disc-preview">
<img className="disc-row__icon" src={disc.icon} />
<DiscTooltip title={disc.title} description={disc.description} />
<DiscTooltip
title={disc.title || disc.defaultTitle}
description={disc.description || disc.defaultDescription}
/>
</div>
<ReactTooltip />
<EditNameModal
show={showEditName}
onClose={() => setShowEditName(false)}
discId={discId}
/>
</div>
)
}

View File

@ -7,7 +7,7 @@
.disc-tooltip {
color: #FFF;
text-shadow: 0.125em 0.125em 0 #3F3F3F
text-shadow: 0.125em 0.125em 0 #3F3F3F;
}
.disc-tooltip {
@ -16,9 +16,9 @@
background-color: rgba(16,0,16,0.94);
padding: 0.375em;
font-family: Minecraft,sans-serif;
font-size: 16px;
font-size: 12px;
word-spacing: 4px;
white-space: nowrap;
/* white-space: nowrap; */
line-height: 1.25em;
margin: 0.125em 0.25em;
}

View File

@ -0,0 +1,40 @@
import { selectDiscs, useAppDispatch, useAppSelector } from "../store"
import { setDescription, setTitle } from "../store/discs"
import Modal from "./Modal"
interface EditNameModalProps {
discId: number
show: boolean
onClose: { (): void }
}
function EditNameModal({ discId, show, onClose }: EditNameModalProps) {
const discs = useAppSelector(selectDiscs)
const disc = discs.discs[discId]
const dispatch = useAppDispatch()
function setInputTitle(e: React.ChangeEvent<HTMLInputElement>) {
dispatch(setTitle({
id: discId,
title: e.target.value
}))
}
function setInputDescription(e: React.ChangeEvent<HTMLInputElement>) {
dispatch(setDescription({
id: discId,
description: e.target.value
}))
}
return <Modal show={show} onClose={onClose}>
<label>Title:</label>
<input onChange={setInputTitle} type="text" value={disc.title} />
<label>Description:</label>
<input onChange={setInputDescription} type="text" value={disc.description}/>
</Modal>
}
export default EditNameModal

25
src/components/Modal.css Normal file
View File

@ -0,0 +1,25 @@
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--background-body);
padding: 2rem;
z-index: 900;
border-radius: 1rem;
}
.modal__overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
z-index: 900;
}
.modal__close-btn {
margin-top: 1rem;
float: right;
}

41
src/components/Modal.tsx Normal file
View File

@ -0,0 +1,41 @@
import { useEffect } from "react"
import "./Modal.css"
interface ModalProps {
show: boolean
onClose: { (): void }
children: React.ReactNode
}
function Modal({ show, onClose, children }: ModalProps) {
function onKeyUp(e: KeyboardEvent) {
if (show && e.key == "Escape") {
onClose()
}
}
useEffect(() => {
document.addEventListener("keyup", onKeyUp)
return () => document.removeEventListener("keyup", onKeyUp)
})
if (!show) return null
return (
<>
<div
className="modal__overlay"
onClick={onClose}
/>
<div className="modal">
<div className="modal__body">
{children}
</div>
<button className="modal__close-btn" onClick={onClose}>Close</button>
</div>
</>
)
}
export default Modal

View File

@ -9,3 +9,7 @@ body {
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}
.margin-right-1 {
margin-right: 1rem;
}

View File

@ -1,8 +1,10 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
export interface Disc {
title: string
description: string
title?: string
description?: string
defaultTitle: string
defaultDescription: string
icon: string
}
@ -10,11 +12,66 @@ interface DiscsState {
discs: Disc[]
}
const defaultTitle = "Music Disc"
const initialState: DiscsState = {
discs: [
{ title: "Music Disc", description: "C418 - 13", icon: "/sprites/music_disc_13.png" },
{ title: "Music Disc", description: "C418 - cat", icon: "/sprites/music_disc_cat.png" },
{ title: "Music Disc", description: "C418 - blocks", icon: "/sprites/music_disc_blocks.png" },
{
defaultTitle, defaultDescription: "C418 - 13",
icon: "/sprites/music_disc_13.png"
},
{
defaultTitle, defaultDescription: "C418 - cat",
icon: "/sprites/music_disc_cat.png"
},
{
defaultTitle, defaultDescription: "C418 - blocks",
icon: "/sprites/music_disc_blocks.png"
},
{
defaultTitle, defaultDescription: "C418 - chirp",
icon: "/sprites/music_disc_chirp.png"
},
{
defaultTitle, defaultDescription: "C418 - far",
icon: "/sprites/music_disc_far.png"
},
{
defaultTitle, defaultDescription: "C418 - mall",
icon: "/sprites/music_disc_mall.png"
},
{
defaultTitle, defaultDescription: "C418 - mellohi",
icon: "/sprites/music_disc_mellohi.png"
},
{
defaultTitle, defaultDescription: "C418 - stal",
icon: "/sprites/music_disc_stal.png"
},
{
defaultTitle, defaultDescription: "C418 - strad",
icon: "/sprites/music_disc_strad.png"
},
{
defaultTitle, defaultDescription: "C418 - ward",
icon: "/sprites/music_disc_ward.png"
},
{
defaultTitle, defaultDescription: "C418 - 11",
icon: "/sprites/music_disc_11.png"
},
{
defaultTitle, defaultDescription: "C418 - wait",
icon: "/sprites/music_disc_wait.png"
},
{
defaultTitle, defaultDescription: "Lena Raine - otherside",
icon: "/sprites/music_disc_otherside.png"
},
{
defaultTitle, defaultDescription: "Lena Raine - Pigstep",
icon: "/sprites/music_disc_pigstep.png"
},
]
}
@ -22,17 +79,17 @@ export const discsSlice = createSlice({
name: "discs",
initialState,
reducers: {
updateTitle: (state, action: PayloadAction<{ id: number, title: string }>) => {
setTitle: (state, action: PayloadAction<{ id: number, title: string }>) => {
const { id, title } = action.payload;
state.discs[id].title = title
},
updateDescription: (state, action: PayloadAction<{ id: number, description: string }>) => {
setDescription: (state, action: PayloadAction<{ id: number, description: string }>) => {
const { id, description } = action.payload;
state.discs[id].description = description
}
}
})
export const { updateTitle, updateDescription } = discsSlice.actions
export const { setTitle, setDescription } = discsSlice.actions
export default discsSlice.reducer

View File

@ -1155,6 +1155,32 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
"@fortawesome/fontawesome-common-types@6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz#7dc996042d21fc1ae850e3173b5c67b0549f9105"
integrity sha512-wVn5WJPirFTnzN6tR95abCx+ocH+3IFLXAgyavnf9hUmN0CfWoDjPT/BAWsUVwSlYYVBeCLJxaqi7ZGe4uSjBA==
"@fortawesome/fontawesome-svg-core@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.1.tgz#3424ec6182515951816be9b11665d67efdce5b5f"
integrity sha512-NCg0w2YIp81f4V6cMGD9iomfsIj7GWrqmsa0ZsPh59G7PKiGN1KymZNxmF00ssuAlo/VZmpK6xazsGOwzKYUMg==
dependencies:
"@fortawesome/fontawesome-common-types" "6.1.1"
"@fortawesome/free-solid-svg-icons@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.1.1.tgz#3369e673f8fe8be2fba30b1ec274d47490a830a6"
integrity sha512-0/5exxavOhI/D4Ovm2r3vxNojGZioPwmFrKg0ZUH69Q68uFhFPs6+dhAToh6VEQBntxPRYPuT5Cg1tpNa9JUPg==
dependencies:
"@fortawesome/fontawesome-common-types" "6.1.1"
"@fortawesome/react-fontawesome@^0.1.18":
version "0.1.18"
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz#dae37f718a24e14d7a99a5496c873d69af3fbd73"
integrity sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ==
dependencies:
prop-types "^15.8.1"
"@humanwhocodes/config-array@^0.9.2":
version "0.9.5"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7"
@ -7138,6 +7164,14 @@ react-scripts@5.0.0:
optionalDependencies:
fsevents "^2.3.2"
react-tooltip@^4.2.21:
version "4.2.21"
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-4.2.21.tgz#840123ed86cf33d50ddde8ec8813b2960bfded7f"
integrity sha512-zSLprMymBDowknr0KVDiJ05IjZn9mQhhg4PRsqln0OZtURAJ1snt1xi5daZfagsh6vfsziZrc9pErPTDY1ACig==
dependencies:
prop-types "^15.7.2"
uuid "^7.0.3"
react@^18.0.0:
version "18.0.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96"
@ -8291,6 +8325,11 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
uuid@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"