upstream #1
| @@ -1,5 +1,5 @@ | ||||
| import Image from 'next/image' | ||||
| import Link from '@/components/Link' | ||||
| import Image from './Image' | ||||
| import Link from './Link' | ||||
|  | ||||
| const Card = ({ title, description, imgSrc, href }) => ( | ||||
|   <div className="p-4 md:w-1/2 md" style={{ maxWidth: '544px' }}> | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| import { MDXRemote } from 'next-mdx-remote' | ||||
| /* eslint-disable react/display-name */ | ||||
| import { useMemo } from 'react' | ||||
| import { getMDXComponent } from 'mdx-bundler/client' | ||||
| import Image from './Image' | ||||
| import CustomLink from './Link' | ||||
| import Pre from './Pre' | ||||
| @@ -7,14 +9,14 @@ export const MDXComponents = { | ||||
|   Image, | ||||
|   a: CustomLink, | ||||
|   pre: Pre, | ||||
|   wrapper: ({ components, layout, ...rest }) => { | ||||
|     const Layout = require(`../layouts/${layout}`).default | ||||
|     return <Layout {...rest} /> | ||||
|   }, | ||||
| } | ||||
|  | ||||
| export const MDXLayoutRenderer = ({ layout, mdxSource, ...rest }) => { | ||||
|   const LayoutComponent = require(`../layouts/${layout}`).default | ||||
|   const MDXLayout = useMemo(() => getMDXComponent(mdxSource), [mdxSource]) | ||||
|  | ||||
|   return ( | ||||
|     <LayoutComponent {...rest}> | ||||
|       <MDXRemote {...mdxSource} components={MDXComponents} /> | ||||
|     </LayoutComponent> | ||||
|   ) | ||||
|   return <MDXLayout layout={layout} components={MDXComponents} {...rest} /> | ||||
| } | ||||
|   | ||||
| @@ -14,6 +14,19 @@ | ||||
|   @apply hidden; | ||||
| } | ||||
|  | ||||
| .code-line { | ||||
|   @apply pl-4 -mx-4 border-l-4 border-gray-800; | ||||
| } | ||||
|  | ||||
| .highlight-line { | ||||
|   @apply -mx-4 bg-gray-700 bg-opacity-50 border-l-4 border-primary-500; | ||||
| } | ||||
|  | ||||
| .line-number::before { | ||||
|   @apply pr-4 -ml-2 text-gray-400; | ||||
|   content: attr(line); | ||||
| } | ||||
|  | ||||
| html { | ||||
|   scroll-behavior: smooth; | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| --- | ||||
| name: Sparrow Hawk | ||||
| avatar: https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Accnis_edit.jpg/220px-Accnis_edit.jpg | ||||
| avatar: /static/images/sparrowhawk-avatar.jpg | ||||
| occupation: Wizard of Earthsea | ||||
| company: Earthsea | ||||
| twitter: https://twitter.com/sparrowhawk | ||||
|   | ||||
| @@ -140,6 +140,7 @@ function fancyAlert(arg) { | ||||
|     $.facebox({ div: '#foo' }) | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| ```` | ||||
|  | ||||
| And here's how it looks - nicely colored with styled code titles! | ||||
|   | ||||
| @@ -50,14 +50,10 @@ _Note_: If you try to save the image, it is in webp format, if your browser supp | ||||
|  | ||||
|  | ||||
| <p> | ||||
|   Photo by{' '} | ||||
|   <a href="https://unsplash.com/@yucar?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     YUCAR FotoGrafik | ||||
|   </a>{' '} | ||||
|   on{' '} | ||||
|   <a href="https://unsplash.com/s/photos/sea?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     Unsplash | ||||
|   </a> | ||||
|   Photo by [YUCAR | ||||
|   FotoGrafik](https://unsplash.com/@yucar?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
|   on | ||||
|   [Unsplash](https://unsplash.com/s/photos/sea?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
| </p> | ||||
|  | ||||
| # Benefits | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| --- | ||||
| title: 'New features in v1' | ||||
| date: '2021-06-02' | ||||
| date: '2021-06-29' | ||||
| tags: ['next-js', 'tailwind', 'guide'] | ||||
| draft: false | ||||
| summary: 'An overview of the new features released in v1 - code block copy, multiple authors, frontmatter layout and more' | ||||
| @@ -12,15 +12,17 @@ layout: PostSimple | ||||
| A post on the new features introduced in v1.0. New features: | ||||
|  | ||||
| - [Theme colors](#theme-colors) | ||||
| - [Xdm MDX compiler](#xdm-mdx-compiler) | ||||
| - [Layouts](#layouts) | ||||
| - [Multiple authors](#multiple-authors) | ||||
| - [Copy button for code blocks](#copy-button-for-code-blocks) | ||||
| - [Line highlighting and line numbers](#line-highlighting-and-line-numbers) | ||||
|  | ||||
| ## Theme colors | ||||
|  | ||||
| You can easily modify the theme color by changing the primary attribute in the tailwind config file: | ||||
|  | ||||
| ```:tailwind.config.js | ||||
| ```js:tailwind.config.js | ||||
| theme: { | ||||
|     colors: { | ||||
|       primary: colors.teal, | ||||
| @@ -37,6 +39,37 @@ Tailwind includes great default color palettes that can be used for theming your | ||||
|  | ||||
| Migrating from v1? You can revert to the previous theme by setting `primary` to `colors.sky` (Tailwind 2.2.2 and above, otherwise `colors.lightBlue`) and changing gray to `colors.coolGray`. | ||||
|  | ||||
| ## Xdm MDX compiler | ||||
|  | ||||
| We switch the MDX bundler from [next-mdx-remote](https://github.com/hashicorp/next-mdx-remote) to [mdx-bundler](https://github.com/kentcdodds/mdx-bundler). | ||||
| This uses [xdm](https://github.com/wooorm/xdm) under the hood uses the latest micromark 3 and remark, rehype libraries. | ||||
|  | ||||
| **Warning:** If you were using custom remark or rehype libraries, please upgrade to micromark 3 compatible ones. If you are upgrading, please delete `node_modules` and `package-lock.json` to avoid having past dependencies related issues. | ||||
|  | ||||
| [xdm](https://github.com/wooorm/xdm) contains multiple improvements over [@mdx-js/mdx](https://github.com/mdx-js/mdx), the compiler used internally by next-mdx-remote, but there might be some breaking behaviour changes. | ||||
| Please check your markdown output to verify. | ||||
|  | ||||
| Some new possibilities include loading components directly in the mdx file using the import syntax and including js code which could be compiled at the build step. | ||||
|  | ||||
| For example, the following jsx snippet can be used directly in an MDX file to render the page title component: | ||||
|  | ||||
| ```js | ||||
| import PageTitle from './PageTitle.js' | ||||
|  | ||||
| ;<PageTitle> Using JSX components in MDX </PageTitle> | ||||
| ``` | ||||
|  | ||||
| import PageTitle from './PageTitle.js' | ||||
|  | ||||
| <PageTitle> Using JSX components in MDX </PageTitle> | ||||
|  | ||||
| The default configuration resolves all components relative to the `components` directory. | ||||
|  | ||||
| **Note**: | ||||
| Components which require external image loaders would require additional esbuild configuration. | ||||
| Components which are dependent on global application state on lifecycle like the Nextjs `Link` component would also not work with this setup as each mdx file is built indepedently. | ||||
| For such cases, it is better to use component substitution. | ||||
|  | ||||
| ## Layouts | ||||
|  | ||||
| You can map mdx blog content to layout components by configuring the frontmatter field. For example, this post is written with the new `PostSimple` layout! | ||||
| @@ -110,7 +143,7 @@ Information on authors is now split from `siteMetadata.json` and stored in its o | ||||
|  | ||||
| Here's how an author markdown file might looks like: | ||||
|  | ||||
| ```:default.md | ||||
| ```md:default.md | ||||
| --- | ||||
| name: Tails Azimuth | ||||
| avatar: /static/images/avatar.png | ||||
| @@ -153,3 +186,46 @@ A demo of a multiple author post is shown in the [Introducing Tailwind Nextjs St | ||||
|  | ||||
| Hover over a code block and you will notice a Github inspired copy button! You can modify `./components/Pre.js` to further customise it. | ||||
| The component is passed to `MDXComponents` and modifies all `<pre>` blocks. | ||||
|  | ||||
| ## Line highlighting and line numbers | ||||
|  | ||||
| Line highlighting and line numbers is now supported out of the box thanks to the new [rehype-prism-plus plugin](https://github.com/timlrx/rehype-prism-plus) | ||||
|  | ||||
| The following javascript code block: | ||||
|  | ||||
| ```` | ||||
| ```js {1, 3-4} showLineNumbers | ||||
| var num1, num2, sum | ||||
| num1 = prompt('Enter first number') | ||||
| num2 = prompt('Enter second number') | ||||
| sum = parseInt(num1) + parseInt(num2) // "+" means "add" | ||||
| alert('Sum = ' + sum) // "+" means combine into a string | ||||
| ``` | ||||
| ```` | ||||
|  | ||||
| will appear as: | ||||
|  | ||||
| ```js {1,3-4} showLineNumbers | ||||
| var num1, num2, sum | ||||
| num1 = prompt('Enter first number') | ||||
| num2 = prompt('Enter second number') | ||||
| sum = parseInt(num1) + parseInt(num2) // "+" means "add" | ||||
| alert('Sum = ' + sum) // "+" means combine into a string | ||||
| ``` | ||||
|  | ||||
| To modify the styles, change the following class selectors in the `tailwind.css` file: | ||||
|  | ||||
| ```css | ||||
| .code-line { | ||||
|   @apply pl-4 -mx-4 border-l-4 border-gray-800; | ||||
| } | ||||
|  | ||||
| .highlight-line { | ||||
|   @apply -mx-4 bg-gray-700 bg-opacity-50 border-l-4 border-primary-500; | ||||
| } | ||||
|  | ||||
| .line-number::before { | ||||
|   @apply pr-4 -ml-2 text-gray-400; | ||||
|   content: attr(line); | ||||
| } | ||||
| ``` | ||||
|   | ||||
| @@ -59,42 +59,26 @@ When MDX v2 is ready, one could potentially interleave markdown in jsx directly! | ||||
| ### Photo Credits | ||||
|  | ||||
| <div> | ||||
|   Maple photo by{' '} | ||||
|   <a href="https://unsplash.com/@i_am_g?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     Guillaume Jaillet | ||||
|   </a>{' '} | ||||
|   on{' '} | ||||
|   <a href="https://unsplash.com/s/photos/canada?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     Unsplash | ||||
|   </a> | ||||
|   Maple photo by [Guillaume | ||||
|   Jaillet](https://unsplash.com/@i_am_g?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
|   on | ||||
|   [Unsplash](https://unsplash.com/s/photos/canada?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
| </div> | ||||
| <div> | ||||
|   Mountains photo by{' '} | ||||
|   <a href="https://unsplash.com/@john_artifexfilms?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     John Lee | ||||
|   </a>{' '} | ||||
|   on{' '} | ||||
|   <a href="https://unsplash.com/s/photos/canada?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     Unsplash | ||||
|   </a> | ||||
|   Mountains photo by [John | ||||
|   Lee](https://unsplash.com/@john_artifexfilms?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
|   on | ||||
|   [Unsplash](https://unsplash.com/s/photos/canada?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
| </div> | ||||
| <div> | ||||
|   Lake photo by{' '} | ||||
|   <a href="https://unsplash.com/@tjholowaychuk?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     Tj Holowaychuk | ||||
|   </a>{' '} | ||||
|   on{' '} | ||||
|   <a href="https://unsplash.com/s/photos/canada?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     Unsplash | ||||
|   </a> | ||||
|   Lake photo by [Tj | ||||
|   Holowaychuk](https://unsplash.com/@tjholowaychuk?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
|   on | ||||
|   [Unsplash](https://unsplash.com/s/photos/canada?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
| </div> | ||||
| <div> | ||||
|   Toronto photo by{' '} | ||||
|   <a href="https://unsplash.com/@matthewhenry?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     Matthew Henry | ||||
|   </a>{' '} | ||||
|   on{' '} | ||||
|   <a href="https://unsplash.com/s/photos/canada?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"> | ||||
|     Unsplash | ||||
|   </a> | ||||
|   Toronto photo by [Matthew | ||||
|   Henry](https://unsplash.com/@matthewhenry?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
|   on | ||||
|   [Unsplash](https://unsplash.com/s/photos/canada?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) | ||||
| </div> | ||||
|   | ||||
| @@ -55,7 +55,7 @@ export default function PostLayout({ frontMatter, authorDetails, next, prev, chi | ||||
|                     <li className="flex items-center space-x-2" key={author.name}> | ||||
|                       {author.avatar && ( | ||||
|                         <Image | ||||
|                           src={siteMetadata.image} | ||||
|                           src={author.avatar} | ||||
|                           width="38px" | ||||
|                           height="38px" | ||||
|                           alt="avatar" | ||||
|   | ||||
| @@ -15,13 +15,14 @@ module.exports = (options) => (tree) => { | ||||
|         const dimensions = sizeOf(`${process.cwd()}/public${imageNode.url}`) | ||||
|  | ||||
|         // Convert original node to next/image | ||||
|         imageNode.type = 'jsx' | ||||
|         imageNode.value = `<Image | ||||
|           alt={\`${imageNode.alt}\`}  | ||||
|           src={\`${imageNode.url}\`} | ||||
|           width={${dimensions.width}} | ||||
|           height={${dimensions.height}} | ||||
|       />` | ||||
|         ;(imageNode.type = 'mdxJsxFlowElement'), | ||||
|           (imageNode.name = 'Image'), | ||||
|           (imageNode.attributes = [ | ||||
|             { type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt }, | ||||
|             { type: 'mdxJsxAttribute', name: 'src', value: imageNode.url }, | ||||
|             { type: 'mdxJsxAttribute', name: 'width', value: dimensions.width }, | ||||
|             { type: 'mdxJsxAttribute', name: 'height', value: dimensions.height }, | ||||
|           ]) | ||||
|  | ||||
|         // Change node type from p to div to avoid nesting error | ||||
|         node.type = 'div' | ||||
|   | ||||
							
								
								
									
										64
									
								
								lib/mdx.js
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								lib/mdx.js
									
									
									
									
									
								
							| @@ -1,10 +1,10 @@ | ||||
| import { MDXComponents } from '@/components/MDXComponents' | ||||
| import { bundleMDX } from 'mdx-bundler' | ||||
| import fs from 'fs' | ||||
| import matter from 'gray-matter' | ||||
| import { serialize } from 'next-mdx-remote/serialize' | ||||
| import path from 'path' | ||||
| import readingTime from 'reading-time' | ||||
| import visit from 'unist-util-visit' | ||||
| import codeTitles from './remark-code-title' | ||||
| import imgToJsx from './img-to-jsx' | ||||
| import getAllFilesRecursively from './utils/files' | ||||
|  | ||||
| @@ -48,21 +48,45 @@ export async function getFileBySlug(type, slug) { | ||||
|     ? fs.readFileSync(mdxPath, 'utf8') | ||||
|     : fs.readFileSync(mdPath, 'utf8') | ||||
|  | ||||
|   const { data, content } = matter(source) | ||||
|   const mdxSource = await serialize(content, { | ||||
|     components: MDXComponents, | ||||
|     mdxOptions: { | ||||
|       remarkPlugins: [ | ||||
|   // https://github.com/kentcdodds/mdx-bundler#nextjs-esbuild-enoent | ||||
|   if (process.platform === 'win32') { | ||||
|     process.env.ESBUILD_BINARY_PATH = path.join( | ||||
|       process.cwd(), | ||||
|       'node_modules', | ||||
|       'esbuild', | ||||
|       'esbuild.exe' | ||||
|     ) | ||||
|   } else { | ||||
|     process.env.ESBUILD_BINARY_PATH = path.join( | ||||
|       process.cwd(), | ||||
|       'node_modules', | ||||
|       'esbuild', | ||||
|       'bin', | ||||
|       'esbuild' | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   const { frontmatter, code } = await bundleMDX(source, { | ||||
|     // mdx imports can be automatically source from the components directory | ||||
|     cwd: path.join(process.cwd(), 'components'), | ||||
|     xdmOptions(options) { | ||||
|       // this is the recommended way to add custom remark/rehype plugins: | ||||
|       // The syntax might look weird, but it protects you in case we add/remove | ||||
|       // plugins in the future. | ||||
|       options.remarkPlugins = [ | ||||
|         ...(options.remarkPlugins ?? []), | ||||
|         require('remark-slug'), | ||||
|         require('remark-autolink-headings'), | ||||
|         require('remark-code-titles'), | ||||
|         require('remark-gfm'), | ||||
|         codeTitles, | ||||
|         [require('remark-footnotes'), { inlineNotes: true }], | ||||
|         require('remark-math'), | ||||
|         imgToJsx, | ||||
|       ], | ||||
|       inlineNotes: true, | ||||
|       rehypePlugins: [ | ||||
|       ] | ||||
|       options.rehypePlugins = [ | ||||
|         ...(options.rehypePlugins ?? []), | ||||
|         require('rehype-katex'), | ||||
|         require('@mapbox/rehype-prism'), | ||||
|         [require('rehype-prism-plus'), { ignoreMissing: true }], | ||||
|         () => { | ||||
|           return (tree) => { | ||||
|             visit(tree, 'element', (node, index, parent) => { | ||||
| @@ -73,17 +97,25 @@ export async function getFileBySlug(type, slug) { | ||||
|             }) | ||||
|           } | ||||
|         }, | ||||
|       ], | ||||
|       ] | ||||
|       return options | ||||
|     }, | ||||
|     esbuildOptions: (options) => { | ||||
|       options.loader = { | ||||
|         ...options.loader, | ||||
|         '.js': 'jsx', | ||||
|       } | ||||
|       return options | ||||
|     }, | ||||
|   }) | ||||
|  | ||||
|   return { | ||||
|     mdxSource, | ||||
|     mdxSource: code, | ||||
|     frontMatter: { | ||||
|       readingTime: readingTime(content), | ||||
|       readingTime: readingTime(code), | ||||
|       slug: slug || null, | ||||
|       fileName: fs.existsSync(mdxPath) ? `${slug}.mdx` : `${slug}.md`, | ||||
|       ...data, | ||||
|       ...frontmatter, | ||||
|     }, | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										32
									
								
								lib/remark-code-title.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/remark-code-title.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| import visit from 'unist-util-visit' | ||||
|  | ||||
| module.exports = function (options) { | ||||
|   return (tree) => | ||||
|     visit(tree, 'code', (node, index) => { | ||||
|       const nodeLang = node.lang || '' | ||||
|       let language = '' | ||||
|       let title = '' | ||||
|  | ||||
|       if (nodeLang.includes(':')) { | ||||
|         language = nodeLang.slice(0, nodeLang.search(':')) | ||||
|         title = nodeLang.slice(nodeLang.search(':') + 1, nodeLang.length) | ||||
|       } | ||||
|  | ||||
|       if (!title) { | ||||
|         return | ||||
|       } | ||||
|  | ||||
|       const className = 'remark-code-title' | ||||
|  | ||||
|       const titleNode = { | ||||
|         type: 'mdxJsxFlowElement', | ||||
|         name: 'div', | ||||
|         attributes: [{ type: 'mdxJsxAttribute', name: 'className', value: className }], | ||||
|         children: [{ type: 'text', value: title }], | ||||
|         data: { _xdmExplicitJsx: true }, | ||||
|       } | ||||
|  | ||||
|       tree.children.splice(index, 0, titleNode) | ||||
|       node.lang = language | ||||
|     }) | ||||
| } | ||||
							
								
								
									
										2204
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2204
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
									
									
									
									
								
							| @@ -12,25 +12,25 @@ | ||||
|     "prepare": "husky install" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@mapbox/rehype-prism": "^0.6.0", | ||||
|     "@tailwindcss/forms": "^0.3.2", | ||||
|     "@tailwindcss/typography": "^0.4.0", | ||||
|     "autoprefixer": "^10.2.5", | ||||
|     "gray-matter": "^4.0.2", | ||||
|     "image-size": "1.0.0", | ||||
|     "mdx-bundler": "^4.1.0", | ||||
|     "next": "11.0.1", | ||||
|     "next-mdx-remote": "^3.0.1", | ||||
|     "next-themes": "^0.0.14", | ||||
|     "postcss": "^8.3.5", | ||||
|     "preact": "^10.5.13", | ||||
|     "react": "17.0.2", | ||||
|     "react-dom": "17.0.2", | ||||
|     "reading-time": "1.3.0", | ||||
|     "rehype-katex": "^4.0.0", | ||||
|     "rehype-katex": "^5.0.0", | ||||
|     "rehype-prism-plus": "0.0.1", | ||||
|     "remark-autolink-headings": "6.0.1", | ||||
|     "remark-code-titles": "0.1.2", | ||||
|     "remark-footnotes": "^3.0.0", | ||||
|     "remark-math": "^3.0.1", | ||||
|     "remark-gfm": "^1.0.0", | ||||
|     "remark-math": "^4.0.0", | ||||
|     "remark-slug": "6.0.0", | ||||
|     "tailwindcss": "^2.2.2" | ||||
|   }, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import Image from 'next/image' | ||||
| import siteMetadata from '@/data/siteMetadata' | ||||
| import projectsData from '@/data/projectsData' | ||||
| import Image from '@/components/Image' | ||||
| import Link from '@/components/Link' | ||||
| import Card from '@/components/Card' | ||||
| import { PageSeo } from '@/components/SEO' | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								public/static/images/sparrowhawk-avatar.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/static/images/sparrowhawk-avatar.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 15 KiB | 
		Reference in New Issue
	
	Block a user