first commit

master
joker 3 years ago
commit 3c7fed5712
  1. 3
      .eslintrc.json
  2. 36
      .gitignore
  3. 34
      README.md
  4. 45
      components/Head.tsx
  5. 44
      components/Layout.tsx
  6. 104
      components/Navigation.tsx
  7. 102
      components/ThemeSwitch.tsx
  8. 1
      components/index.ts
  9. 45
      lib/api.ts
  10. 7
      next.config.js
  11. 11947
      package-lock.json
  12. 40
      package.json
  13. 8
      pages/_app.tsx
  14. 13
      pages/api/hello.ts
  15. 49
      pages/index.tsx
  16. 95
      pages/posts/[slug].tsx
  17. 8
      postcss.config.js
  18. 22
      posts/python_1_1.mdx
  19. 265
      posts/python_functions.mdx
  20. BIN
      public/favicon.ico
  21. 4
      public/vercel.svg
  22. 119
      styles/globals.css
  23. 75
      tailwind.config.js
  24. 20
      tsconfig.json
  25. 9
      types/layout.ts
  26. 7
      types/post.ts
  27. 11
      utils/mdxUtils.ts

@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

36
.gitignore vendored

@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

@ -0,0 +1,34 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

@ -0,0 +1,45 @@
import NextHead from 'next/head';
import { useRouter } from 'next/router';
import React from 'react';
import { MetaProps } from '../types/layout';
export type WithYandexMetrikaProps = {
children: React.ReactNode;
}
export const WEBSITE_HOST_URL = 'https://robotop.krasnikov.pro';
const Head = ({ customMeta }: { customMeta?: MetaProps }): JSX.Element => {
const router = useRouter();
const meta: MetaProps = {
title: 'РоботТоп - робототехнический фестиваль',
description:
'РоботТОП – это робототехнические соревнования, в которых могут принять участие молодые любители робототехники, объединившись в команды.',
image: `${WEBSITE_HOST_URL}/images/site-preview.png`,
type: 'website',
...customMeta,
};
return (
<NextHead>
<title>{meta.title}</title>
<meta content={meta.description} name="РоботТОП – это робототехнические соревнования, в которых могут принять участие молодые любители робототехники, объединившись в команды." />
<meta property="og:url" content={`${WEBSITE_HOST_URL}${router.asPath}`} />
<link rel="canonical" href={`${WEBSITE_HOST_URL}${router.asPath}`} />
<meta property="og:type" content={meta.type} />
<meta property="og:site_name" content="РоботТоп - робототехнический фестиваль" />
<meta property="og:description" content={meta.description} />
<meta property="og:title" content={meta.title} />
<meta property="og:image" content={meta.image} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={meta.title} />
<meta name="twitter:description" content={meta.description} />
<meta name="twitter:image" content={meta.image} />
{meta.date && (
<meta property="article:published_time" content={meta.date} />
)}
</NextHead>
);
};
export default Head;

@ -0,0 +1,44 @@
import React from 'react';
import { MetaProps } from '../types/layout';
import Head from './Head';
import Navigation from './Navigation';
import ThemeSwitch from './ThemeSwitch';
type LayoutProps = {
children: React.ReactNode;
customMeta?: MetaProps;
};
export const WEBSITE_HOST_URL = 'https:// krasnikov.pro/';
export const Layout = ({ children, customMeta }: LayoutProps): JSX.Element => {
return (
<>
<Head customMeta={customMeta} />
<header>
<div className="max-w-5xl px-8 mx-auto max-w">
<div className="flex items-center justify-between py-6">
<Navigation />
<ThemeSwitch />
</div>
</div>
</header>
<main>
<div className="max-w-5xl px-8 py-4 mx-auto max-w">
{children}
</div>
</main>
<footer className="py-8">
<div className="max-w-5xl px-8 mx-auto max-w">
Разработано {' '}
<a
className="text-gray-900 dark:text-white"
href="https://krasnikov.pro" target='_blank' rel="noreferrer"
>
Krasnikov.pro - {(new Date()).getFullYear()} год
</a>
</div>
</footer>
</>
);
};

