Merge pull request #23 from tmshv/fix/new-cards

New cards
This commit is contained in:
tmshv authored and GitHub committed 2020-02-22 03:13:51 +03:00
commit e09574586a
21 files changed
+245 -347

No files matched your search

+2 -5
View File
@@ -1,7 +1,7 @@
import Head from 'next/head'
import { range } from 'lodash'
import { App } from 'src/components/App'
import { ArticleCardList } from 'src/components/ArticleCardList'
import { ArticleGrid } from 'src/components/ArticleGrid'
import menuModel from 'src/models/menu'
import { buildMenu } from 'src/lib/menu'
import { meta } from 'src/lib/meta'
@@ -31,15 +31,12 @@ const Page: NextPage<Props> = props => {
menu={buildMenu(props.pageUrl, menuModel)}
showAuthor={true}
wide={true}
contentStyle={{
margin: 'var(--size-l) var(--size-xl)'
}}
>
<Head>
<title>{props.title}</title>
<Meta meta={props.meta} />
</Head>
<ArticleCardList
<ArticleGrid
articles={props.data}
prevPage={props.prevPage}
nextPage={props.nextPage}
+19 -10
View File
@@ -3,7 +3,6 @@ import { get } from 'lodash'
import { App } from 'src/components/App'
import { Meta } from 'src/components/Meta'
import { CollectiveImage } from 'src/components/CollectiveImage'
import { PersonCard } from 'src/components/PersonCard'
import menuModel from 'src/models/menu'
import { buildMenu } from 'src/lib/menu'
import { meta } from 'src/lib/meta'
@@ -11,10 +10,12 @@ import { IMeta, IImage } from 'src/types'
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
import { NextPage, NextPageContext } from 'next'
import { CardGrid } from 'src/components/CardGrid'
import { Card } from 'src/components/Card'
interface IPerson {
url: string
name: string
position: string
picture: IImage
}
@@ -37,9 +38,6 @@ const Page: NextPage<Props> = props => {
menu={buildMenu(props.pageUrl, menuModel)}
showAuthor={true}
wide={true}
contentStyle={{
margin: 'var(--size-l) var(--size-xl)'
}}
>
<Head>
<title>{props.title}</title>
@@ -59,13 +57,24 @@ const Page: NextPage<Props> = props => {
marginBottom: 'var(--size-xl)',
}}>
{props.data.map((item, index) => (
<PersonCard
<Card
key={index}
profile={item}
picture={item.picture}
url={item.url}
name={item.name}
/>
layout={'featured'}
img={{
src: item.picture.src,
alt: item.name,
srcSet: '',//item.name.sr,
}}
href={item.url}
>
<h2 style={{
margin: '0 0 var(--size-s)',
fontSize: '14pt',
}}>
{item.name[0]} {item.name[1]} {item.name[2]}
</h2>
{item.position}
</Card>
))}
</CardGrid>
</App>
-3
View File
@@ -28,9 +28,6 @@ const Page: NextPage<Props> = props => {
<App
menu={buildMenu(props.pageUrl, menuModel)}
showAuthor={true}
contentStyle={{
marginTop: 'var(--size-l)'
}}
>
<Head>
<title>{props.data.title}</title>
-3
View File
@@ -103,9 +103,6 @@ const Page: NextPage<IProps> = props => (
<App
menu={buildMenu(props.pageUrl, menuModel)}
showAuthor={true}
contentStyle={{
marginTop: 'var(--size-l)'
}}
>
<Head>
<title>{props.title}</title>
-3
View File
@@ -74,9 +74,6 @@ const Page: NextPage<IProps> = props => (
menu={buildMenu(props.pageUrl, menuModel)}
showAuthor={true}
wide={true}
contentStyle={{
margin: 'var(--size-l) var(--size-xl)'
}}
>
<Head>
<title>{props.title}</title>
+6 -5
View File
@@ -1,7 +1,7 @@
import Head from 'next/head'
import { App } from 'src/components/App'
import { Meta } from 'src/components/Meta'
import { ArticleCardList } from 'src/components/ArticleCardList'
import { ArticleGrid } from 'src/components/ArticleGrid'
import { HudozkaTitle } from 'src/components/HudozkaTitle'
import menuModel from 'src/models/menu'
import { meta } from 'src/lib/meta'
@@ -24,9 +24,6 @@ const Page: NextPage<IProps> = props => (
menu={buildMenu(props.pageUrl, menuModel)}
showAuthor={true}
wide={true}
contentStyle={{
margin: 'var(--size-l) var(--size-xl)',
}}
>
<Head>
<title>{props.title}</title>
@@ -39,7 +36,7 @@ const Page: NextPage<IProps> = props => (
}}
/>
<ArticleCardList
<ArticleGrid
articles={props.articles}
prevPage={props.prevPage}
nextPage={props.nextPage}
@@ -53,6 +50,10 @@ export const unstable_getStaticProps = async () => {
const pageSize = process.env.APP_ARTICLES_PAGE_SIZE
const res = await requestGet<IResponseItems<IArticle>>(createApiUrl(`/api/articles?page=${page}&pageSize=${pageSize}`), null)
const articles = (res.items || [])
.map(x => ({
...x,
featured: ['2019-kotiki', 'veloparking'].includes(x.id)
}))
const nextPage = res.nextPage
const prevPage = res.prevPage
const title = 'Шлиссельбургская ДХШ'
-3
View File
@@ -18,9 +18,6 @@ const Page: NextPage<Props> = props => (
menu={buildMenu(props.pageUrl, menuModel)}
showAuthor={true}
wide={true}
contentStyle={{
marginTop: 'var(--size-l)'
}}
>
<Head>
<title>{props.title}</title>
-14
View File
@@ -1,14 +0,0 @@
import * as React from 'react'
import { dateFormat } from '../../lib/date'
export const Date: React.FC<{ children: string }> = ({ children }) => (
<p>
<style jsx>{`
p {
color: #ccc;
font-size: small;
}
`}</style>
{dateFormat(children)}
</p>
)
-43
View File
@@ -1,43 +0,0 @@
import './styles.css'
import cx from 'classnames'
import { Date } from './Date'
import { IImage } from 'src/types'
import Link from 'next/link'
export interface IArticleCardProps {
style?: React.CSSProperties
article: any
preview?: IImage
}
export const ArticleCard: React.FC<IArticleCardProps> = ({ article, ...props }) => (
<div className="ArticleCard" style={props.style}>
<Link href={article.url}>
<a className="invisible">
<div className="ArticleCard-image">
{!props.preview ? null : (
<picture>
<img
className={cx({ opa: false })}
alt={props.preview.alt}
src={props.preview.src}
srcSet={props.preview.srcSet.map(({ url, density }) => `${url} ${density}x`).join(' ')}
/>
</picture >
)}
</div>
<div className="ArticleCard-body">
{article.title}
{!article.date ? null : (
<Date>
{article.date}
</Date>
)}
</div>
</a>
</Link>
</div>
)
-91
View File
@@ -1,91 +0,0 @@
.ArticleCard {
--article-card-image-height: 15em;
display: flex;
flex-direction: column;
border-radius: var(--radius);
box-shadow: var(--shadow);
/* box-shadow: 0 0 0 1px var(--color-shadow); */
overflow: hidden;
transition: box-shadow 150ms;
}
.ArticleCard:hover {
box-shadow: var(--shadow-active);
}
.ArticleCard > a {
display: block;
position: relative;
}
.ArticleCard-image {
overflow: hidden;
position: relative;
width: 100%;
height: var(--article-card-image-height);
}
.ArticleCard-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: all 150ms ease-out;
position: absolute;
top: 0;
left: 0;
}
.ArticleCard-body {
position: relative;
z-index: 1000;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
height: 5em;
background-color: white;
padding: 0 var(--size-m) var(--size-m);
}
.ArticleCard-body:before {
position: absolute;
content: '';
background-color: white;
border-radius: var(--radius) var(--radius) 0 0 ;
width: 100%;
height: var(--radius);
top: calc(var(--radius) * -1);
left: 0;
}
.ArticleCard:hover img {
width: 104%;
height: 104%;
top: -2%;
left: -2%;
}
/* Tablet */
@media screen and (min-width: var(--tablet-min-width)) and (max-width: var(--tablet-max-width)) {
.ArticleCard {
--article-card-image-height: 12em;
}
}
/* Mobile */
@media (max-width: 31.25em) {
.ArticleCard {
}
}
-46
View File
@@ -1,46 +0,0 @@
import { ArticleCard } from './ArticleCard'
import { Pager } from './Pager'
import { CardGrid } from './CardGrid'
import { IArticle } from 'src/types'
export interface IArticleCardListProps {
articles: IArticle[]
nextPage: number | null
prevPage: number | null
}
export const ArticleCardList: React.FC<IArticleCardListProps> = ({ articles, nextPage, prevPage, ...props }) => (
<>
<CardGrid
style={{
marginBottom: 'var(--size-m)',
}}
>
{articles.map((article, i) => {
const preview = {
alt: article.title,
src: article.preview.src,
srcSet: article.preview.set,
}
const gridColumn = article.featured ? 'span 2' : 'auto'
return (
<ArticleCard
key={i}
article={article}
preview={preview as any}
style={{
gridColumn
}}
/>
)
})}
</CardGrid>
<Pager
nextHref={nextPage ? `/articles/${nextPage}` : null}
prevHref={prevPage ? `/articles/${prevPage}` : null}
/>
</>
)
+17
View File
@@ -0,0 +1,17 @@
import { dateFormat } from 'src/lib/date'
export type DateProps = {
style?: React.CSSProperties
children: string | Date
}
export const Date: React.FC<DateProps> = props => (
<p style={props.style}>
<style jsx>{`
p {
color: var(--color-text-second);
font-size: var(--font-size-second);
}
`}</style>
{dateFormat(props.children)}
</p>
)
+67
View File
@@ -0,0 +1,67 @@
import { IArticle } from 'src/types'
import { Pager } from '../Pager'
import { CardGrid } from '../CardGrid'
import { Card, CardLayout } from '../Card'
import { Date } from './Date'
import { Block } from '../Block'
import { Spacer } from '../Spacer'
export type ArticleGridProps = {
articles: IArticle[]
nextPage: number | null
prevPage: number | null
}
export const ArticleGrid: React.FC<ArticleGridProps> = ({ articles, nextPage, prevPage, ...props }) => (
<>
<CardGrid
style={{
marginBottom: 'var(--size-m)',
}}
>
{articles.map((article, i) => {
const gridColumn = article.featured ? 'span 2' : 'auto'
const layout: CardLayout = article.featured ? 'featured' : 'simple'
const srcSet = article.preview.set.map(({ url, density }) => `${url} ${density}x`).join(' ')
const content = !article.featured
? (
<Block
direction={'vertical'}
>
{article.title}
<Spacer />
<Date style={{
marginTop: 'var(--size-m)',
}}>{article.date}</Date>
</Block>
) : (
article.title
)
return (
<Card
key={i}
href={article.url}
img={{
alt: article.title,
src: article.preview.src,
srcSet,
}}
layout={layout}
style={{
gridColumn,
}}
>
{content}
</Card>
)
})}
</CardGrid>
<Pager
nextHref={nextPage ? `/articles/${nextPage}` : null}
prevHref={prevPage ? `/articles/${prevPage}` : null}
/>
</>
)
+36
View File
@@ -0,0 +1,36 @@
import './styles.css'
import cx from 'classnames'
import Link from 'next/link'
export type CardLayout = 'simple' | 'featured'
export type CardProps = {
style?: React.CSSProperties
href: string
img: {
alt: string
src: string
srcSet: string
}
layout: CardLayout
}
export const Card: React.FC<CardProps> = props => (
<div className={cx('card', props.layout)} style={props.style}>
<Link href={props.href}>
<a>
<div className={'card-image'}>
<img
className={cx({ opa: false })}
alt={props.img.alt}
src={props.img.src}
srcSet={props.img.srcSet}
/>
</div>
<div className={'card-body'}>
{props.children}
</div>
</a>
</Link>
</div>
)
+85
View File
@@ -0,0 +1,85 @@
.card {
border-radius: var(--radius);
box-shadow: var(--shadow);
overflow: hidden;
transition: box-shadow 150ms;
}
.card:hover {
box-shadow: var(--shadow-active);
}
.card:hover img {
width: 104%;
height: 104%;
top: -2%;
left: -2%;
}
.card > a {
display: block;
height: 100%;
position: relative;
}
.card-image {
position: relative;
width: 100%;
height: 100%;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: all 150ms ease-out;
position: absolute;
top: 0;
left: 0;
}
.card-body {
background-color: var(--color-back-main);
padding: var(--size-m);
}
/* SIMPLE */
.card.simple .card-body {
position: relative;
padding-top: 0;
}
.card.simple .card-body:before {
position: absolute;
content: '';
background-color: var(--color-back-main);
border-radius: var(--radius) var(--radius) 0 0;
width: 100%;
height: var(--radius);
top: calc(var(--radius) * -1);
left: 0;
}
.card.simple > a {
display: flex;
flex-direction: column;
}
/* FEATURED */
.card.featured .card-body {
position: absolute;
--offset: var(--size-m);
--r: var(--size-s);
left: var(--offset);
right: var(--offset);
bottom: var(--offset);
border-radius: var(--radius) var(--radius) var(--r) var(--r);
}
+2 -7
View File
@@ -1,17 +1,12 @@
.card-grid {
--min-cell-size: 240px;
display: grid;
/* grid-template-columns: 1fr 1fr 1fr; */
grid-template-columns: repeat(auto-fill, minmax(var(--min-cell-size), 1fr));
grid-auto-rows: 1fr;
grid-auto-rows: 25em;
grid-auto-flow: dense;
grid-gap: var(--size-xl) var(--size-l);
}
/* .card-grid > *:first-child {
grid-row: 1 / 1;
grid-column: 1 / 1;
} */
@media screen and (max-width: 31.25em) {
.card-grid {
grid-template-columns: 1fr;
-29
View File
@@ -1,29 +0,0 @@
import './styles.css'
import cx from 'classnames'
import { Image } from '../Image'
export const PersonCard = ({ picture, name, url, profile }) => (
<div className={'personCard'}>
<a className={'invisible'} href={url}>
<div className={'personCard-Picture'}>
<picture>
<img
className={cx({ opa: false })}
alt={''}
src={picture.src}
srcSet={picture.set.map(({ url, density }) => `${url} ${density}x`)}
/>
</picture>
</div>
<div className={'personCard-Title'}>
{name[0]} {name[1]} {name[2]}
</div>
<div className={'personCard-Body'}>
{profile.position}
</div>
</a>
</div>
)
-72
View File
@@ -1,72 +0,0 @@
.personCard {
--person-card-height: 24em;
display: flex;
flex-direction: column;
min-width: 10em;
max-width: 30em;
}
.personCard > a {
display: block;
position: relative;
}
.personCard-Picture {
position: relative;
border-radius: var(--radius);
width: 100%;
height: var(--person-card-height);
overflow: hidden;
}
.personCard-Picture img {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
object-fit: cover;
transition: all 150ms ease-out;
}
.personCard-Title,
.personCard-Body {
position: absolute;
width: 100%;
padding: var(--single-margin);
box-sizing: border-box;
color: white;
text-align: center;
text-shadow: 0 0 3px #000;
}
.personCard-Title {
top: 0;
}
.personCard-Body {
bottom: 0;
}
.personCard:hover img {
width: 105%;
height: 105%;
top: -2.5%;
left: -2.5%;
}
/* Tablet */
@media screen and (min-width: var(--tablet-min-width)) and (max-width: var(--tablet-max-width)) {
.personCard {
--person-card-height: 20em;
}
@media screen and (orientation: portrait) {
}
}
+8 -4
View File
@@ -22,8 +22,10 @@
--tablet-max-width: 64em;
/* CONTENT */
--content-wide: 100%;
--content-width: 60%;
--content-margin: 0;
--content-wide-width: 100%;
--content-wide-margin: var(--size-l) var(--size-xl);
--embed-video-ratio: 56.25%;
@@ -65,14 +67,14 @@
--color-back-opposite: var(--darker-color);
/* SIZE */
--size-sx: 0.2em;
--size-xs: 0.25em;
--size-s: 0.5em;
--size-m: 1em;
--size-l: 2em;
--size-xl: 3em;
/* EFFECTS */
--radius: 15px;
--radius: 16px;
--shadow: 0 0 8px var(--color-shadow);
--shadow-active: 0 4px 16px var(--color-shadow);
@@ -193,7 +195,9 @@ a.invisible {
--font-size-h2: 1.5rem;
--font-size-h3: 1.25rem;
--content-wide: 90%;
--content-width: 100%;
--content-margin: var(--size-l);
--content-wide-margin: var(--size-l) var(--size-l);
--kazimir-image-increase: 0px;
}
-8
View File
@@ -15,8 +15,6 @@
}
&-Body {
--text-margin: 10px;
ul,
ol {
margin-left: var(--half-margin);
@@ -36,12 +34,6 @@
line-height: var(--article-line-height);
}
h2,
h3 {
margin-left: var(--text-margin);
margin-right: var(--text-margin);
}
blockquote {
background-color: hsl(215, 10%, 96%);
padding: var(--article-quote-padding);
+3 -1
View File
@@ -1,9 +1,11 @@
.content {
width: var(--content-width);
margin: var(--content-margin);
}
.content_wide {
--content-width: var(--content-wide);
--content-width: var(--content-wide-width);
--content-margin: var(--content-wide-margin);
}
/* Animation on load */