mirror of
https://github.com/dzeiocom/markblog.git
synced 2025-06-19 22:19:19 +00:00
128
pages/[category]/[slug].tsx
Normal file
128
pages/[category]/[slug].tsx
Normal file
@ -0,0 +1,128 @@
|
||||
import { NextPageContext } from "next"
|
||||
|
||||
import{ Component } from 'react'
|
||||
import Post from "../../components/Post"
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import Error from "../_error"
|
||||
import Link from "next/link"
|
||||
|
||||
interface Props {
|
||||
post: Post
|
||||
}
|
||||
|
||||
interface States {
|
||||
imgHeight: number
|
||||
}
|
||||
|
||||
export default class PostPage extends Component<Props, States> {
|
||||
public render() {
|
||||
return (
|
||||
<main>
|
||||
{this.props.post === undefined ? (
|
||||
<Error statusCode={404} />
|
||||
) : (
|
||||
<div>
|
||||
<img src={this.props.post.header.image} alt={this.props.post.header.imageAlt} />
|
||||
<ReactMarkdown source={this.props.post.content}/>
|
||||
<h2>Détails</h2>
|
||||
<p>Tags:</p>
|
||||
<ul>
|
||||
{this.props.post.header.tags.map((el) => (
|
||||
<li>
|
||||
<Link href="/tag/[tag]" as={'/tag/'+el.toLowerCase()}>
|
||||
<a className="button">{el}</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{this.props.post.header.url ? (
|
||||
<a className="button outline large" href={this.props.post.header.url}>Visiter le site :D</a>
|
||||
) : undefined}
|
||||
</div>
|
||||
)}
|
||||
<style jsx global>{`
|
||||
main h1 {
|
||||
font-size: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
main h2 {
|
||||
font-size: 40px;
|
||||
text-align: center;
|
||||
text-shadow: 4px 4px 0px rgba(66, 133, 244, 0.5);
|
||||
}
|
||||
main h2::selection {
|
||||
text-shadow: 4px 4px 0px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
main p {
|
||||
text-align: justify;
|
||||
}
|
||||
.header {
|
||||
height: 250px;
|
||||
}
|
||||
@media (min-width: 820px) {
|
||||
.header {
|
||||
height: 0
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
<style jsx>{`
|
||||
main div {
|
||||
margin-top: -150px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 0 10%;
|
||||
}
|
||||
main a.button.outline {
|
||||
align-self: center;
|
||||
}
|
||||
@media (min-width: 820px) {
|
||||
main div {
|
||||
margin-top: 0
|
||||
}
|
||||
main img {
|
||||
max-width: 750px;
|
||||
}
|
||||
}
|
||||
main img {
|
||||
z-index: 999;
|
||||
max-width: 100%;
|
||||
border-radius: 10px;
|
||||
max-height: 300px;
|
||||
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
/*
|
||||
li {
|
||||
border-radius: 10px;
|
||||
background: #4285F4;
|
||||
color: white;
|
||||
margin: 10px;
|
||||
display: inline-block;
|
||||
transition: background 200ms;
|
||||
}
|
||||
li:hover {
|
||||
background: #45CAFC;
|
||||
}
|
||||
li a {
|
||||
padding: 15px 20px;
|
||||
color: white;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
}*/
|
||||
li {
|
||||
display: inline-block;
|
||||
}
|
||||
`}</style>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
public static async getInitialProps(context: NextPageContext) {
|
||||
const { slug } = context.query
|
||||
if (typeof slug === "object" || slug === "[slug]") return {post: undefined}
|
||||
const post = new Post(slug)
|
||||
await post.fetch()
|
||||
return {post}
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ const PortfolioIndex: NextPage<Props> = (props: Props) => {
|
||||
<ul>
|
||||
{props.files.map(post => (
|
||||
<li key={post.slug}>
|
||||
<Link href="/portfolio/[slug]" as={`/portfolio/${post.slug}`}>
|
||||
<Link href="/[category]/[slug]" as={`/${post.slug}`}>
|
||||
<a>{post.title}</a>
|
||||
</Link>
|
||||
</li>
|
||||
@ -41,7 +41,7 @@ PortfolioIndex.getInitialProps = async (context: NextPageContext) => {
|
||||
for (const post of await Post.fetchAll()) {
|
||||
if (!post.isStarted) await post.fetch()
|
||||
arr.push({
|
||||
slug: post.slug,
|
||||
slug: post.slug.replace(".md", ""),
|
||||
title: post.title
|
||||
})
|
||||
}
|
||||
@ -49,10 +49,3 @@ PortfolioIndex.getInitialProps = async (context: NextPageContext) => {
|
||||
}
|
||||
|
||||
export default PortfolioIndex
|
||||
|
||||
function l(args: any) {
|
||||
console.log(arguments)
|
||||
}
|
||||
|
||||
async function test() {
|
||||
}
|
@ -1,23 +1,17 @@
|
||||
import React from 'react'
|
||||
import App from 'next/app'
|
||||
import '../styl/styl.styl'
|
||||
import Layout from '../components/Layout'
|
||||
|
||||
class MyApp extends App {
|
||||
// Only uncomment this method if you have blocking data requirements for
|
||||
// every single page in your application. This disables the ability to
|
||||
// perform automatic static optimization, causing every page in your app to
|
||||
// be server-side rendered.
|
||||
//
|
||||
// static async getInitialProps(appContext) {
|
||||
// // calls page's `getInitialProps` and fills `appProps.pageProps`
|
||||
// const appProps = await App.getInitialProps(appContext);
|
||||
//
|
||||
// return { ...appProps }
|
||||
// }
|
||||
|
||||
render() {
|
||||
const { Component, pageProps } = this.props
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
render() {
|
||||
const { Component, pageProps } = this.props
|
||||
return(
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
|
@ -5,22 +5,24 @@
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
class MyDocument extends Document {
|
||||
static async getInitialProps(ctx) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
return { ...initialProps }
|
||||
}
|
||||
static async getInitialProps(ctx) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
return { ...initialProps }
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head>
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument
|
||||
|
58
pages/_error.tsx
Normal file
58
pages/_error.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import React, { Component } from 'react'
|
||||
import { NextPageContext } from 'next'
|
||||
import Head from 'next/head'
|
||||
import Layout from '../components/Layout'
|
||||
|
||||
interface Props {
|
||||
statusCode: number
|
||||
}
|
||||
|
||||
const codesTexts = {
|
||||
404: "Page non trouvé !",
|
||||
500: "Le serveur n'a pas pu répondre a ta demande :O"
|
||||
}
|
||||
|
||||
export default class Error extends Component<Props, {}> {
|
||||
public render = () => {
|
||||
const statusCode = this.props.statusCode
|
||||
return (
|
||||
<main>
|
||||
<Head>
|
||||
<title>Pouet :D</title>
|
||||
</Head>
|
||||
<div className="errorContainer">
|
||||
<h1>{statusCode ? statusCode : "404"}</h1>
|
||||
<h2>{statusCode ? codesTexts[statusCode] : codesTexts[404]}</h2>
|
||||
</div>
|
||||
<style jsx>{`
|
||||
.errorContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
height: 100%
|
||||
}
|
||||
|
||||
.separator {
|
||||
border: 1px solid black
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 250px;
|
||||
margin: 10px;
|
||||
color: transparent;
|
||||
background: linear-gradient(90deg, #45CAFC 0%, #4285F4 92.19%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
}
|
||||
|
||||
`}</style>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
getInitialProps = ({ res, err }: NextPageContext) => {
|
||||
const statusCode = res ? res.statusCode : err ? err.statusCode : 404
|
||||
return { statusCode }
|
||||
}
|
||||
}
|
133
pages/index.tsx
133
pages/index.tsx
@ -1,124 +1,119 @@
|
||||
import { NextPage } from 'next'
|
||||
import Head from 'next/head'
|
||||
import Link from 'next/link'
|
||||
import '../styl/styl.styl'
|
||||
import Element from '../components/Element'
|
||||
import Navbar from '../components/Navbar'
|
||||
import Header from '../components/Header'
|
||||
import Menu from '../components/Menu'
|
||||
import Filters from '../components/Filters'
|
||||
import Category from '../components/interfaces/Category'
|
||||
import { Component } from 'react'
|
||||
import Post, { PostHeader } from '../components/Post'
|
||||
|
||||
interface Props {
|
||||
userAgent?: string
|
||||
}
|
||||
|
||||
interface el {
|
||||
link: string,
|
||||
title: string,
|
||||
img: string,
|
||||
date: Date
|
||||
}
|
||||
interface el extends PostHeader {}
|
||||
|
||||
interface States {
|
||||
elements: el[]
|
||||
loaded: boolean
|
||||
asideHeight: number
|
||||
categories: string[]
|
||||
}
|
||||
|
||||
// export const config = {amp: 'hybrid'}
|
||||
|
||||
const categories: Category[] = [
|
||||
{
|
||||
name: "test",
|
||||
slug: "pouet"
|
||||
}
|
||||
]
|
||||
|
||||
const elements: el[] = [
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Dzeio.io, Services en ligne pour vous simplifier la vie !", img:"/sea.jpg", date: new Date()},
|
||||
{link:"/studiomoto", title:"Loram ipsum dolor sit amet", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"j'aime les licornes et leurs jolie corne", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Pokémon ! attrapez les tous !", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"abcde", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"def", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"abc", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()},
|
||||
{link:"/studiomoto", title:"Studiomoto, Site de référencement d'événement moto en France", img:"/uploads/stm.png", date: new Date()}
|
||||
]
|
||||
let elements: PostHeader[] = []
|
||||
|
||||
export default class Page extends Component<Props, States> {
|
||||
|
||||
onQuery = (query: string) => {
|
||||
console.log(`query: ${query}`)
|
||||
onQuery = async (query: string, recent: boolean = true) => {
|
||||
// console.log(`query: ${query}`)
|
||||
const t= elements.filter(el => {
|
||||
return el.title.toLowerCase().includes(query.toLowerCase())
|
||||
})
|
||||
if (recent) {
|
||||
t.sort((a, b) => {
|
||||
return (a.date < b.date) ? 1 : -1
|
||||
})
|
||||
} else {
|
||||
t.sort((a, b) => {
|
||||
return (a.date > b.date) ? 1 : -1
|
||||
})
|
||||
}
|
||||
this.setState({
|
||||
elements: t
|
||||
})
|
||||
}
|
||||
|
||||
onHeight = (height: number) => {
|
||||
onHeight = async (height: number) => {
|
||||
this.setState({
|
||||
asideHeight: height
|
||||
})
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
async componentDidMount() {
|
||||
const posts = await Post.fetchAll()
|
||||
const header: Array<PostHeader> = []
|
||||
let cats: Array<string> = []
|
||||
posts.forEach(el => {
|
||||
el.fetchSync()
|
||||
header.push(el.header)
|
||||
cats.push(...el.header.tags)
|
||||
})
|
||||
header.sort((a, b) => {
|
||||
return (a.date < b.date) ? 1 : -1
|
||||
})
|
||||
|
||||
cats.sort((a, b) => (a < b) ? -1 : 1)
|
||||
|
||||
elements = header
|
||||
this.setState({
|
||||
elements
|
||||
elements: header,
|
||||
loaded: true,
|
||||
categories: cats.filter((item, pos) => {return cats.indexOf(item) === pos})
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
</Head>
|
||||
<Navbar>
|
||||
<Menu />
|
||||
</Navbar>
|
||||
<Header />
|
||||
<main>
|
||||
<span>
|
||||
{this.state && this.state.elements.map((el, index) => (
|
||||
<Element key={index} link={el.link} title={el.title} image={el.img} date={el.date} />
|
||||
))}
|
||||
</span>
|
||||
<Filters categories={categories} onQuery={this.onQuery} onHeight={this.onHeight}/>
|
||||
</main>
|
||||
<main>
|
||||
<span>
|
||||
{this.state && this.state.elements && this.state.elements.length !== 0 ? this.state.elements.map((el, index) => (
|
||||
<Element key={index} link={"/"+el.category.toLowerCase() + "/" + el.id} title={el.title} image={el.image} alt={el.imageAlt} date={el.date || new Date} />
|
||||
)) : this.state && this.state.loaded ? (
|
||||
<div>La recherche n'a rien donnée <span className="emoji">😢</span></div>
|
||||
) : (
|
||||
<div>Chargement en cours... <span className="emoji">😃</span></div>
|
||||
)}
|
||||
</span>
|
||||
<Filters categories={this.state && this.state.categories || []} onQuery={this.onQuery} onHeight={this.onHeight}/>
|
||||
<style jsx>{`
|
||||
span {
|
||||
span:not(.emoji) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
div {
|
||||
font-size: 36px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
main span {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
@media (min-width: 820px) and (min-height: ${this.state && this.state.asideHeight ? this.state.asideHeight+100 : 600}px) {
|
||||
main span {
|
||||
@media (min-width: 820px) and (min-height: ${this.state && this.state.asideHeight ? this.state.asideHeight+100 : 600}px) {
|
||||
span {
|
||||
max-width: calc(100% - 400px);
|
||||
}
|
||||
main {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
import { NextPage, NextPageContext } from "next"
|
||||
|
||||
import React from 'react'
|
||||
import Post from "../../components/Post"
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
|
||||
interface Props {
|
||||
post: Post
|
||||
}
|
||||
|
||||
const PostPage: NextPage<Props> = (props: Props) => {
|
||||
// React.
|
||||
return (
|
||||
<main>
|
||||
<ReactMarkdown source={props.post.content}/>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
PostPage.getInitialProps = async (context: NextPageContext) => {
|
||||
const { slug } = context.query
|
||||
if (typeof slug === "object") throw new Error("Slug is not correct")
|
||||
const post = new Post(slug)
|
||||
await post.fetch()
|
||||
return {post}
|
||||
}
|
||||
|
||||
export default PostPage
|
85
pages/tag/[tag].tsx
Normal file
85
pages/tag/[tag].tsx
Normal file
@ -0,0 +1,85 @@
|
||||
import { NextPage, NextPageContext } from "next"
|
||||
import Link from 'next/link'
|
||||
import Post from "../../components/Post"
|
||||
import Element from '../../components/Element'
|
||||
import Error from "../_error"
|
||||
// import posts from '../../posts/pages.json'
|
||||
// import firstline from 'firstline'
|
||||
// import 'fs'
|
||||
|
||||
interface Props {
|
||||
files: Post[],
|
||||
tag: string
|
||||
}
|
||||
|
||||
const PortfolioIndex: NextPage<Props> = (props: Props) => {
|
||||
|
||||
const el: JSX.Element[] = []
|
||||
for (const post of props.files) {
|
||||
el.push(
|
||||
)
|
||||
}
|
||||
|
||||
if (props.files.length === 0) {
|
||||
return (
|
||||
<Error statusCode={404} />
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Tag: {props && props.tag}</h2>
|
||||
<div>
|
||||
{props.files.map((post, index) => (
|
||||
<Element key={index} link={"/"+post.header.category.toLowerCase() + "/" + post.header.id} title={post.header.title} image={post.header.image} date={post.header.date || new Date} />
|
||||
))}
|
||||
</div>
|
||||
<style jsx>{`
|
||||
span:not(.emoji) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
div div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
h2 {
|
||||
display: inline-block;
|
||||
padding: 20px;
|
||||
margin: auto;
|
||||
background: linear-gradient(90deg, #45CAFC 0%, #4285F4 92.19%);
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
PortfolioIndex.getInitialProps = async (context: NextPageContext) => {
|
||||
const { tag } = context.query
|
||||
if (typeof tag === "object" || tag === "[tag]") return {files: [], tag: ""}
|
||||
const arr: Post[] = []
|
||||
for (const post of await Post.fetchAll()) {
|
||||
if (!post.isStarted) await post.fetch()
|
||||
let tags = []
|
||||
for (const tg of post.header.tags) {
|
||||
tags.push(tg.toLowerCase())
|
||||
}
|
||||
if (!tags.includes(tag)) continue
|
||||
arr.push(post)
|
||||
}
|
||||
return {files: arr, tag: tag} as Props
|
||||
}
|
||||
|
||||
export default PortfolioIndex
|
Reference in New Issue
Block a user