@ -0,0 +1,104 @@
import Link from 'next/link';
import React, { useState } from 'react';
import { MenuIcon, XIcon } from '@heroicons/react/outline'
import { Transition } from "@headlessui/react";
import { useRouter } from 'next/router'
const navigation = [
{ name: 'Главная', href: '/', as: false },
{ name: 'Робототехника', href: '/posts/[slug]', as:'regulations'},
{ name: 'Программирование', href: '/registration', as: false }
]
function classNames(...classes: string[]) {
return classes.filter(Boolean).join(' ')
}
const Navigation = (): JSX.Element => {
const [isOpen, setIsOpen] = useState(false);
const router = useRouter();
return (
<nav className="">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
<div className="flex items-center">
<div className="hidden md:block">
<div className="ml-10 flex items-baseline space-x-4">
{navigation.map((item) => (
<Link as={ item.as ? '/posts/'+item.as : ''} href={item.href} key={item.name}>
<a
className={classNames(
item.as == router.query.slug && router.query.slug !== 'undefined'?
'bg-gray-900 text-white' :
item.href == router.pathname && item.as === false ?
'bg-gray-900 text-white' :
'text-gray-900 hover:bg-gray-700 hover:text-white',
'px-3 py-2 rounded-md text-sm font-medium'
)}
aria-current={item.href == router.pathname || item.as == router.query.slug ? 'page' : 'false'}
>
{item.name}
</a>
</Link>
))}
</div>
</div>
</div>
<div className="-mr-2 flex md:hidden">
<button
onClick={() => setIsOpen(!isOpen)}
type="button"
aria-controls="mobile-menu"
aria-expanded="false"
>
<span className="sr-only">Открыть главное меню</span>
{!isOpen ? (
<MenuIcon className="block h-6 w-6" aria-hidden="false" />
) : (
<XIcon className="block h-6 w-6" aria-hidden="true" />
)}
</button>
</div>
</div>
</div>
<Transition
show={isOpen}
enter="transition ease-out duration-100 transform"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="transition ease-in duration-75 transform"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
className="absolute bg-gray-100 z-50"
>
{(ref) => (
<div className="md:hidden" id="mobile-menu">
<div ref={ref} className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
{navigation.map((item) => (
<Link as={'/posts/'+item.as} href={item.href} key={item.name}>
<a
className={classNames(
item.as == router.query.slug && router.query.slug !== 'undefined'?
'bg-gray-900 text-white' :
item.href == router.pathname && item.as === 'true' ?
'bg-gray-900 text-white' :
'text-gray-900 hover:bg-gray-900 hover:text-white',
'block px-3 py-2 rounded-md text-base font-medium'
)}
aria-current={item.href ? 'page' : undefined}
>
{item.name}
</a>
</Link>
))}
</div>
</div>
)}
</Transition>
</nav>
);
};
export default Navigation;

