Compare commits
No commits in common. "99d2b92b03d52d2b2680cef9b4841272255a2e3c" and "cb848739e5e4478b31bc6477081d8a1db1516293" have entirely different histories.
99d2b92b03
...
cb848739e5
@ -5,6 +5,8 @@
|
|||||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Porridger</title>
|
<title>Porridger</title>
|
||||||
|
<!-- most likely will be loaded from browser cache -->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@ -7,9 +7,7 @@
|
|||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview"
|
||||||
"typecheck": "tsc",
|
|
||||||
"addFetchApiRoute": "bash utils/addFetchApiRoute.sh"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/leaflet": "^1.9.3",
|
"@types/leaflet": "^1.9.3",
|
||||||
|
@ -6,28 +6,19 @@ import { categoryNames } from '../assets/category'
|
|||||||
import { useBook } from '../hooks/api'
|
import { useBook } from '../hooks/api'
|
||||||
import { Announcement } from '../api/announcement/types'
|
import { Announcement } from '../api/announcement/types'
|
||||||
import { iconItem } from '../utils/markerIcons'
|
import { iconItem } from '../utils/markerIcons'
|
||||||
import { CSSProperties } from 'react'
|
|
||||||
|
|
||||||
type AnnouncementDetailsProps = {
|
type AnnouncementDetailsProps = {
|
||||||
close: () => void,
|
close: () => void,
|
||||||
announcement: Announcement
|
announcement: Announcement
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = {
|
|
||||||
container: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
} as CSSProperties,
|
|
||||||
}
|
|
||||||
|
|
||||||
function AnnouncementDetails({ close, announcement: { id, name, category, bestBy, description, lat, lng, address, metro } }: AnnouncementDetailsProps) {
|
function AnnouncementDetails({ close, announcement: { id, name, category, bestBy, description, lat, lng, address, metro } }: AnnouncementDetailsProps) {
|
||||||
const { handleBook, status: bookStatus } = useBook(id)
|
const { handleBook, status: bookStatus } = useBook(id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='modal'
|
className='modal'
|
||||||
style={styles.container}
|
style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
|
||||||
>
|
>
|
||||||
<Modal.Dialog style={{ minWidth: '50vw' }}>
|
<Modal.Dialog style={{ minWidth: '50vw' }}>
|
||||||
<Modal.Header closeButton onHide={close}>
|
<Modal.Header closeButton onHide={close}>
|
||||||
|
@ -3,30 +3,27 @@ import { Link } from 'react-router-dom'
|
|||||||
import addIcon from '../assets/addIcon.svg'
|
import addIcon from '../assets/addIcon.svg'
|
||||||
import filterIcon from '../assets/filterIcon.svg'
|
import filterIcon from '../assets/filterIcon.svg'
|
||||||
import userIcon from '../assets/userIcon.svg'
|
import userIcon from '../assets/userIcon.svg'
|
||||||
import { CSSProperties } from 'react'
|
|
||||||
|
|
||||||
const styles = {
|
const navBarStyles: React.CSSProperties = {
|
||||||
navBar: {
|
backgroundColor: 'var(--bs-success)',
|
||||||
backgroundColor: 'var(--bs-success)',
|
height: 56,
|
||||||
height: 56,
|
width: '100%',
|
||||||
width: '100%',
|
|
||||||
} as CSSProperties,
|
|
||||||
navBarGroup: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: '100%',
|
|
||||||
margin: 'auto'
|
|
||||||
} as CSSProperties,
|
|
||||||
navBarElement: {
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
} as CSSProperties,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const navBarGroupStyles: React.CSSProperties = {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
height: '100%',
|
||||||
|
margin: 'auto'
|
||||||
|
}
|
||||||
|
|
||||||
|
const navBarElementStyles: React.CSSProperties = {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}
|
||||||
|
|
||||||
type BottomNavBarProps = {
|
type BottomNavBarProps = {
|
||||||
width: number,
|
width: number,
|
||||||
@ -35,18 +32,18 @@ type BottomNavBarProps = {
|
|||||||
|
|
||||||
function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
||||||
return (
|
return (
|
||||||
<div style={styles.navBar}>
|
<div style={navBarStyles}>
|
||||||
<div style={{ ...styles.navBarGroup, width: width }}>
|
<div style={{ ...navBarGroupStyles, width: width }}>
|
||||||
|
|
||||||
<a style={styles.navBarElement} onClick={() => toggleFilters(true)}>
|
<a style={navBarElementStyles} onClick={() => toggleFilters(true)}>
|
||||||
<img src={filterIcon} alt='Фильтровать объявления' title='Фильтровать объявления' />
|
<img src={filterIcon} alt='Фильтровать объявления' title='Фильтровать объявления' />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<Link style={styles.navBarElement} to='/add' >
|
<Link style={navBarElementStyles} to='/add' >
|
||||||
<img src={addIcon} alt='Опубликовать объявление' title='Опубликовать объявление' />
|
<img src={addIcon} alt='Опубликовать объявление' title='Опубликовать объявление' />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link style={styles.navBarElement} to={'/user'} >
|
<Link style={navBarElementStyles} to={'/user'} >
|
||||||
<img src={userIcon} alt='Личный кабинет' title='Личный кабинет' />
|
<img src={userIcon} alt='Личный кабинет' title='Личный кабинет' />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ import ReactDOM from 'react-dom/client'
|
|||||||
|
|
||||||
import App from './App.tsx'
|
import App from './App.tsx'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CSSProperties, FormEventHandler, useEffect, useState } from 'react'
|
import { FormEventHandler, useEffect, useState } from 'react'
|
||||||
import { Form, Button, Card } from 'react-bootstrap'
|
import { Form, Button, Card } from 'react-bootstrap'
|
||||||
import { MapContainer, TileLayer } from 'react-leaflet'
|
import { MapContainer, TileLayer } from 'react-leaflet'
|
||||||
import { latLng } from 'leaflet'
|
import { latLng } from 'leaflet'
|
||||||
@ -11,19 +11,6 @@ import { stations, lines, lineNames } from '../assets/metro'
|
|||||||
import { fallbackError, gotError } from '../hooks/api/useFetch'
|
import { fallbackError, gotError } from '../hooks/api/useFetch'
|
||||||
import { useOsmAddresses } from '../hooks/api'
|
import { useOsmAddresses } from '../hooks/api'
|
||||||
|
|
||||||
const styles = {
|
|
||||||
modal: {
|
|
||||||
height: 'calc(100vh - 3rem)',
|
|
||||||
} as CSSProperties,
|
|
||||||
body: {
|
|
||||||
overflowY: 'auto',
|
|
||||||
} as CSSProperties,
|
|
||||||
map: {
|
|
||||||
width: '100%',
|
|
||||||
height: 400,
|
|
||||||
} as CSSProperties,
|
|
||||||
}
|
|
||||||
|
|
||||||
function AddPage() {
|
function AddPage() {
|
||||||
const [addressPosition, setAddressPosition] = useState(latLng(59.972, 30.3227))
|
const [addressPosition, setAddressPosition] = useState(latLng(59.972, 30.3227))
|
||||||
|
|
||||||
@ -67,8 +54,8 @@ function AddPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className='m-4' style={styles.modal}>
|
<Card className='m-4' style={{ height: 'calc(100vh - 3rem)' }}>
|
||||||
<Card.Body style={styles.body} >
|
<Card.Body style={{ overflowY: 'auto' }} >
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<Form.Group className='mb-3' controlId='name'>
|
<Form.Group className='mb-3' controlId='name'>
|
||||||
<Form.Label>Заголовок объявления</Form.Label>
|
<Form.Label>Заголовок объявления</Form.Label>
|
||||||
@ -97,7 +84,7 @@ function AddPage() {
|
|||||||
<div className='mb-3'>
|
<div className='mb-3'>
|
||||||
<MapContainer
|
<MapContainer
|
||||||
scrollWheelZoom={false}
|
scrollWheelZoom={false}
|
||||||
style={styles.map}
|
style={{ width: '100%', height: 400 }}
|
||||||
center={addressPosition}
|
center={addressPosition}
|
||||||
zoom={13}
|
zoom={13}
|
||||||
>
|
>
|
||||||
@ -156,19 +143,19 @@ function AddPage() {
|
|||||||
<div className='mb-3'>
|
<div className='mb-3'>
|
||||||
{trashboxes.loading
|
{trashboxes.loading
|
||||||
? (
|
? (
|
||||||
<div style={styles.map}>
|
<div style={{ height: 400 }}>
|
||||||
<p>Загрузка...</p>
|
<p>Загрузка...</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
gotError(trashboxes) ? (
|
gotError(trashboxes) ? (
|
||||||
<p
|
<p
|
||||||
style={styles.map}
|
style={{ height: 400 }}
|
||||||
className='text-danger'
|
className='text-danger'
|
||||||
>{trashboxes.error}</p>
|
>{trashboxes.error}</p>
|
||||||
) : (
|
) : (
|
||||||
<MapContainer
|
<MapContainer
|
||||||
scrollWheelZoom={false}
|
scrollWheelZoom={false}
|
||||||
style={styles.map}
|
style={{ width: '100%', height: 400 }}
|
||||||
center={addressPosition}
|
center={addressPosition}
|
||||||
zoom={13}
|
zoom={13}
|
||||||
className=''
|
className=''
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CSSProperties, useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import Stories from 'react-insta-stories'
|
import Stories from 'react-insta-stories'
|
||||||
import { Story } from 'react-insta-stories/dist/interfaces'
|
import { Story } from 'react-insta-stories/dist/interfaces'
|
||||||
|
|
||||||
@ -44,22 +44,17 @@ const fallbackStory = (text = '', isError = false): Story[] => [{
|
|||||||
useEffect(() => { action('pause') }, [action])
|
useEffect(() => { action('pause') }, [action])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={styles.center} className={isError ? 'text-danger' : ''}>
|
<div style={{ margin: 'auto' }} className={isError ? 'text-danger' : ''}>
|
||||||
{text || <img src={puffSpinner} />}
|
{text || <img src={puffSpinner} />}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}]
|
}]
|
||||||
|
|
||||||
const styles = {
|
const storiesContainerCSS = {
|
||||||
container: {
|
display: 'flex',
|
||||||
display: 'flex',
|
justifyContent: 'center',
|
||||||
justifyContent: 'center',
|
backgroundColor: 'rgb(17, 17, 17)'
|
||||||
backgroundColor: 'rgb(17, 17, 17)',
|
|
||||||
} as CSSProperties,
|
|
||||||
center: {
|
|
||||||
margin: 'auto'
|
|
||||||
} as CSSProperties,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function HomePage() {
|
function HomePage() {
|
||||||
@ -74,7 +69,7 @@ function HomePage() {
|
|||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<Filters filter={filter} setFilter={setFilter} filterShown={filterShown} setFilterShown={setFilterShown} />
|
<Filters filter={filter} setFilter={setFilter} filterShown={filterShown} setFilterShown={setFilterShown} />
|
||||||
<div style={styles.container}>
|
<div style={storiesContainerCSS}>
|
||||||
<Stories
|
<Stories
|
||||||
stories={stories}
|
stories={stories}
|
||||||
defaultInterval={11000}
|
defaultInterval={11000}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
NAME=${1:-Route}
|
|
||||||
|
|
||||||
NAME=${NAME^}
|
|
||||||
|
|
||||||
mkdir -p src/api/${NAME,}
|
|
||||||
cat > src/api/${NAME,}/index.ts << EOF
|
|
||||||
import { API_URL } from '../../config'
|
|
||||||
import { ${NAME}Response, ${NAME} } from './types'
|
|
||||||
|
|
||||||
const initial${NAME}: ${NAME} = {}
|
|
||||||
|
|
||||||
const compose${NAME}URL = () =>
|
|
||||||
API_URL + '/${NAME,}?'
|
|
||||||
|
|
||||||
const process${NAME} = (data: ${NAME}Response): ${NAME} => {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
export { initial${NAME}, compose${NAME}URL, process${NAME} }
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat > src/api/${NAME,}/types.ts << EOF
|
|
||||||
import { isObject } from '../../utils/types'
|
|
||||||
|
|
||||||
type ${NAME}Response = {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const is${NAME}Response = (obj: unknown): obj is ${NAME}Response =>
|
|
||||||
isObject(obj, {
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
type ${NAME} = {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const is${NAME} = (obj: unknown): obj is ${NAME} =>
|
|
||||||
isObject(obj, {
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
export type { ${NAME}Response, ${NAME} }
|
|
||||||
|
|
||||||
export { is${NAME}Response, is${NAME} }
|
|
||||||
EOF
|
|
Loading…
x
Reference in New Issue
Block a user