fix: some details

This commit is contained in:
Daniel Soares
2021-12-15 08:11:58 -03:00
parent 2f4dd0097b
commit 5df44ceddc
22 changed files with 330 additions and 118 deletions

View File

@@ -4,6 +4,7 @@
"rules": {
"prettier/prettier": "error",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
"simple-import-sort/exports": "error",
"no-unused-vars": "error"
}
}

View File

@@ -61,13 +61,20 @@ async function main() {
]
}
const hasData = await prisma.data.findFirst()
const hasData = await prisma.data.findUnique({
where: {
id: 1
}
})
if (!hasData) {
console.log(`Start seeding...`)
await prisma.data.create({
data: { data: JSON.stringify(data) }
data: {
id: 1,
data: JSON.stringify(data)
}
})
}
}

View File

@@ -7,8 +7,9 @@ type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
children: ReactNode
colorSchema?: ButtonVariantProps['colorSchema']
styleSchema?: ButtonVariantProps['styleSchema']
size?: ButtonVariantProps['size']
font?: ButtonVariantProps['font']
outline?: ButtonVariantProps['outline']
outline?: boolean
}
export function Button({ children, ...rest }: ButtonProps) {

View File

@@ -38,10 +38,9 @@ export const Wrapper = styled('button', {
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '3rem',
padding: '0 1rem',
borderWidth: '2.5px',
borderStyle: 'solid',
fontSize: '1rem',
fontWeight: 500,
cursor: 'pointer',
transition: 'all 0.25s ease-in-out',
@@ -84,6 +83,17 @@ export const Wrapper = styled('button', {
}
},
size: {
small: {
height: '2rem',
fontSize: '0.875rem'
},
medium: {
height: '3rem',
fontSize: '1rem'
}
},
font: {
baloo: {
fontFamily: theme.fonts.baloo
@@ -199,6 +209,7 @@ export const Wrapper = styled('button', {
defaultVariants: {
colorSchema: 'teal',
styleSchema: 'pill',
size: 'medium',
font: 'roboto',
outline: false
}

View File

@@ -0,0 +1,25 @@
import { useData } from '../../../hooks/useData'
import type { ButtonVariantProps } from '../../Button'
export function ButtonsStyleSelect() {
const { data, setData } = useData()
return (
<select
value={data.settings.buttonsSchema as string}
onChange={e =>
setData({
...data,
settings: {
...data.settings,
buttonsSchema: e.target.value as ButtonVariantProps['styleSchema']
}
})
}
>
<option value="square">Square</option>
<option value="rounded">Rounded</option>
<option value="pill">Pill</option>
</select>
)
}

View File

@@ -1,4 +1,4 @@
import { useState } from 'react'
import { useEffect, useState } from 'react'
import { useData } from '../../../hooks/useData'
import type { Colors } from '../../../styles/stitches.config'
@@ -11,7 +11,11 @@ type ColorSelectProps = {
export function ColorSelect({ prop }: ColorSelectProps) {
const { data, setData } = useData()
const [activeColor, setActiveColor] = useState<string>(data.settings.colors[prop] as string)
const [activeColor, setActiveColor] = useState(data.settings.colors[prop] as string)
useEffect(() => {
setActiveColor(data.settings.colors[prop] as string)
}, [data, prop])
const allColors = Object.keys(theme.colors) as Colors[]
const colorsSchema = [

View File

@@ -10,10 +10,11 @@ export const SelectButton = styled('button', {
width: '100%',
height: '3rem',
padding: '0.25rem',
borderRadius: '0.25rem',
borderRadius: '0.2rem',
borderWidth: '3px',
borderStyle: 'solid',
borderColor: theme.colors.slate200,
background: 'transparent',
cursor: 'pointer',
variants: {

View File

@@ -0,0 +1,19 @@
import { ColorSelect } from '../ColorSelect'
export function ColorsSettings() {
return (
<div>
<h1>Texts</h1>
<ColorSelect prop="texts" />
<h1>Icons</h1>
<ColorSelect prop="socialLinks" />
<h1>Buttons</h1>
<ColorSelect prop="buttonLinks" />
<h1>Background</h1>
<ColorSelect prop="background" />
</div>
)
}

View File

@@ -0,0 +1,17 @@
import { ButtonsStyleSelect } from '../ButtonsStyleSelect'
import { DescriptionInput } from '../DescriptionInput'
import { FontsSelect } from '../FontsSelect'
import { NameInput } from '../NameInput'
import { OutlineCheckbox } from '../OutlineCheckbox'
export function DataSettings() {
return (
<div>
<NameInput />
<DescriptionInput />
<FontsSelect />
<ButtonsStyleSelect />
<OutlineCheckbox />
</div>
)
}

View File

@@ -5,7 +5,7 @@ export function DescriptionInput() {
return (
<textarea
style={{ height: '200px', width: '100%' }}
style={{ height: '200px !important', width: '100% !important' }}
value={data.settings.description}
onChange={e =>
setData({

View File

@@ -0,0 +1,25 @@
import { useData } from '../../../hooks/useData'
import type { Fonts } from '../../../styles/stitches.config'
export function FontsSelect() {
const { data, setData } = useData()
return (
<select
value={data.settings.font}
onChange={e =>
setData({
...data,
settings: {
...data.settings,
font: e.target.value as Fonts
}
})
}
>
<option value="baloo">Baloo</option>
<option value="montserrat">Montserrat</option>
<option value="roboto">Roboto</option>
</select>
)
}

View File

@@ -0,0 +1,21 @@
import { useData } from '../../../hooks/useData'
export function OutlineCheckbox() {
const { data, setData } = useData()
return (
<input
type="checkbox"
defaultChecked={data.settings.outline}
onChange={() =>
setData({
...data,
settings: {
...data.settings,
outline: !data.settings.outline
}
})
}
/>
)
}

View File

@@ -0,0 +1,62 @@
import { useRouter } from 'next/router'
import type { Dispatch, SetStateAction } from 'react'
import { useData } from '../../../hooks/useData'
import { api } from '../../../services/api'
import type { Data } from '../../../types/Data'
import { removeLocalStorageData } from '../../../utils/localStorage'
import { Button } from '../../Button'
import { ButtonsGroup, Wrapper } from './styles'
type SaveChangesAlertProps = {
hasUnsavedChanges: boolean
setHasUnsavedChanges: Dispatch<SetStateAction<boolean>>
initialData: Data
}
export function SaveChangesAlert({
hasUnsavedChanges,
setHasUnsavedChanges,
initialData
}: SaveChangesAlertProps) {
const { push } = useRouter()
const { data, setData } = useData()
const handleSave = async () => {
try {
await api.put('data', { data })
removeLocalStorageData()
setHasUnsavedChanges(false)
setData(data)
push('/')
} catch (error) {
console.error(error)
}
}
const handleCancel = () => {
setHasUnsavedChanges(false)
removeLocalStorageData()
setData(initialData)
}
return (
<Wrapper show={hasUnsavedChanges}>
You have unsaved changes.
<ButtonsGroup>
<Button
size="small"
styleSchema="square"
colorSchema="rose"
outline
onClick={() => handleCancel()}
>
Cancel
</Button>
<Button size="small" styleSchema="square" colorSchema="slate" onClick={() => handleSave()}>
Save
</Button>
</ButtonsGroup>
</Wrapper>
)
}

View File

@@ -0,0 +1,38 @@
import { styled, theme } from '../../../styles/stitches.config'
export const Wrapper = styled('div', {
position: 'fixed',
top: 0,
left: 0,
width: '50%',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '1rem',
background: theme.colors.sky200,
color: theme.colors.slate700,
fontFamily: theme.fonts.roboto,
fontSize: '0.875rem',
lineHeight: 1,
transition: 'all 0.25s ease-in-out',
variants: {
show: {
true: {
opacity: 1
},
false: {
opacity: 0
}
}
},
defaultVariant: {
show: false
}
})
export const ButtonsGroup = styled('div', {
display: 'flex',
gap: '1rem'
})

View File

@@ -1,21 +1,13 @@
import { isEqual } from 'lodash'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { useData } from '../../hooks/useData'
import { api } from '../../services/api'
import type { Fonts } from '../../styles/stitches.config'
import type { Data } from '../../types/Data'
import {
getLocalStorageData,
removeLocalStorageData,
setLocalStorageData
} from '../../utils/localStorage'
import { ButtonVariantProps } from '../Button'
import { getLocalStorageData, setLocalStorageData } from '../../utils/localStorage'
import { Home } from '../Home'
import { ColorSelect } from './ColorSelect'
import { DescriptionInput } from './DescriptionInput'
import { NameInput } from './NameInput'
import { ColorsSettings } from './ColorsSettings'
import { DataSettings } from './DataSettings'
import { SaveChangesAlert } from './SaveChangesAlert'
import { Content, Preview, Wrapper } from './styles'
type DashProps = {
@@ -23,10 +15,10 @@ type DashProps = {
}
export function Dash({ initialData }: DashProps) {
const { push } = useRouter()
const { data, setData } = useData()
const [isLoading, setIsLoading] = useState(true)
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false)
const [activeTab, setActiveTab] = useState<'data' | 'colors'>('data')
useEffect(() => {
if (isLoading) {
@@ -45,75 +37,29 @@ export function Dash({ initialData }: DashProps) {
}
}, [data, initialData, isLoading, setData])
const handleSave = async () => {
try {
await api.put('data', { data })
removeLocalStorageData()
setHasUnsavedChanges(false)
push('/')
} catch (error) {
console.error(error)
}
}
const handleChangeButtonsSchema = (schema: ButtonVariantProps['styleSchema']) => {
setData({ ...data, settings: { ...data.settings, buttonsSchema: schema } })
}
const handleChangeOutline = (outline: ButtonVariantProps['outline']) => {
setData({ ...data, settings: { ...data.settings, outline } })
}
const handleChangeFont = (font: Fonts) => {
setData({ ...data, settings: { ...data.settings, font } })
}
const tabs = [
{ label: 'Data', value: 'data' },
{ label: 'Colors', value: 'colors' }
]
const body = { data: <DataSettings />, colors: <ColorsSettings /> }
return (
<Wrapper>
<Content>
<h1>
Dash{' '}
{hasUnsavedChanges && (
<>
- has unsaved changes <button onClick={() => handleSave()}>save</button>
</>
)}
</h1>
<NameInput />
<DescriptionInput />
<select
value={data.settings.font}
onChange={e => handleChangeFont(e.target.value as Fonts)}
>
<option value="square">Baloo</option>
<option value="montserrat">Montserrat</option>
<option value="roboto">Roboto</option>
</select>
<ColorSelect prop="texts" />
<ColorSelect prop="socialLinks" />
<ColorSelect prop="buttonLinks" />
<ColorSelect prop="background" />
<select
value={data.settings.buttonsSchema as string}
onChange={e =>
handleChangeButtonsSchema(e.target.value as ButtonVariantProps['styleSchema'])
}
>
<option value="square">Square</option>
<option value="rounded">Rounded</option>
<option value="pill">Pill</option>
</select>
<input
type="checkbox"
defaultChecked={data.settings.outline as boolean}
onChange={() =>
handleChangeOutline(!data.settings.outline as ButtonVariantProps['outline'])
}
<SaveChangesAlert
hasUnsavedChanges={hasUnsavedChanges}
setHasUnsavedChanges={setHasUnsavedChanges}
initialData={initialData}
/>
<h1>Dash </h1>
{tabs.map(tab => (
<button key={tab.value} onClick={() => setActiveTab(tab.value as 'data' | 'colors')}>
{tab.label}
</button>
))}
{body[activeTab]}
</Content>
<Preview>
<Home />

View File

@@ -2,25 +2,29 @@ import { styled, theme } from '../../styles/stitches.config'
export const Wrapper = styled('main', {
display: 'grid',
gridTemplateColumns: '1fr 1fr'
gridTemplateColumns: '1fr 1fr',
position: 'fixed',
inset: 0
})
export const Content = styled('div', {
display: 'flex',
flexDirection: 'column',
gap: '1rem',
fontFamily: theme.fonts.roboto
padding: '5rem 1rem 1rem',
fontFamily: theme.fonts.roboto,
color: theme.colors.slate900,
background: theme.colors.slate50,
overflowY: 'scroll'
})
export const Preview = styled('div', {
position: 'relative',
overflowY: 'scroll',
'&::after': {
content: '',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0
inset: 0
}
})

View File

@@ -1,3 +1,5 @@
import Head from 'next/head'
import { useData } from '../../hooks/useData'
import { theme } from '../../styles/stitches.config'
import { Avatar } from '../Avatar'
@@ -12,11 +14,17 @@ export const Home = () => {
return (
<Wrapper
css={{
background: theme.colors[colors.background as keyof typeof theme.colors],
color: theme.colors[colors.texts as keyof typeof theme.colors],
fontFamily: theme.fonts[font as keyof typeof theme.fonts]
color: theme.colors[colors.texts],
fontFamily: theme.fonts[font]
}}
>
<Head>
<style
dangerouslySetInnerHTML={{
__html: `body { background: ${theme.colors[colors.background]} }`
}}
/>
</Head>
<Content>
<Avatar />
<Name>{name}</Name>

View File

@@ -1,32 +1,45 @@
import { NextApiRequest, NextApiResponse } from 'next'
import type { NextApiRequest, NextApiResponse } from 'next'
import nc from 'next-connect'
import { prisma } from '../../services/prisma'
const handler = nc<NextApiRequest, NextApiResponse>()
.get(async (_req, res) => {
try {
const data = await prisma.data.findFirst()
res.status(200).json(data?.data)
} catch (error) {
console.error(error)
res.status(500).send('Internal server error')
const handler = nc<NextApiRequest, NextApiResponse>({
onNoMatch: (_req, res) => {
res.status(404).json({ error: 'Not found' })
},
onError: (err, _req, res) => {
res.status(500).json({ error: err.message })
}
})
.get(async (_req, res) => {
const response = await prisma.data.findUnique({
where: { id: 1 }
})
if (!response) {
throw new Error('No data found')
}
res.status(200).json(response?.data)
})
.put(async (req, res) => {
const { data } = req.body
if (!data) {
throw new Error('No data provided')
}
try {
const response = await prisma.data.update({
where: {
id: 1
},
where: { id: 1 },
data: { data: JSON.stringify(req.body.data) }
})
res.status(200).json(response)
} catch (error) {
console.error(error)
res.status(500).send('Internal server error')
} catch (err: any) {
console.error(err)
res.status(500).json({ error: err.message })
}
})

View File

@@ -2,11 +2,13 @@ import type { Data } from '../types/Data'
import { prisma } from './prisma'
export async function fetchData(): Promise<Data> {
const data = await prisma.data.findFirst()
const response = await prisma.data.findUnique({
where: { id: 1 }
})
if (data) {
return JSON.parse(data.data)
} else {
if (!response) {
throw new Error('No data found')
}
return JSON.parse(response.data)
}

View File

@@ -1,5 +1,4 @@
import data from '../../temp/data.json'
import { globalCss, theme } from './stitches.config'
import { globalCss } from './stitches.config'
export const globalStyles = globalCss({
'*': {
@@ -8,6 +7,6 @@ export const globalStyles = globalCss({
boxSizing: 'border-box'
},
body: {
fontFamily: theme.fonts[data.settings.font as keyof typeof theme.fonts]
transition: 'all 0.25s ease-in-out'
}
})

View File

@@ -207,6 +207,14 @@ export const { css, styled, globalCss, theme, keyframes, getCssText } = createSt
rose800: '#9f1239',
rose900: '#881337'
}
},
utils: {
inset: (value: number | string) => ({
top: value,
right: value,
left: value,
bottom: value
})
}
})

View File

@@ -9,7 +9,7 @@ export type Data = {
description: string
font: Fonts
buttonsSchema: ButtonVariantProps['styleSchema']
outline: ButtonVariantProps['outline']
outline: boolean
colors: {
texts: Colors
socialLinks: LinkVariantProps['theme']