@ -0,0 +1,102 @@
import { useTheme } from 'next-themes';
import React from 'react';
const ThemeSwitch = (): JSX.Element => {
const [mounted, setMounted] = React.useState(false);
const { theme, setTheme } = useTheme();
// After mounting, we have access to the theme
React.useEffect(() => setMounted(true), []);
if (!mounted) {
return null;
}
const isDark = theme === 'dark';
const color = isDark ? '#fff' : '#000';
const maskColor = isDark ? '#000' : '#fff';
return (
<button
className="theme-button"
type="button"
aria-label="Toggle Dark Mode"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
>
<div className="moon-or-sun" />
<div className="moon-mask" />
<style jsx>{`
.theme-button {
opacity: 0.5;
position: relative;
border-radius: 5px;
width: 42px;
height: 42px;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.3s ease;
}
.theme-button:hover {
opacity: 1;
}
.moon-or-sun {
position: relative;
width: 20px;
height: 20px;
border-radius: 50%;
border: ${isDark ? '4px' : '2px'} solid;
border-color: ${color};
background: ${color};
transform: scale(${isDark ? 0.5 : 1});
transition: all 0.45s ease;
overflow: ${isDark ? 'visible' : 'hidden'};
}
.moon-or-sun::before {
content: '';
position: absolute;
right: -9px;
top: -9px;
height: 20px;
width: 20px;
border: 2px solid;
border-color: ${color};
border-radius: 50%;
transform: translate(${isDark ? '14px, -14px' : '0, 0'});
opacity: ${isDark ? 0 : 1};
transition: transform 0.45s ease;
}
.moon-or-sun::after {
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
margin: -4px 0 0 -4px;
position: absolute;
top: 50%;
left: 50%;
box-shadow: 0 -23px 0 ${color}, 0 23px 0 ${color}, 23px 0 0 ${color},
-23px 0 0 ${color}, 15px 15px 0 ${color}, -15px 15px 0 ${color},
15px -15px 0 ${color}, -15px -15px 0 ${color};
transform: scale(${isDark ? 1 : 0});
transition: all 0.35s ease;
}
.moon-mask {
position: absolute;
right: 4px;
top: 4px;
height: 20px;
width: 20px;
border-radius: 50%;
border: 0;
background: ${maskColor};
transform: translate(${isDark ? '4px, -4px' : '0, 0'});
opacity: ${isDark ? 0 : 1};
transition: transform 0.45s ease;
}
`}</style>
</button>
);
};
export default ThemeSwitch;

@ -0,0 +1 @@
export * from './Layout';

@ -0,0 +1,45 @@
import fs from 'fs';
import matter from 'gray-matter';
import { join } from 'path';
import { POSTS_PATH } from '../utils/mdxUtils';
export function getPostSlugs(): string[] {
return fs.readdirSync(POSTS_PATH);
}
type PostItems = {
[key: string]: string;
};
export function getPostBySlug(slug: string, fields: string[] = []): PostItems {
const realSlug = slug.replace(/\.mdx$/, '');
const fullPath = join(POSTS_PATH, `${realSlug}.mdx`);
const fileContents = fs.readFileSync(fullPath, 'utf8');
const { data, content } = matter(fileContents);
const items: PostItems = {};
// Ensure only the minimal needed data is exposed
fields.forEach((field) => {
if (field === 'slug') {
items[field] = realSlug;
}
if (field === 'content') {
items[field] = content;
}
if (data[field]) {
items[field] = data[field];
}
});
return items;
}
export function getAllPosts(fields: string[] = []): PostItems[] {
const slugs = getPostSlugs();
const posts = slugs
.map((slug) => getPostBySlug(slug, fields))
// sort posts by date in descending order
.sort((post1, post2) => (post1.date > post2.date ? -1 : 1));
return posts;
}

@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
}
module.exports = nextConfig

11947
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,40 @@
{
"name": "krasnikov_blog",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@code-hike/mdx": "^0.7.4",
"@headlessui/react": "^1.7.3",
"@heroicons/react": "^1.0.6",
"@mdx-js/loader": "^2.1.5",
"@next/mdx": "^12.3.1",
"@tailwindcss/typography": "^0.5.7",
"date-fns": "^2.29.3",
"gray-matter": "^4.0.3",
"next": "12.3.1",
"next-mdx-remote": "^4.1.0",
"next-themes": "^0.2.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.0.1",
"remark-code-titles": "^0.1.2"
},
"devDependencies": {
"@types/node": "18.11.3",
"@types/react": "18.0.21",
"@types/react-dom": "18.0.6",
"autoprefixer": "^10.4.12",
"eslint": "8.26.0",
"eslint-config-next": "12.3.1",
"postcss": "^8.4.18",
"tailwindcss": "^3.2.1",
"typescript": "4.8.4"
}
}

@ -0,0 +1,8 @@
import '../styles/globals.css'
import type { AppProps } from 'next/app'
function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
export default MyApp

@ -0,0 +1,13 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

