feat: add modal for editing title and description
This commit is contained in:
parent
6b22bf8431
commit
cc350e4bf2
5
babel-plugin-macros.config.js
Normal file
5
babel-plugin-macros.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
'fontawesome-svg-core': {
|
||||
'license': 'free'
|
||||
}
|
||||
}
|
5
babel.config.js
Normal file
5
babel.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = function (api) {
|
||||
return {
|
||||
plugins: ['macros'],
|
||||
}
|
||||
}
|
@ -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"
|
||||
},
|
||||
|
@ -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; */
|
||||
}
|
||||
|
||||
|
@ -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} /> }) }
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
40
src/components/EditNameModal.tsx
Normal file
40
src/components/EditNameModal.tsx
Normal 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
25
src/components/Modal.css
Normal 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
41
src/components/Modal.tsx
Normal 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
|
@ -9,3 +9,7 @@ body {
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.margin-right-1 {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
@ -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
|
||||
|
39
yarn.lock
39
yarn.lock
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user