diff --git a/next.config.js b/next.config.js index 2f3110f1..536139e2 100644 --- a/next.config.js +++ b/next.config.js @@ -4,7 +4,7 @@ const withSass = require('@zeit/next-sass') module.exports = withCss(withSass({ exportTrailingSlash: true, env: { - APP_ARTICLES_PAGE_SIZE: 15, + APP_ARTICLES_PAGE_SIZE: 12, }, webpack(config) { config.resolve.modules.push(__dirname) diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx index cac1472e..d337d2e3 100644 --- a/src/components/App/index.tsx +++ b/src/components/App/index.tsx @@ -38,14 +38,14 @@ export const App: React.FC = props => { /> )} > -
{props.children} -
+ - + {/* */} ) diff --git a/src/components/ArticleCard/index.tsx b/src/components/ArticleCard/index.tsx index 82191af1..ba0e77da 100644 --- a/src/components/ArticleCard/index.tsx +++ b/src/components/ArticleCard/index.tsx @@ -1,123 +1,43 @@ -import * as React from 'react' +import './styles.css' + import cx from 'classnames' import { Date } from './Date' - -interface IImage { - alt: string - src: string - srcSet: Array<{ url: string, density: number }> -} +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 = ({ article, ...props }) => ( -
- - - -
- {!props.preview ? null : ( - - {props.preview.alt} `${url} ${density}x`).join(' ')} - /> - - )} -
- -
- {article.title} - - {!article.date ? null : ( - - {article.date} - - )} -
-
-
+ {!article.date ? null : ( + + {article.date} + + )} + + + + ) diff --git a/src/components/ArticleCard/styles.css b/src/components/ArticleCard/styles.css new file mode 100644 index 00000000..db9fb096 --- /dev/null +++ b/src/components/ArticleCard/styles.css @@ -0,0 +1,91 @@ +.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 { + } +} diff --git a/src/components/ArticleCardList.tsx b/src/components/ArticleCardList.tsx index 9ee98ae1..0b5655bd 100644 --- a/src/components/ArticleCardList.tsx +++ b/src/components/ArticleCardList.tsx @@ -1,28 +1,21 @@ -import Paginator from './Paginator' import { ArticleCard } from './ArticleCard' +import { Pager } from './Pager' +import { CardGrid } from './CardGrid' +import { IArticle } from 'src/types' export interface IArticleCardListProps { - articles: any[] + articles: IArticle[] nextPage: number | null prevPage: number | null } -export const ArticleCardList:React.FC = ({ articles, nextPage, prevPage }) => ( -
- - - {!prevPage ? null : ( - - )} - -
+export const ArticleCardList: React.FC = ({ articles, nextPage, prevPage, ...props }) => ( + <> + {articles.map((article, i) => { const preview = { alt: article.title, @@ -30,18 +23,24 @@ export const ArticleCardList:React.FC = ({ articles, next srcSet: article.preview.set, } + const gridColumn = article.featured ? 'span 2' : 'auto' + return ( ) })} -
+ - {!nextPage ? null : ( - - )} -
+ + ) diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx new file mode 100644 index 00000000..39cc8faa --- /dev/null +++ b/src/components/Button/index.tsx @@ -0,0 +1,25 @@ +import './styles.css' +import Link from 'next/link' + +export type ButtonProps = { + style?: React.CSSProperties + href?: string +} + +export const Button: React.FC = props => { + if (props.href) { + return ( + + + {props.children} + + + ) + } + + return ( + + ) +} \ No newline at end of file diff --git a/src/components/Button/styles.css b/src/components/Button/styles.css new file mode 100644 index 00000000..84708c32 --- /dev/null +++ b/src/components/Button/styles.css @@ -0,0 +1,25 @@ +.button { + border: none; + font-size: var(--font-size-default); + + text-align: center; + margin-top: var(--size-m); + margin-bottom: var(--size-m); + margin-left: 1px; + margin-right: 1px; + + padding: var(--size-s) var(--size-m); + border-radius: 100px; + + background-color: var(--color-back); + box-shadow: 0 0 0 1px var(--color-shadow); + + transition: box-shadow 150ms; + + outline: none; + cursor: pointer; +} + +.button:hover { + box-shadow: var(--shadow-active); +} diff --git a/src/components/CardGrid/index.tsx b/src/components/CardGrid/index.tsx new file mode 100644 index 00000000..2357d8d3 --- /dev/null +++ b/src/components/CardGrid/index.tsx @@ -0,0 +1,13 @@ +import './styles.css' + +export type CardGridProps = { + style?: React.CSSProperties +} + +export const CardGrid: React.FC = props => { + return ( +
+ {props.children} +
+ ) +} diff --git a/src/components/CardGrid/styles.css b/src/components/CardGrid/styles.css new file mode 100644 index 00000000..4fccc77c --- /dev/null +++ b/src/components/CardGrid/styles.css @@ -0,0 +1,21 @@ +.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-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; + /* grid-template-columns: auto; */ + grid-gap: var(--size-l) 0; + } +} diff --git a/src/components/Pager/index.tsx b/src/components/Pager/index.tsx new file mode 100644 index 00000000..f99889d0 --- /dev/null +++ b/src/components/Pager/index.tsx @@ -0,0 +1,20 @@ +import { Block, BlockProps } from '../Block' +import { Button } from '../Button' +import { Spacer } from '../Spacer' + +export type PagerProps = Omit & { + nextHref: string | null + prevHref: string | null +} + +export const Pager: React.FC = ({ prevHref, nextHref, ...props }) => ( + + {!prevHref ? null : ( + + )} + + {!nextHref ? null : ( + + )} + +) diff --git a/src/components/Paginator.js b/src/components/Paginator.js deleted file mode 100644 index 30f0de90..00000000 --- a/src/components/Paginator.js +++ /dev/null @@ -1,21 +0,0 @@ -const React = require('react') - -const text = ['↑', '↓'] -const linkText = ['Предыдущая страница', 'Следующая страница'] - -const i = type => type === 'top' - ? 0 - : 1 - -const Icon = ({children}) => ( - {children} -) - -const Paginator = ({url, type}) => ( -
- {text[i(type)]} - {linkText[i(type)]} -
-) - -module.exports = Paginator diff --git a/src/components/Wrapper/index.tsx b/src/components/Wrapper/index.tsx index 96c643e5..7105591c 100644 --- a/src/components/Wrapper/index.tsx +++ b/src/components/Wrapper/index.tsx @@ -21,11 +21,16 @@ export const Wrapper: React.FC = props => ( .content { flex: 1; } + + main { + display: flex; + justify-content: center; + } `} {props.header} -
+
{props.children}
diff --git a/src/style.css b/src/style.css index 1a1b9171..da9c3217 100644 --- a/src/style.css +++ b/src/style.css @@ -23,10 +23,12 @@ --tablet-min-width: 31.25em; --tablet-max-width: 64em; + /* CONTENT */ --content-full: 100%; --content-wide: 90%; --content-semi-wide: 70%; --content-thin: 60%; + --content-width: var(--content-full); --embed-video-ratio: 56.25%; @@ -53,6 +55,7 @@ --magenta-color: rgb(214, 39, 246); --red-color: rgb(246, 27, 20); --gray-color: rgb(153, 154, 160); + --color-shadow: rgba(27, 51, 88, 0.15); --inactive-link-color: var(--light-color); @@ -71,7 +74,12 @@ --size-s: 0.5em; --size-m: 1em; --size-l: 2em; - --size-xl: 5em; + --size-xl: 3em; + + /* EFFECTS */ + --radius: 15px; + --shadow: 0 0 8px var(--color-shadow); + --shadow-active: 0 4px 16px var(--color-shadow); /* MARGINS */ --small-margin: 0.2em; @@ -149,9 +157,9 @@ a:active { border-width: 2px; } -a:visited { +/* a:visited { color: #a4059c; -} +} */ a.invisible { border-bottom: none; diff --git a/src/style/components/Paginator.scss b/src/style/components/Paginator.scss deleted file mode 100644 index c30feff5..00000000 --- a/src/style/components/Paginator.scss +++ /dev/null @@ -1,10 +0,0 @@ -.Paginator { - text-align: center; - font-size: var(--font-size-second); - - margin: var(--single-margin) 0; -} - -.Paginator-Icon { - margin: 0 10px; -} \ No newline at end of file diff --git a/src/style/content.scss b/src/style/content.scss index 3889e7fa..437e3889 100644 --- a/src/style/content.scss +++ b/src/style/content.scss @@ -1,25 +1,27 @@ .content { - margin: 0 auto 1em; + // margin: 0 auto 1em; - &.content_full { - width: var(--content-full); - } + width: var(--content-width); +} - &.content_wide { - width: var(--content-wide); - } +.content_full { + --content-width: var(--content-full); +} - &.content_semi-wide { - width: var(--content-semi-wide); - } +.content_wide { + --content-width: var(--content-wide); +} - &.content_thin { - width: var(--content-thin); - } +.content_semi-wide { + --content-width: var(--content-semi-wide); +} - &.content--padding-top--menu { - padding-top: var(--menu-thickness); - } +.content_thin { + --content-width: var(--content-thin); +} + +.content--padding-top--menu { + padding-top: var(--menu-thickness); } // Animation on load diff --git a/src/style/style.scss b/src/style/style.scss index fde37379..fc2389e2 100644 --- a/src/style/style.scss +++ b/src/style/style.scss @@ -6,7 +6,6 @@ @import "components/schedule-table"; @import "components/footer-links"; @import "components/Article"; -@import "components/Paginator"; @import "components/album"; @import "components/ArticleTags"; diff --git a/src/types.ts b/src/types.ts index 7bd31cff..b781be23 100644 --- a/src/types.ts +++ b/src/types.ts @@ -23,3 +23,18 @@ export interface IMeta { twitterSite: string twitterCreator: string } + +export interface IImage { + alt: string + src: string + srcSet: Array<{ url: string, density: number }> + set: any // TODO +} + +export interface IArticle { + id: string + featured: boolean + url: string + title: string + preview: IImage +}