@ -0,0 +1,49 @@
import type { GetStaticProps, NextPage } from 'next'
import { format, parseISO } from 'date-fns';
import Link from 'next/link';
import { Layout } from '../components/index'
import { PostType } from '../types/post';
import { getAllPosts } from '../lib/api';
type IndexProps = {
posts: PostType[];
};
export const Home = ({ posts }: IndexProps): JSX.Element => {
return (
<Layout>
<h1>Красников Павел</h1>
<p>Робототехника, программирование</p>
{posts.map((post) => (
<article key={post.slug} className="mt-12">
<p className="mb-1 text-sm text-gray-500 dark:text-gray-400">
{format(parseISO(post.date), 'MMMM dd, yyyy')}
</p>
<h1 className="mb-2 text-xl">
<Link as={`/posts/${post.slug}`} href={`/posts/[slug]`}>
<a className="text-gray-900 dark:hover:text-blue-400">
{post.title}
</a>
</Link>
</h1>
<p className="mb-3">{post.description}</p>
<p>
<Link as={`/posts/${post.slug}`} href={`/posts/[slug]`}>
<a>Подробнее...</a>
</Link>
</p>
</article>
))}
</Layout>
)
}
export const getStaticProps: GetStaticProps = async () => {
const posts = getAllPosts(['date', 'description', 'slug', 'title']);
return {
props: { posts },
};
};
export default Home

@ -0,0 +1,95 @@
import { format, parseISO } from 'date-fns';
import fs from 'fs';
import matter from 'gray-matter';
import { GetStaticPaths, GetStaticProps } from 'next';
import { serialize } from 'next-mdx-remote/serialize';
import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';
import path from 'path';
import React from 'react';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import rehypeSlug from 'rehype-slug';
import { Layout } from '../../components/index';
import { MetaProps } from '../../types/layout';
import { PostType } from '../../types/post';
import { postFilePaths, POSTS_PATH } from '../../utils/mdxUtils';
// Custom components/renderers to pass to MDX.
// Since the MDX files aren't loaded by webpack, they have no knowledge of how
// to handle import statements. Instead, you must include components in scope
// here.
const components = {
Head,
Image,
Link,
};
type PostPageProps = {
source: MDXRemoteSerializeResult;
frontMatter: PostType;
};
const PostPage = ({ source, frontMatter }: PostPageProps): JSX.Element => {
const customMeta: MetaProps = {
title: `${frontMatter.title} - RoboTop`,
description: frontMatter.description,
image: `${frontMatter.image}`,
date: frontMatter.date,
type: 'article',
};
return (
<Layout customMeta={customMeta}>
<article className="max-w">
<h1 className="mb-3 text-gray-900 dark:text-white">
{frontMatter.title}
</h1>
<p className="mb-10 text-sm text-gray-500 dark:text-gray-400">
{format(parseISO(frontMatter.date), 'MMMM dd, yyyy')}
</p>
<div className="prose dark:prose-dark">
<MDXRemote {...source} components={components} />
</div>
</article>
</Layout>
);
};
export const getStaticProps: GetStaticProps = async ({ params }) => {
const postFilePath = path.join(POSTS_PATH, `${params.slug}.mdx`);
const source = fs.readFileSync(postFilePath);
const { content, data } = matter(source);
const mdxSource = await serialize(content, {
// Optionally pass remark/rehype plugins
mdxOptions: {
remarkPlugins: [require('remark-code-titles')],
rehypePlugins: [rehypeSlug, rehypeAutolinkHeadings],
},
scope: data,
});
return {
props: {
source: mdxSource,
frontMatter: data,
},
};
};
export const getStaticPaths: GetStaticPaths = async () => {
const paths = postFilePaths
// Remove file extensions for page paths
.map((path) => path.replace(/\.mdx?$/, ''))
// Map the path into the static paths object required by Next.js
.map((slug) => ({ params: { slug } }));
return {
paths,
fallback: false,
};
};
export default PostPage;

@ -0,0 +1,8 @@
// If you want to use other PostCSS plugins, see the following:
// https://tailwindcss.com/docs/using-with-preprocessors
module.exports = {
plugins: {
tailwindcss: { config: './tailwind.config.js' },
autoprefixer: {},
},
};

