mirror of
https://github.com/phuoc-ng/csslayout.git
synced 2025-08-06 06:07:33 +02:00
Add layout
This commit is contained in:
14
.babelrc
14
.babelrc
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"@loadable/babel-plugin",
|
||||
["prismjs", {
|
||||
"languages": ["css", "html", "javascript", "jsx", "tsx"],
|
||||
// "theme": "okaidia",
|
||||
"css": true
|
||||
}]
|
||||
],
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
]
|
||||
}
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
.DS_Store
|
||||
.netlify
|
||||
dist
|
||||
.next
|
||||
node_modules
|
||||
out
|
||||
package-lock.json
|
||||
tslint.log
|
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@@ -0,0 +1,3 @@
|
||||
.netlify
|
||||
.next
|
||||
node_modules
|
@@ -18,7 +18,7 @@ const main = () => {
|
||||
const browser = await puppeteer.launch();
|
||||
|
||||
const page = await browser.newPage();
|
||||
await page.goto(`http://localhost:1234/patterns/${pattern}`);
|
||||
await page.goto(`http://localhost:3000/patterns/${pattern}`);
|
||||
|
||||
await page.waitForSelector('.demo__live');
|
||||
const element = await page.$('.demo__live');
|
||||
|
32
components/FooterBlock.tsx
Normal file
32
components/FooterBlock.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as React from 'react';
|
||||
import { Footer, FooterGroup, FooterLink } from '@1milligram/design';
|
||||
|
||||
export const FooterBlock = () => (
|
||||
<footer className="block-footer">
|
||||
<div className="block-container">
|
||||
<Footer>
|
||||
<FooterGroup title="Products">
|
||||
<FooterLink href="https://blur.page">Blur Page</FooterLink>
|
||||
<FooterLink href="https://formvalidation.io">Form Validation</FooterLink>
|
||||
<FooterLink href="https://intersectionobserver.io">IntersectionObserver Examples</FooterLink>
|
||||
<FooterLink href="https://react-pdf-viewer.dev">React PDF Viewer</FooterLink>
|
||||
</FooterGroup>
|
||||
<FooterGroup title="Open sources">
|
||||
<FooterLink href="https://1loc.dev">1 LOC</FooterLink>
|
||||
<FooterLink href="https://csslayout.io">CSS Layout</FooterLink>
|
||||
<FooterLink href="https://getfrontend.tips">Front-end Tips</FooterLink>
|
||||
<FooterLink href="https://htmldom.dev">HTML DOM</FooterLink>
|
||||
<FooterLink href="https://thisthat.dev">this VS that</FooterLink>
|
||||
</FooterGroup>
|
||||
<FooterGroup title="Follow us">
|
||||
<FooterLink href="https://github.com/1milligram">GitHub</FooterLink>
|
||||
<FooterLink href="https://twitter.com/nghuuphuoc">Twitter</FooterLink>
|
||||
</FooterGroup>
|
||||
</Footer>
|
||||
|
||||
<div className="block-footer__copyright">
|
||||
© 2020 — {new Date().getFullYear()}, 1 milligram. All rights reserved.
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
37
components/HeaderBlock.tsx
Normal file
37
components/HeaderBlock.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import Link from 'next/link';
|
||||
import * as React from 'react';
|
||||
import { Logo } from '@1milligram/design';
|
||||
|
||||
export const HeaderBlock = () => {
|
||||
const [totalStars, setTotalStars] = React.useState(0);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetch('https://api.github.com/repos/1milligram/csslayout')
|
||||
.then((res) => res.json())
|
||||
.then((data) => setTotalStars(data.stargazers_count))
|
||||
.catch(console.log);
|
||||
}, []);
|
||||
|
||||
const HeaderLogo = React.forwardRef<HTMLAnchorElement, React.LinkHTMLAttributes<HTMLAnchorElement>>(
|
||||
(props, ref) => (
|
||||
<a href={props.href} onClick={props.onClick} ref={ref}>
|
||||
<Logo brand="CSS Layout" />
|
||||
</a>
|
||||
)
|
||||
);
|
||||
|
||||
return (
|
||||
<header className="block-header">
|
||||
<div className="block-container">
|
||||
<div className="block-header__inner">
|
||||
<Link href="/" passHref>
|
||||
<HeaderLogo />
|
||||
</Link>
|
||||
<Link href="https://github.com/1milligram/csslayout">
|
||||
<a className="block-header__cta">GitHub {totalStars}★</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
25
layouts/Layout.tsx
Normal file
25
layouts/Layout.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import Head from 'next/head';
|
||||
import * as React from 'react';
|
||||
import { FooterBlock } from '../components/FooterBlock';
|
||||
import { HeaderBlock } from '../components/HeaderBlock';
|
||||
|
||||
interface LayoutProps {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const Layout: React.FC<LayoutProps> = ({ children, title }) => (
|
||||
<>
|
||||
<Head>
|
||||
<title>{title} - CSS Layout</title>
|
||||
<meta name="description" content={title} />
|
||||
<meta name="twitter:title" content={`${title} - CSS Layout`} />
|
||||
<meta name="twitter:description" content={title} />
|
||||
<meta property="og:title" content={`${title} - CSS Layout`} />
|
||||
<meta property="og:description" content={title} />
|
||||
</Head>
|
||||
|
||||
<HeaderBlock />
|
||||
{children}
|
||||
<FooterBlock />
|
||||
</>
|
||||
);
|
6
next-env.d.ts
vendored
Normal file
6
next-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
9
next.config.js
Normal file
9
next.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const withMDX = require('@next/mdx')({
|
||||
extension: /\.mdx?$/,
|
||||
});
|
||||
|
||||
module.exports = withMDX({
|
||||
// `true` will transform `/about` to `/about/index.html`
|
||||
trailingSlash: true,
|
||||
pageExtensions: ['js', 'jsx', 'tsx', 'mdx'],
|
||||
});
|
88
package.json
88
package.json
@@ -1,61 +1,61 @@
|
||||
{
|
||||
"name": "csslayout",
|
||||
"description": "A collection of popular layouts and patterns made with CSS",
|
||||
"author": {
|
||||
"name": "Nguyen Huu Phuoc",
|
||||
"email": "me@phuoc.ng",
|
||||
"url": "https://twitter.com/nghuuphuoc"
|
||||
},
|
||||
"homepage": "https://csslayout.io",
|
||||
"keywords": [
|
||||
"CSS grid",
|
||||
"CSS flexbox",
|
||||
"CSS layout",
|
||||
"CSS patterns"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/1milligram/csslayout"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/1milligram/csslayout/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"copy": "rimraf dist && mkdir dist && cpx 'public/**/*' dist",
|
||||
"dev": "npm run copy && webpack --mode=development",
|
||||
"dev-server": "npm run copy && NODE_ENV=development webpack serve",
|
||||
"build": "npm run copy && webpack --mode=production && npm run export",
|
||||
"export": "react-snap",
|
||||
"deploy": "npm run build && netlify deploy --dir=dist --prod",
|
||||
"analyse": "NODE_ENV=analyse webpack --config webpack.config.js -p",
|
||||
"build": "next build",
|
||||
"dev": "next dev",
|
||||
"format": "prettier --write \"**/*.+(css|html|json|js|jsx|mdx|scss|ts|tsx)\"",
|
||||
"preexport": "npm run build",
|
||||
"export": "next export",
|
||||
"deploy": "npm run export && netlify deploy --prod --dir=out",
|
||||
"lint": "tslint -c tslint.json -o tslint.log 'client/**/*.{ts,tsx}'",
|
||||
"screenshot": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node bin/generateScreenshot.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@loadable/component": "^5.14.1",
|
||||
"prismjs": "^1.23.0",
|
||||
"@1milligram/design": "^0.4.0",
|
||||
"@1milligram/frame": "^1.0.0",
|
||||
"@mdx-js/loader": "^1.6.22",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@next/mdx": "^11.1.2",
|
||||
"next": "^11.1.2",
|
||||
"prism-react-renderer": "^1.2.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-router-dom": "^5.2.0"
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.13.13",
|
||||
"@babel/preset-env": "^7.13.12",
|
||||
"@babel/preset-react": "^7.13.13",
|
||||
"@loadable/babel-plugin": "^5.13.2",
|
||||
"@types/linkifyjs": "^2.1.4",
|
||||
"@types/loadable__component": "^5.13.3",
|
||||
"@types/prismjs": "^1.16.4",
|
||||
"@types/react": "^17.0.3",
|
||||
"@types/react-dom": "^17.0.3",
|
||||
"@types/react-helmet": "^6.1.0",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-prismjs": "^2.0.1",
|
||||
"cpx2": "^3.0.0",
|
||||
"css-loader": "^5.2.0",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"mini-css-extract-plugin": "^1.4.0",
|
||||
"puppeteer": "^1.20.0",
|
||||
"react-snap": "^1.23.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"source-map-loader": "^2.0.1",
|
||||
"style-loader": "^2.0.0",
|
||||
"@types/react": "^17.0.20",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"puppeteer": "^10.4.0",
|
||||
"prettier": "^2.4.0",
|
||||
"sass": "^1.39.2",
|
||||
"serve": "^12.0.1",
|
||||
"typescript": "^4.4.3",
|
||||
"ts-loader": "^8.1.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-react": "^5.0.0",
|
||||
"typescript": "^4.2.3",
|
||||
"webpack": "^5.28.0",
|
||||
"webpack-bundle-analyzer": "^4.4.0",
|
||||
"webpack-cli": "^4.6.0",
|
||||
"webpack-dev-server": "^3.11.2"
|
||||
},
|
||||
"reactSnap": {
|
||||
"source": "dist",
|
||||
"minifyHtml": {
|
||||
"collapseWhitespace": false,
|
||||
"removeComments": false
|
||||
}
|
||||
"tslint-react": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
17
pages/_app.tsx
Normal file
17
pages/_app.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import Head from 'next/head';
|
||||
|
||||
// Design
|
||||
import '@1milligram/design/lib/styles/index.css';
|
||||
import '@1milligram/frame/lib/styles/index.css';
|
||||
import '../styles/index.scss';
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</Head>
|
||||
<Component {...pageProps} />
|
||||
</>
|
||||
);
|
||||
}
|
44
pages/_document.tsx
Normal file
44
pages/_document.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
class MyDocument extends Document {
|
||||
render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head>
|
||||
<link href="/favicon.png" rel="icon" />
|
||||
<meta charSet="utf-8" />
|
||||
|
||||
<meta content="A collection of popular layouts and patterns made with CSS" name="description" />
|
||||
<meta content="CSS flexbox, CSS grid, CSS layout, CSS patterns" name="keywords" />
|
||||
<meta content="Nguyen Huu Phuoc" name="author" />
|
||||
<meta content="@nghuuphuoc" name="twitter:site" />
|
||||
<meta content="summary" name="twitter:card" />
|
||||
<meta content="A collection of popular layouts and patterns made with CSS" name="twitter:description" />
|
||||
<meta content="A collection of popular layouts and patterns made with CSS" name="twitter:title" />
|
||||
<meta content="/assets/logo.png" name="twitter:image" />
|
||||
|
||||
<meta content="A collection of popular layouts and patterns made with CSS" property="og:title" />
|
||||
<meta content="A collection of popular layouts and patterns made with CSS" property="og:description" />
|
||||
<meta content="article" property="og:type" />
|
||||
<meta content="https://csslayout.io" property="og:url" />
|
||||
<meta content="/assets/logo.png" property="og:image" />
|
||||
<meta content="CSS Layout" property="og:site_name" />
|
||||
|
||||
<link rel="icon" href="/assets/favicon.png" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="true" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?&family=Source+Code+Pro:wght@400&family=Inter:wght@400;700&display=swap"
|
||||
/>
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument;
|
13
pages/index.tsx
Normal file
13
pages/index.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Layout } from '../layouts/Layout';
|
||||
|
||||
const HomePage = () => {
|
||||
return (
|
||||
<Layout title="A collection of popular layouts and patterns made with CSS">
|
||||
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomePage;
|
5
prettier.config.js
Normal file
5
prettier.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
printWidth: 120,
|
||||
singleQuote: true,
|
||||
tabWidth: 4,
|
||||
};
|
30
styles/_reset.scss
Normal file
30
styles/_reset.scss
Normal file
@@ -0,0 +1,30 @@
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: #333;
|
||||
font-family: 'Inter', sans-serif;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 0;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
ol,
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
11
styles/blocks/_footer.scss
Normal file
11
styles/blocks/_footer.scss
Normal file
@@ -0,0 +1,11 @@
|
||||
/* Footer */
|
||||
.block-footer {
|
||||
border-top: 1px solid #e1e1e1;
|
||||
padding-top: 4rem;
|
||||
}
|
||||
.block-footer__copyright {
|
||||
color: #afafaf;
|
||||
margin: 2rem 0 4rem 0;
|
||||
padding: 1rem 0;
|
||||
text-align: center;
|
||||
}
|
23
styles/blocks/_header.scss
Normal file
23
styles/blocks/_header.scss
Normal file
@@ -0,0 +1,23 @@
|
||||
.block-header {
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e4e4e4;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
.block-header__inner {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 3rem;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.block-header__cta {
|
||||
align-items: center;
|
||||
background-color: var(--mgd-color-primary);
|
||||
border-radius: 9999px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
font-weight: 600;
|
||||
height: 2rem;
|
||||
padding: 0 1.5rem;
|
||||
}
|
13
styles/blocks/_layout.scss
Normal file
13
styles/blocks/_layout.scss
Normal file
@@ -0,0 +1,13 @@
|
||||
.block-container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 64rem;
|
||||
}
|
||||
.block-hero {
|
||||
text-align: center;
|
||||
}
|
||||
.block-hero__heading--secondary {
|
||||
color: #808080;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
}
|
6
styles/index.scss
Normal file
6
styles/index.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
@import './reset';
|
||||
|
||||
// Blocks
|
||||
@import 'blocks/footer';
|
||||
@import 'blocks/header';
|
||||
@import 'blocks/layout';
|
@@ -1,12 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
"jsx": "react"
|
||||
}
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
"jsx": "preserve",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* A collection of popular layouts and patterns made with CSS (https://csslayout.io)
|
||||
* (c) 2019 - 2021 Nguyen Huu Phuoc <https://twitter.com/nghuuphuoc>
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const HtmlWebPackPlugin = require("html-webpack-plugin");
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
|
||||
const plugins = [
|
||||
new HtmlWebPackPlugin({
|
||||
template: './client/index.html',
|
||||
filename: './index.html',
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].[contenthash].css',
|
||||
ignoreOrder: false, // Enable to remove warnings about conflicting order
|
||||
}),
|
||||
];
|
||||
|
||||
if (process.env.NODE_ENV === "analyse") {
|
||||
plugins.push(new BundleAnalyzerPlugin());
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mode: process.env.NODE_ENV,
|
||||
entry: {
|
||||
client: './client/index.tsx',
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, 'dist'),
|
||||
filename: '[name].[contenthash].js',
|
||||
// If user browser enables ad blocking, then the pattern likes `Cookie banner` can't be loaded
|
||||
// In order to fix that, we remove the `[name]` from the bundled output
|
||||
chunkFilename: '[contenthash].js',
|
||||
// It's very important
|
||||
// All the chunk generated by webpack then will be loaded such as
|
||||
// <script charset="utf-8" src="/[chunk-name].bundle.js"></script>
|
||||
// The script is accessible from any page that exported by a 3rd party such as react-snap
|
||||
publicPath: '/',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
},
|
||||
'css-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.ts(x?)$/,
|
||||
exclude: /node_modules/,
|
||||
// The order of loaders are very important
|
||||
// It will make the @loadable/component work
|
||||
use: ['babel-loader', 'ts-loader'],
|
||||
},
|
||||
{
|
||||
enforce: "pre",
|
||||
test: /\.js$/,
|
||||
loader: 'source-map-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
|
||||
devServer: {
|
||||
contentBase: path.join(__dirname, 'dist'),
|
||||
historyApiFallback: true,
|
||||
port: 1234,
|
||||
},
|
||||
plugins,
|
||||
};
|
Reference in New Issue
Block a user