mirror of
https://github.com/kremalicious/portfolio.git
synced 2024-12-23 01:29:41 +01:00
Merge pull request #6 from kremalicious/feature/projectslider
Add projects slider
This commit is contained in:
commit
2f13a07652
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
"stylelint-config-standard",
|
"stylelint-config-standard",
|
||||||
|
"stylelint-config-css-modules",
|
||||||
"./node_modules/prettier-stylelint/config.js"
|
"./node_modules/prettier-stylelint/config.js"
|
||||||
],
|
],
|
||||||
"syntax": "scss",
|
"syntax": "scss",
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
"prettier-stylelint": "^0.4.2",
|
"prettier-stylelint": "^0.4.2",
|
||||||
"slugify": "^1.3.0",
|
"slugify": "^1.3.0",
|
||||||
"stylelint": "^9.2.1",
|
"stylelint": "^9.2.1",
|
||||||
|
"stylelint-config-css-modules": "^1.2.0",
|
||||||
"stylelint-config-standard": "^18.2.0"
|
"stylelint-config-standard": "^18.2.0"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
font-size: $font-size-h4;
|
font-size: $font-size-h4;
|
||||||
color: $brand-grey;
|
color: $brand-grey;
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
color: $brand-grey-light;
|
color: $brand-grey-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,14 +45,16 @@
|
|||||||
transform-origin: top center;
|
transform-origin: top center;
|
||||||
transform-box: border-box;
|
transform-box: border-box;
|
||||||
|
|
||||||
|
// stylelint-disable no-descending-specificity
|
||||||
.logounit__title,
|
.logounit__title,
|
||||||
.logounit__description {
|
.logounit__description {
|
||||||
color: $brand-grey-light;
|
color: $brand-grey-light;
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
color: $brand-grey;
|
color: $brand-grey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// stylelint-enable no-descending-specificity
|
||||||
|
|
||||||
.logounit__logo {
|
.logounit__logo {
|
||||||
margin-bottom: $spacer / 3;
|
margin-bottom: $spacer / 3;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
transition: opacity .2s ease-out;
|
transition: opacity .2s ease-out;
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
color: $text-color-light--dark;
|
color: $text-color-light--dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: $spacer;
|
bottom: $spacer;
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
background: rgba($body-background-color--dark, .8);
|
background: rgba($body-background-color--dark, .8);
|
||||||
color: $brand-light;
|
color: $brand-light;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,16 @@
|
|||||||
transition: none;
|
transition: none;
|
||||||
background: rgba(#fff, .15);
|
background: rgba(#fff, .15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.dark) & {
|
||||||
|
background: darken($body-background-color--dark, 1%);
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 6px 10px rgba(darken($brand-main, 20%), .1),
|
||||||
|
0 10px 25px rgba(darken($brand-main, 20%), .1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,61 +1,77 @@
|
|||||||
import React from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import Link from 'gatsby-link'
|
import Link from 'gatsby-link'
|
||||||
import Img from 'gatsby-image'
|
import Img from 'gatsby-image'
|
||||||
import FullWidth from '../atoms/FullWidth'
|
import FullWidth from '../atoms/FullWidth'
|
||||||
import { ReactComponent as Index } from '../../images/index.svg'
|
|
||||||
|
|
||||||
import icons from '../atoms/Icons.module.scss'
|
|
||||||
import styles from './ProjectNav.module.scss'
|
import styles from './ProjectNav.module.scss'
|
||||||
|
|
||||||
const ProjectNavLink = ({ previous, next }) => {
|
const ProjectItem = ({ title, slug, img, current }) => (
|
||||||
const slug = previous ? previous.slug : next.slug
|
<div className={styles.item} id={current ? 'current' : null}>
|
||||||
const title = previous ? previous.title : next.title
|
<Link className={styles.link} to={slug}>
|
||||||
const img = previous ? previous.img : next.img
|
<Img
|
||||||
|
className={styles.image}
|
||||||
return (
|
sizes={img.childImageSharp.sizes}
|
||||||
<div className={styles.item}>
|
alt={title}
|
||||||
<Link className={styles.link + ' prev'} to={slug}>
|
/>
|
||||||
<Img
|
<h1 className={styles.title}>{title}</h1>
|
||||||
className={styles.image}
|
</Link>
|
||||||
sizes={img.childImageSharp.sizes}
|
</div>
|
||||||
alt={title}
|
|
||||||
/>
|
|
||||||
<h1 className={styles.title}>{title}</h1>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProjectNav = ({ previous, next }) => (
|
|
||||||
<FullWidth>
|
|
||||||
<nav className={styles.projectNav}>
|
|
||||||
{previous && <ProjectNavLink previous={previous} />}
|
|
||||||
<Link className={styles.index} title="Back to projects" to={'/'}>
|
|
||||||
<Index className={icons.icon} />
|
|
||||||
</Link>
|
|
||||||
{next ? (
|
|
||||||
<ProjectNavLink next={next} />
|
|
||||||
) : (
|
|
||||||
<div className={`${styles.item} ${styles.itemEnd}`}>
|
|
||||||
<div className={styles.end}>
|
|
||||||
<h3>This is the end</h3>
|
|
||||||
<p>I would rather not show you my websites from 1999.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</nav>
|
|
||||||
</FullWidth>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ProjectNavLink.propTypes = {
|
class ProjectNav extends Component {
|
||||||
previous: PropTypes.object,
|
constructor(props) {
|
||||||
next: PropTypes.object
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.scrollToCurrent()
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToCurrent = () => {
|
||||||
|
const container = window.document.getElementById('scrollContainer')
|
||||||
|
const current = window.document.getElementById('current')
|
||||||
|
const currentLeft = current.getBoundingClientRect().left
|
||||||
|
const currentWidth = current.clientWidth
|
||||||
|
const finalPosition = currentLeft - window.innerWidth / 2 + currentWidth / 2
|
||||||
|
|
||||||
|
container.scrollLeft = finalPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { projects, project } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FullWidth>
|
||||||
|
<nav className={styles.projectNav} id="scrollContainer">
|
||||||
|
{projects.map(({ node }) => {
|
||||||
|
const current = node.slug === project.slug
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProjectItem
|
||||||
|
key={node.slug}
|
||||||
|
title={node.title}
|
||||||
|
current={current}
|
||||||
|
slug={node.slug}
|
||||||
|
img={node.img}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
</FullWidth>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectItem.propTypes = {
|
||||||
|
current: PropTypes.bool,
|
||||||
|
title: PropTypes.string,
|
||||||
|
slug: PropTypes.string,
|
||||||
|
img: PropTypes.object
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectNav.propTypes = {
|
ProjectNav.propTypes = {
|
||||||
previous: PropTypes.object,
|
projects: PropTypes.array,
|
||||||
next: PropTypes.object
|
project: PropTypes.object
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProjectNav
|
export default ProjectNav
|
||||||
|
@ -1,12 +1,24 @@
|
|||||||
@import 'variables';
|
@import 'variables';
|
||||||
|
|
||||||
$breakpoint-project-nav: 45rem;
|
|
||||||
|
|
||||||
.projectNav {
|
.projectNav {
|
||||||
display: flex;
|
white-space: nowrap;
|
||||||
flex-wrap: wrap;
|
overflow-y: hidden;
|
||||||
justify-content: space-between;
|
overflow-x: scroll;
|
||||||
overflow: hidden;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: inline-block;
|
||||||
|
width: 40vw;
|
||||||
|
margin-left: $spacer * 2;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: $spacer * 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.image {
|
.image {
|
||||||
@ -14,54 +26,12 @@ $breakpoint-project-nav: 45rem;
|
|||||||
box-shadow: 0 3px 5px rgba($brand-main, .15),
|
box-shadow: 0 3px 5px rgba($brand-main, .15),
|
||||||
0 5px 16px rgba($brand-main, .15);
|
0 5px 16px rgba($brand-main, .15);
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
box-shadow: 0 3px 5px rgba(darken($brand-main, 20%), .15),
|
box-shadow: 0 3px 5px rgba(darken($brand-main, 20%), .15),
|
||||||
0 5px 16px rgba(darken($brand-main, 20%), .15);
|
0 5px 16px rgba(darken($brand-main, 20%), .15);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
|
||||||
flex: 1 1 46%;
|
|
||||||
position: relative;
|
|
||||||
transition: .2s ease-out;
|
|
||||||
max-width: 500px;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-right: $spacer / 2;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
transform: translate3d(-.5rem, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stylelint-disable no-descending-specificity */
|
|
||||||
&:last-child {
|
|
||||||
margin-left: $spacer / 2;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
transform: translate3d(.5rem, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* stylelint-enable no-descending-specificity */
|
|
||||||
|
|
||||||
@media (min-width: $breakpoint-project-nav) {
|
|
||||||
flex-basis: 33%;
|
|
||||||
|
|
||||||
&:first-child,
|
|
||||||
&:last-child {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.itemEnd {
|
|
||||||
pointer-events: none;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
@ -70,69 +40,3 @@ $breakpoint-project-nav: 45rem;
|
|||||||
.link {
|
.link {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.index {
|
|
||||||
height: 100%;
|
|
||||||
display: block;
|
|
||||||
align-self: center;
|
|
||||||
margin-top: $spacer * 2;
|
|
||||||
margin-left: $spacer;
|
|
||||||
margin-right: $spacer;
|
|
||||||
transition: .2s ease-out;
|
|
||||||
order: 3;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
@media (min-width: $breakpoint-project-nav) {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-left: $spacer * 4;
|
|
||||||
margin-right: $spacer * 4;
|
|
||||||
order: initial;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
fill: $brand-grey-light;
|
|
||||||
width: 1.5rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
svg {
|
|
||||||
fill: $brand-cyan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 48.5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.end {
|
|
||||||
padding-right: $spacer;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: $font-size-h4;
|
|
||||||
margin-bottom: $spacer / 4;
|
|
||||||
color: $brand-grey-light;
|
|
||||||
|
|
||||||
@media (min-width: $breakpoint-project-nav) {
|
|
||||||
font-size: $font-size-h3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
color: $brand-grey-light;
|
|
||||||
font-size: $font-size-small;
|
|
||||||
|
|
||||||
@media (min-width: $breakpoint-project-nav) {
|
|
||||||
font-size: $font-size-base;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
margin-bottom: $spacer / 2;
|
margin-bottom: $spacer / 2;
|
||||||
flex: 0 0 calc(50% - #{$spacer / 2});
|
flex: 0 0 calc(50% - #{$spacer / 2});
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
|
|
||||||
|
:global(.dark) & {
|
||||||
|
background: darken($body-background-color--dark, 1%);
|
||||||
|
color: $brand-grey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
height: .7rem;
|
height: .7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
fill: $brand-grey;
|
fill: $brand-grey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ $knob-space: 1px;
|
|||||||
transform: translate3d(0, 0, 0);
|
transform: translate3d(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
border-color: $brand-grey;
|
border-color: $brand-grey;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
@ -69,7 +69,7 @@ $knob-space: 1px;
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: .6;
|
opacity: .6;
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
opacity: .8;
|
opacity: .8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
margin-bottom: $spacer * 2;
|
margin-bottom: $spacer * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark & {
|
:global(.dark) & {
|
||||||
color: $text-color-light--dark;
|
color: $text-color-light--dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,12 +29,12 @@
|
|||||||
margin-left: $spacer;
|
margin-left: $spacer;
|
||||||
color: $text-color-light;
|
color: $text-color-light;
|
||||||
|
|
||||||
.dark & {
|
|
||||||
color: $text-color-light--dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.dark) & {
|
||||||
|
color: $text-color-light--dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,10 @@ class Project extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const meta = this.props.data.dataYaml
|
const meta = this.props.data.dataYaml
|
||||||
|
const projects = this.props.data.allProjectsYaml.edges
|
||||||
const project = this.props.data.projectsYaml
|
const project = this.props.data.projectsYaml
|
||||||
const projectImages = this.props.data.projectImages.edges
|
const projectImages = this.props.data.projectImages.edges
|
||||||
const pathContext = this.props.pathContext
|
|
||||||
const { title, links, techstack } = project
|
const { title, links, techstack } = project
|
||||||
const { next, previous } = pathContext
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
@ -67,7 +66,7 @@ class Project extends Component {
|
|||||||
</Content>
|
</Content>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<ProjectNav previous={previous} next={next} />
|
<ProjectNav projects={projects} project={project} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -90,7 +89,7 @@ Project.propTypes = {
|
|||||||
|
|
||||||
export default Project
|
export default Project
|
||||||
|
|
||||||
export const projectQuery = graphql`
|
export const projectAndProjectsQuery = graphql`
|
||||||
query ProjectBySlug($slug: String!) {
|
query ProjectBySlug($slug: String!) {
|
||||||
projectsYaml(slug: { eq: $slug }) {
|
projectsYaml(slug: { eq: $slug }) {
|
||||||
title
|
title
|
||||||
@ -136,6 +135,7 @@ export const projectQuery = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
projectImages: allImageSharp(
|
projectImages: allImageSharp(
|
||||||
filter: { id: { regex: $slug } }
|
filter: { id: { regex: $slug } }
|
||||||
sort: { fields: [id], order: ASC }
|
sort: { fields: [id], order: ASC }
|
||||||
@ -147,5 +147,19 @@ export const projectQuery = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allProjectsYaml {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
img {
|
||||||
|
childImageSharp {
|
||||||
|
...ProjectImageSizes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
Loading…
Reference in New Issue
Block a user