@ -0,0 +1,22 @@
---
title: Python. Первая программа, арифметические выражения - Задание 1
description: Решение задания 1
date: '2021-10-23'
---
## I Python. Первая программа, арифметические выражения - Задание 1
Разработчики языка Python придерживаются определённой философии программирования, называемой «The Zen of Python» («Дзен Питона»). Её текст выдаётся интерпретатором Python по команде import this.
Напишите программу, состоящую из одной строки:
```python
import this
```
Какое первое слово в последней строке выведет эта программа?
### Решение
```python
import this
```
### Ответ:
Namespaces

@ -0,0 +1,265 @@
---
title: Python. Функции
description: Интерпретатор Python имеет ряд встроенных функций и типов, которые всегда доступны.
date: '2021-10-24'
---
# abs(x)
Возвращает абсолютное значение числа. Аргументом может быть целое число, число с плавающей запятой или реализация объекта __abs__().
Если аргумент является комплексным числом, возвращается его величина.
## Пример
```python
print(abs(-4))
# 4
```
***
# bin(x)
Преобразование целого числа в двоичную строку с префиксом “0b”.
Результатом является допустимое выражение Python.
Если X не является intобъектом Python, он должен определить __index__() метод, который возвращает целое число. Некоторые примеры:
```python
print(bin(7))
# 0b111
```
***
# chr(i)
Возвращает строку, представляющую символ, кодовой точкой которого в Юникоде является целое число i.
Например, chr(97)возвращает строку 'a', в то время chr(8364)как возвращает строку '€'. Это обратное ord().
```python
print(chr(97))
# a
```
***
# ord(i)
Учитывая строку, представляющую один символ Юникода, верните целое число, представляющее кодовую точку Юникода этого символа.
Например, ord('a') возвращает целое 97 число и ord('€') (знак евро) возвращает 8364. Это обратное chr().
```python
print(ord('a'))
# 97
```
***
# dir(i)
Без аргументов возвращает список имен в текущей локальной области. С помощью аргумента попытайтесь вернуть список допустимых атрибутов для этого объекта.
```python
class Shape:
def __dir__(self):
return ['area', 'perimeter', 'location']
s = Shape()
print(dir(s))
# ['area', 'location', 'perimeter']
```
***
# divmod(i, j)
Функция divmod() возвращает кортеж, содержащий частное и остаток. Не поддерживает комплексные числа.
Со смешанными типами операндов применяются правила для двоичных арифметических операторов.
Для целых результат аналогичен (a // b, a % b).
```python
print(divmod(5, 3))
# (1, 2 )
```
***
# eval()
Аргументами являются строка и необязательные глобальные и локальные переменные. Если предусмотрено, глобальные должен быть словарь.
Если предусмотрено, локальные может быть любым объектом сопоставления.
```python
x = 1
print(eval('x + 1'))
# 2
```
***
# float()
Возвращает число с плавающей запятой, построенное из числа или строки x.
```python
print(float('+1.23'))
# 1.23
print(float('-Infinity'))
# -inf
```
***
# help()
Вызовите встроенную справочную систему.
```python
print(help())
# Welcome to Python 3.10's help utility!
print(help('abs'))
# abs(x, /)
# Return the absolute value of the argument.
```
***
# hex(x)
Преобразуйте целое число в строчную шестнадцатеричную строку с префиксом “0x”.
Если x не является intобъектом Python, он должен определить __index__()метод, который возвращает целое число. Некоторые примеры:
```python
print(hex(255))
# 0xff
```
***
# len(x)
Возвращает длину (количество элементов) объекта.
Аргументом может быть последовательность (например, строка, байты, кортеж, список или диапазон) или коллекция (например, словарь, набор или замороженный набор).
```python
x = [1,2,3,4,5,6]
print(len(x))
# 6
```
***
# map(i, j)
map() перебирает элементы входного итерируемого (или итерируемых) и возвращает итератор,
который является результатом применения функции преобразования к каждому элементу в исходном входном итерируемом.
```python
def plus(a, b, c):
return a + b +c
# функция 'plus' применяется к элементам
# из всех последовательностей параллельно
x = map(plus, [1, 2], [3, 4], [5, 6])
print(list(x))
# [9, 12]
```
***
# max(x)
Возвращает самый большой элемент в итерации или самый большой из двух или более аргументов.
```python
x = [1, 3, 5, 1, 2]
print(max(x))
# 5
```
***
# min(x)
Возвращает наименьший элемент в итерируемом или наименьший из двух или более аргументов.
```python
x = [1, 3, 5, 1, 2]
print(min(x))
# 1
```
***
# open()
Открыть файл и возвращает соответствующий файловый объект. Если файл не может быть открыт, OSError возникает проблема. См. Чтение и запись файлов.
```python
f = open('workfile', 'r', encoding="utf-8")
Варианты использования режимов:
* 'r' - Открывает файл только для чтения. Указатель файла помещается в начале файла. Это режим "по умолчанию".
* 'rb' - Открывает файл в бинарном режиме только для чтения. Указатель файла помещается в начале файла. Это режим "по умолчанию".
* 'r+' - Открывает файл для чтения и записи. Указатель файла помещается в начало файла.
* 'rb+' - Открывает файл в бинарном режиме для чтения и записи. Указатель файла помещается в начале файла. Это режим "по умолчанию".
* 'w' - Открывает файл только для записи. Перезаписывает файл, если файл существует. Если файл не существует, создает новый файл для записи.
* 'wb' - Открывает файл в бинарном режиме только для записи. Перезаписывает файл, если файл существует. Если файл не существует, создает новый файл для записи.
* 'w+' - Открывает файл для записи и чтения. Перезаписывает существующий файл, если файл существует. Если файл не существует, создается новый файл для чтения и записи.
* 'wb+' - Открывает файл в бинарном режиме для записи и чтения. Перезаписывает существующий файл, если файл существует. Если файл не существует, создается новый файл для чтения и записи.
* 'a' - Открывает файл для добавления. Указатель файла находится в конце файла, если файл существует. То есть файл находится в режиме добавления. Если файл не существует, он создает новый файл для записи.
* 'ab' - Открывает файл в бинарном режиме для добавления. Указатель файла находится в конце файла, если файл существует. То есть файл находится в режиме добавления. Если файл не существует, он создает новый файл для записи.
* 'a+' - Открывает файл для добавления и чтения. Указатель файла находится в конце файла, если файл существует. Файл открывается в режиме добавления. Если файл не существует, он создает новый файл для чтения и записи.
* 'ab+' - Открывает файл в бинарном режиме для добавления и чтения. Указатель файла находится в конце файла, если файл существует. Файл открывается в режиме добавления. Если файл не существует, он создает новый файл для чтения и записи.
print(f.read())
# 1
```
***
# sorted()
Функция sorted() возвращает новый отсортированный список итерируемого объекта (списка, словаря, кортежа). По умолчанию она сортирует его по возрастанию.
```python
x = [1, 3, 5, 1, 2]
print(sorted(x))
# [1, 1, 2, 3, 5]
```
***
# sum()
Суммирует начало и элементы итерации слева направо и возвращает итоговое значение.
Элементы итерации обычно представляют собой числа, а начальное значение не может быть строкой.
```python
x = [1, 3, 5, 1, 2]
print(sum(x))
# 12
```
***
# zip()
Выполняйте параллельную итерацию по нескольким итерациям, создавая кортежи с элементом из каждого.
```python
for item in zip([1,2,3], ['sugar', 'spice', 'everything nice']):
print(item)
# (1, 'sugar')
# (2, 'spice')
# (3, 'everything nice')
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,119 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
h1 {
@apply mb-6 text-3xl font-semibold;
}
h2 {
@apply text-2xl font-semibold;
}
p {
@apply mb-4;
}
a {
@apply text-blue-500 hover:text-blue-400 dark:text-blue-400 dark:hover:text-blue-300;
}
}
/* Post styles */
.prose {
max-width: 100vh;
}
.prose pre {
@apply bg-gray-50 border border-gray-200 dark:border-gray-700 dark:bg-gray-900;
}
.prose code {
@apply text-gray-800 dark:text-gray-200 px-1 py-0.5 border border-gray-100 dark:border-gray-800 rounded-md bg-gray-100 dark:bg-gray-900;
}
.prose img {
/* Don't apply styles to next/image */
@apply m-0;
}
/* Prism Styles */
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
@apply text-gray-700 dark:text-gray-300;
}
.token.punctuation {
@apply text-gray-700 dark:text-gray-300;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
@apply text-green-500;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
@apply text-purple-500;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
@apply text-yellow-500;
}
.token.atrule,
.token.attr-value,
.token.keyword {
@apply text-blue-500;
}
.token.function,
.token.class-name {
@apply text-pink-500;
}
.token.regex,
.token.important,
.token.variable {
@apply text-yellow-500;
}
code[class*='language-'],
pre[class*='language-'] {
@apply text-gray-800 dark:text-gray-50;
}
pre::-webkit-scrollbar {
display: none;
}
pre {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
/* Remark Styles */
.remark-code-title {
@apply text-gray-800 dark:text-gray-200 px-5 py-3 border border-b-0 border-gray-200 dark:border-gray-700 rounded-t bg-gray-200 dark:bg-gray-800 text-sm font-mono font-bold;
}
.remark-code-title + pre {
@apply mt-0 rounded-t-none;
}
.mdx-marker {
@apply block -mx-4 px-4 bg-gray-100 dark:bg-gray-800 border-l-4 border-blue-500;
}

@ -0,0 +1,75 @@
const { spacing } = require('tailwindcss/defaultTheme');
module.exports = {
mode: 'jit',
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
darkMode: 'class', // or 'media' or 'class'
theme: {
extend: {
typography: (theme) => ({
DEFAULT: {
css: {
color: theme('colors.gray.700'),
a: {
color: theme('colors.blue.500'),
'&:hover': {
color: theme('colors.blue.700'),
},
code: { color: theme('colors.blue.400') },
},
'h2,h3,h4': {
'scroll-margin-top': spacing[32],
},
code: { color: theme('colors.pink.500') },
'blockquote p:first-of-type::before': false,
'blockquote p:last-of-type::after': false,
},
},
dark: {
css: {
color: theme('colors.gray.300'),
a: {
color: theme('colors.blue.400'),
'&:hover': {
color: theme('colors.blue.600'),
},
code: { color: theme('colors.blue.400') },
},
blockquote: {
borderLeftColor: theme('colors.gray.800'),
color: theme('colors.gray.300'),
},
'h2,h3,h4': {
color: theme('colors.gray.100'),
'scroll-margin-top': spacing[32],
},
hr: { borderColor: theme('colors.gray.800') },
ol: {
li: {
'&:before': { color: theme('colors.gray.500') },
},
},
ul: {
li: {
'&:before': { backgroundColor: theme('colors.gray.500') },
},
},
strong: { color: theme('colors.gray.300') },
thead: {
color: theme('colors.gray.100'),
},
tbody: {
tr: {
borderBottomColor: theme('colors.gray.700'),
},
},
},
},
}),
},
},
variants: {
typography: ['dark'],
},
plugins: [require('@tailwindcss/typography')],
};

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

@ -0,0 +1,9 @@
import { PostType } from './post';
export interface MetaProps
extends Pick<PostType, 'date' | 'description' | 'image' | 'title'> {
/**
* For the meta tag `og:type`
*/
type?: string;
}

@ -0,0 +1,7 @@
export type PostType = {
date?: string;
description?: string;
image?: string;
slug: string;
title: string;
};

@ -0,0 +1,11 @@
import fs from 'fs';
import path from 'path';
// POSTS_PATH is useful when you want to get the path to a specific file
export const POSTS_PATH = path.join(process.cwd(), 'posts');
// postFilePaths is the list of all mdx files inside the POSTS_PATH directory
export const postFilePaths = fs
.readdirSync(POSTS_PATH)
// Only include md(x) files
.filter((path) => /\.mdx?$/.test(path));
Loading…
Cancel
Save