070500
23
.github/workflows/stale.yaml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Close inactive issues
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
close-issues:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
days-before-issue-stale: 10
|
||||
days-before-issue-close: 10
|
||||
stale-issue-label: "stale"
|
||||
stale-issue-message: "This issue is stale because it has been open for 10 days with no activity."
|
||||
close-issue-message: "This issue was closed because it has been inactive for 10 days since being marked as stale."
|
||||
days-before-pr-stale: -1
|
||||
days-before-pr-close: -1
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# build output
|
||||
dist/
|
||||
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
4
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"recommendations": ["astro-build.astro-vscode", "unifiedjs.vscode-mdx"],
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
11
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "./node_modules/.bin/astro dev",
|
||||
"name": "Development server",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"[astro]": {
|
||||
"editor.defaultFormatter": "astro-build.astro-vscode"
|
||||
}
|
||||
}
|
||||
BIN
_astrosphere.jpg
Normal file
|
After Width: | Height: | Size: 68 KiB |
17
_deploy_netlify.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg width="179" height="32" viewBox="0 0 179 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_8_30)">
|
||||
<path d="M173 0H6C2.68629 0 0 2.68629 0 6V26C0 29.3137 2.68629 32 6 32H173C176.314 32 179 29.3137 179 26V6C179 2.68629 176.314 0 173 0Z" fill="#2E51ED"/>
|
||||
<path d="M15.027 23.227H14.781L13.556 22.049V21.813L15.429 20.011H16.727L16.9 20.178V21.426L15.027 23.227ZM13.556 9.89999V9.66399L14.781 8.48499H15.027L16.9 10.287V11.535L16.727 11.701H15.429L13.556 9.89999ZM24.343 19.429H22.561L22.411 19.286V15.273C22.411 14.559 22.12 14.005 21.224 13.986C20.764 13.975 20.236 13.986 19.673 14.007L19.588 14.091V19.284L19.439 19.427H17.657L17.507 19.284V12.429L17.657 12.285H21.669C23.229 12.285 24.492 13.5 24.492 15V19.286L24.343 19.429ZM15.28 16.86H8.15L8 16.716V14.998L8.149 14.855H15.28L15.43 14.998V16.716L15.28 16.859V16.86ZM33.853 16.86H26.722L26.572 16.716V14.998L26.722 14.855H33.853L34.002 14.998V16.716L33.853 16.859V16.86ZM19.973 10.143V4.99999L20.122 4.85699H21.909L22.057 4.99999V10.143L21.909 10.287H20.122L19.973 10.143ZM19.973 26.714V21.571L20.122 21.428H21.909L22.057 21.571V26.714L21.909 26.857H20.122L19.973 26.714ZM155.15 10.64C154.72 11.06 154.51 11.64 154.51 12.39V13.43H153.28V15.1H154.51V21.19H156.47V15.1H158.11V13.43H156.47V12.38C156.47 11.85 156.75 11.58 157.3 11.58H158.34V9.99999H156.94C156.18 9.99999 155.59 10.21 155.16 10.64H155.15ZM150.93 10.13C150.57 10.13 150.27 10.25 150.05 10.48C149.84 10.7 149.73 10.98 149.73 11.32C149.73 11.66 149.84 11.95 150.05 12.19C150.27 12.42 150.57 12.54 150.93 12.54C151.29 12.54 151.57 12.42 151.78 12.19C152 11.96 152.12 11.67 152.12 11.32C152.12 10.97 152.01 10.7 151.78 10.48C151.56 10.25 151.28 10.13 150.93 10.13ZM73.23 10.14H75.19V21.19H73.23V10.14Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M47.32 10.63C48.49 10.63 49.49 10.84 50.33 11.27C51.17 11.69 51.81 12.3 52.25 13.09C52.7 13.88 52.92 14.83 52.92 15.92C52.92 17.01 52.7 17.96 52.25 18.75C51.81 19.54 51.17 20.14 50.33 20.56C49.49 20.98 48.49 21.19 47.32 21.19H44V10.63H47.32ZM47.23 19.22C48.31 19.22 49.16 18.93 49.78 18.35V18.36C50.41 17.77 50.72 16.97 50.72 15.92C50.72 14.87 50.41 14.05 49.78 13.47C49.16 12.89 48.31 12.6 47.23 12.6H46.11V19.22H47.23ZM58.16 13.29C58.96 13.29 59.65 13.45 60.25 13.79L60.24 13.78C60.85 14.11 61.31 14.57 61.64 15.17C61.97 15.77 62.13 16.47 62.13 17.26V17.92H56.28C56.31 18.18 56.36 18.44 56.47 18.66C56.63 18.96 56.85 19.19 57.14 19.36C57.43 19.53 57.78 19.61 58.19 19.61C58.6 19.61 58.95 19.54 59.23 19.41C59.51 19.28 59.72 19.09 59.86 18.86H61.96C61.8 19.33 61.54 19.76 61.19 20.13C60.85 20.51 60.41 20.79 59.89 21C59.38 21.21 58.8 21.31 58.17 21.31C57.38 21.31 56.68 21.15 56.07 20.82C55.47 20.49 55.01 20.02 54.67 19.41C54.34 18.81 54.18 18.1 54.18 17.3C54.18 16.5 54.34 15.8 54.67 15.2C55 14.6 55.46 14.13 56.06 13.79C56.67 13.46 57.36 13.29 58.16 13.29ZM58.16 14.99C57.8 14.99 57.47 15.08 57.18 15.26C56.89 15.42 56.66 15.66 56.49 15.97C56.41 16.14 56.35 16.31 56.31 16.49H60.05C60.0095 16.2241 59.9069 15.9714 59.7505 15.7525C59.5941 15.5336 59.3884 15.3546 59.15 15.23C58.86 15.07 58.52 14.99 58.16 14.99ZM70.16 13.74C69.64 13.42 69.04 13.26 68.35 13.26C67.66 13.26 67.06 13.42 66.57 13.74C66.28 13.93 66.05 14.19 65.86 14.47V13.43H63.9V23.85H65.86V20.16C66.06 20.45 66.29 20.7 66.57 20.9C67.06 21.23 67.65 21.39 68.35 21.39C69.05 21.39 69.63 21.23 70.16 20.91C70.68 20.58 71.09 20.12 71.38 19.51C71.67 18.89 71.81 18.17 71.81 17.33C71.81 16.49 71.67 15.75 71.38 15.15C71.09 14.53 70.68 14.07 70.16 13.75V13.74ZM69.5 18.6C69.33 18.95 69.1 19.22 68.8 19.41C68.51 19.6 68.18 19.69 67.81 19.69C67.22 19.69 66.75 19.48 66.4 19.07C66.05 18.65 65.87 18.08 65.87 17.35C65.87 16.62 66.05 16.07 66.4 15.66C66.75 15.25 67.23 15.04 67.81 15.04C68.18 15.04 68.51 15.14 68.8 15.33C69.1 15.52 69.33 15.79 69.5 16.14C69.67 16.49 69.75 16.89 69.75 17.34C69.75 17.79 69.67 18.23 69.5 18.59V18.6ZM82.85 13.79C82.23 13.44 81.51 13.26 80.68 13.26C79.85 13.26 79.13 13.44 78.51 13.79C77.9 14.14 77.44 14.62 77.11 15.23C76.78 15.85 76.62 16.54 76.62 17.32C76.62 18.1 76.78 18.79 77.11 19.41C77.44 20.02 77.9 20.5 78.51 20.85C79.13 21.2 79.85 21.38 80.68 21.38C81.51 21.38 82.23 21.2 82.85 20.85C83.47 20.5 83.93 20.01 84.25 19.39C84.58 18.77 84.74 18.08 84.74 17.32C84.74 16.56 84.58 15.85 84.25 15.23C83.93 14.61 83.47 14.13 82.85 13.79ZM82.43 18.49C82.27 18.83 82.04 19.09 81.73 19.27C81.43 19.46 81.08 19.55 80.68 19.55C80.28 19.55 79.91 19.46 79.62 19.27C79.32 19.08 79.09 18.82 78.92 18.49C78.76 18.15 78.68 17.76 78.68 17.31C78.68 16.86 78.76 16.46 78.92 16.12C79.09 15.78 79.32 15.53 79.62 15.35C79.92 15.16 80.27 15.07 80.68 15.07C81.09 15.07 81.43 15.16 81.73 15.35C82.04 15.53 82.27 15.79 82.43 16.13C82.6 16.47 82.68 16.86 82.68 17.31C82.68 17.76 82.6 18.15 82.43 18.49Z" fill="white"/>
|
||||
<path d="M87.11 13.43L89.15 18.5L91.26 13.43H93.15L88.84 23.75H86.95L88.14 20.9L85.13 13.43H87.11ZM102.71 10.98H100.75V13.43H99.26V15.1H100.75V21.19H102.71V15.1H104.39V13.43H102.71V10.98Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M109.18 13.26C110.01 13.26 110.73 13.44 111.35 13.79C111.97 14.13 112.43 14.61 112.75 15.23C113.08 15.85 113.24 16.56 113.24 17.32C113.24 18.08 113.08 18.77 112.75 19.39C112.43 20.01 111.97 20.5 111.35 20.85C110.73 21.2 110.01 21.38 109.18 21.38C108.35 21.38 107.63 21.2 107.01 20.85C106.4 20.5 105.94 20.02 105.61 19.41C105.28 18.79 105.12 18.1 105.12 17.32C105.12 16.54 105.28 15.85 105.61 15.23C105.94 14.62 106.4 14.14 107.01 13.79C107.63 13.44 108.35 13.26 109.18 13.26ZM110.23 19.27C110.54 19.09 110.77 18.83 110.93 18.49C111.1 18.15 111.18 17.76 111.18 17.31C111.18 16.86 111.1 16.47 110.93 16.13C110.77 15.79 110.54 15.53 110.23 15.35C109.93 15.16 109.59 15.07 109.18 15.07C108.77 15.07 108.42 15.16 108.12 15.35C107.82 15.53 107.59 15.78 107.42 16.12C107.26 16.46 107.18 16.86 107.18 17.31C107.18 17.76 107.26 18.15 107.42 18.49C107.59 18.82 107.82 19.08 108.12 19.27C108.41 19.46 108.78 19.55 109.18 19.55C109.58 19.55 109.93 19.46 110.23 19.27Z" fill="white"/>
|
||||
<path d="M126.91 16.02L122.22 10.63H120.41V21.19H122.52V14.26L126.91 19.31V21.19H129.02V10.63H126.91V16.02Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M134.5 13.29C135.3 13.29 135.99 13.45 136.59 13.79L136.58 13.78C137.19 14.11 137.65 14.57 137.98 15.17C138.31 15.77 138.47 16.47 138.47 17.26V17.92H132.62C132.65 18.18 132.7 18.44 132.81 18.66C132.97 18.96 133.19 19.19 133.48 19.36C133.77 19.53 134.12 19.61 134.53 19.61C134.94 19.61 135.29 19.54 135.57 19.41C135.85 19.28 136.06 19.09 136.2 18.86H138.3C138.14 19.33 137.88 19.76 137.53 20.13C137.19 20.51 136.75 20.79 136.23 21C135.72 21.21 135.14 21.31 134.51 21.31C133.72 21.31 133.02 21.15 132.41 20.82C131.81 20.49 131.35 20.02 131.01 19.41C130.68 18.81 130.52 18.1 130.52 17.3C130.52 16.5 130.68 15.8 131.01 15.2C131.34 14.6 131.8 14.13 132.4 13.79C133.01 13.46 133.7 13.29 134.5 13.29ZM134.5 14.99C134.14 14.99 133.81 15.08 133.52 15.26C133.23 15.42 133 15.66 132.83 15.97C132.75 16.14 132.69 16.31 132.65 16.49H136.39C136.349 16.224 136.247 15.9714 136.09 15.7525C135.934 15.5336 135.728 15.3546 135.49 15.23C135.2 15.07 134.86 14.99 134.5 14.99Z" fill="white"/>
|
||||
<path d="M142.58 10.98H140.62V13.43H139.14V15.1H140.62V21.19H142.58V15.1H144.26V13.43H142.58V10.98ZM145.92 10.14H147.88V21.19H145.92V10.14ZM149.95 21.18V13.26C150.21 13.45 150.53 13.55 150.93 13.55C151.33 13.55 151.66 13.46 151.91 13.26V21.18H149.95ZM163.14 18.5L165.26 13.43H167.15L162.84 23.75H160.95L162.14 20.9L159.13 13.43H161.1L163.14 18.5Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_8_30">
|
||||
<rect width="179" height="32" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.5 KiB |
5
_deploy_vercel.svg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
_lighthouse.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
11
astro.config.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from "astro/config"
|
||||
import mdx from "@astrojs/mdx"
|
||||
import sitemap from "@astrojs/sitemap"
|
||||
import tailwind from "@astrojs/tailwind"
|
||||
import solidJs from "@astrojs/solid-js"
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: "https://astro-sphere-demo.vercel.app",
|
||||
integrations: [mdx(), sitemap(), solidJs(), tailwind({ applyBaseStyles: false })],
|
||||
})
|
||||
51
content/blog/01-astro-sphere-file-structure/index.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: "Astro Sphere: File Structure"
|
||||
summary: "You'll find these directories and files in the project. What do they do?"
|
||||
date: "Mar 17 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
|
||||
A one line summary of what each file and directory is for:
|
||||
```js
|
||||
/
|
||||
├── public/ // Files publicly available to the browser
|
||||
│ ├── fonts/ // The default fonts for Astro Sphere
|
||||
│ │ └── atkinson-bold.woff // default font weight 700
|
||||
│ │ └── atkinson-regular.woff // default font weight 400
|
||||
│ ├── js/ // Javascript that will be imported into <head>
|
||||
│ │ └── animate.js // function for animating page elements
|
||||
│ │ └── bg.js // function for generating the background
|
||||
│ │ └── scroll.js // scroll handler for the header styles
|
||||
│ │ └── theme.js // controls the light and dark theme
|
||||
│ └── brand.svg //the icon that displays in header and footer
|
||||
│ └── favicon.svg //the icon that displays in the browser
|
||||
│ └── ui.svg // an svg sprite for all ui icons on the website
|
||||
│ └── social.svg // an svg sprite for all social media icons
|
||||
│ └── open-graph.jpg // the default image for open-graph
|
||||
│ └── robots.txt // for web crawlers and bots to index the website
|
||||
├── src/ // Everything that will be built for the website
|
||||
│ ├── components/ // All astro and SolidJs components
|
||||
│ ├── content/ // Contains all static markdown to be compiled
|
||||
│ │ | blog/ // Contains all blog post markdown
|
||||
│ │ | projects/ // Contains all projects markdown
|
||||
│ │ | work/ // Contains all work page markdown
|
||||
│ │ | legal/ // Contains all legal docs markdown
|
||||
│ │ └── config.ts // Contains the collection config for Astro
|
||||
│ ├── layouts/ // Reused layouts across the website
|
||||
│ └── pages/ // All of the pages on the website
|
||||
│ └── styles/ // CSS and global tailwind styles
|
||||
│ └── lib/ // Global helper functions
|
||||
│ └── consts.ts // Page metadata, general configuration
|
||||
│ └── types.ts // Types for consts.ts
|
||||
└── .gitignore // Files and directories to be ignored by Git
|
||||
└── .eslintignore // Files and directories to be ignored by ESLint
|
||||
└── eslintrc.cjs // ESLint configuration
|
||||
└── astro.config.mjs // Astro configuration
|
||||
└── tailwind.config.mjs // Tailwind configuration
|
||||
└── tsconfig.json // Typescript configuration
|
||||
└── package.json // All the installed packages
|
||||
```
|
||||
90
content/blog/02-astro-sphere-getting-started/index.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: "Astro Sphere: Getting Started"
|
||||
summary: "You've downloaded and installed the project. Let's hit the ground running."
|
||||
date: "Mar 16 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
|
||||
Astro Sphere is designed to be configurable. This article will cover the basics on
|
||||
configuring the site and make it personal.
|
||||
|
||||
### First let's change the url
|
||||
|
||||
```js
|
||||
//astro.config.mjs
|
||||
|
||||
export default defineConfig({
|
||||
site: "https://astro-sphere.vercel.app", // your domain here
|
||||
integrations: [mdx(), sitemap(), solidJs(), tailwind({ applyBaseStyles: false })],
|
||||
})
|
||||
```
|
||||
|
||||
### Next, Let's configure the Site
|
||||
|
||||
```js
|
||||
// src/consts.ts
|
||||
|
||||
export const SITE: Site = {
|
||||
TITLE: "Astro Sphere",
|
||||
DESCRIPTION: "Welcome to Astro Sphere, a portfolio and blog for designers and developers.",
|
||||
AUTHOR: "Mark Horn",
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
| :---------- | :----- | :--------------------------------------------------------------------- |
|
||||
| TITLE | String | The title of the website. Displayed in header and footer. Used in SEO. |
|
||||
| DESCRIPTION | String | The description of the index page of the website. Used in SEO. |
|
||||
| AUTHOR | String | Your name. |
|
||||
|
||||
### Change the branding
|
||||
|
||||
The browser icon is located in `/public/favicon.svg`
|
||||
|
||||
The header and footer branding icon is located in `/public/brand.svg` as a sprite with id="brand"
|
||||
|
||||
### The rest of the consts file
|
||||
|
||||
Each page has a metadata entry that is useful for SEO.
|
||||
|
||||
```js
|
||||
export const WORK: Page = {
|
||||
TITLE: "Work",
|
||||
DESCRIPTION: "Places I have worked.",
|
||||
}
|
||||
```
|
||||
|
||||
The links that are displayed in the header and drawer
|
||||
|
||||
```js
|
||||
export const LINKS: Links = [
|
||||
{ HREF: "/", TEXT: "Home" },
|
||||
{ HREF: "/work", TEXT: "Work" },
|
||||
{ HREF: "/blog", TEXT: "Blog" },
|
||||
{ HREF: "/projects", TEXT: "Projects" },
|
||||
]
|
||||
```
|
||||
|
||||
The social media links
|
||||
|
||||
```js
|
||||
export const SOCIALS: Socials = [
|
||||
{
|
||||
NAME: "Github",
|
||||
ICON: "github",
|
||||
TEXT: "markhorn-dev",
|
||||
HREF: "https://github.com/markhorn-dev/astro-sphere"
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| :---- | :--- | :------- | :---------- |
|
||||
| NAME | string | yes | Accessible name |
|
||||
| ICON | string | yes | Refers to the symbol id in `public/social.svg` |
|
||||
| TEXT | string | yes | Shorthand profile name |
|
||||
| HREF | string | yes | The link to the social media profile |
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: "Astro Sphere: Adding a new post or project."
|
||||
summary: "Adding a new article (blog post or project) is pretty easy."
|
||||
date: "Mar 14 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
### Basics
|
||||
|
||||
Create a folder in the respective collection you wish to create content. The name of the folder will be the slug in which your content will be found.
|
||||
|
||||
```text
|
||||
creating the following
|
||||
|
||||
/content/blog/my-new-post/index.md
|
||||
|
||||
will be published to
|
||||
|
||||
https://yourdomain.com/blog/my-new-post
|
||||
|
||||
```
|
||||
|
||||
### Frontmatter
|
||||
|
||||
Front matter is in yaml if you are familiar with the format. All posts and projects require frontmatter at the top of the document to be imported. All frontmatter must be inside triple dashes, similar to Astro format. See example below.
|
||||
|
||||
### Blog Collection
|
||||
|
||||
| Field | Type | Req? | Description |
|
||||
| :------ | :------ | :--- | :------------------------------------------------------------ |
|
||||
| title | string | yes | Title of the post. Used in SEO. |
|
||||
| summary | string | yes | Short description of the post. Used in SEO. |
|
||||
| date | string | yes | Any string date that javascript can convert. Used in sorting |
|
||||
| tags | array | yes | Post topic. Array of strings. Used in filtering. |
|
||||
| draft | boolean | no | Hides the post from collections. Unpublished entry. |
|
||||
|
||||
Example blog post frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Astro Sphere: Adding a new post or project."
|
||||
summary: "Adding a new article (blog post or project) is pretty easy."
|
||||
date: "Mar 18 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
```
|
||||
|
||||
### Projects Collection (extends Blog Collection)
|
||||
|
||||
| Field | Type | Req? | Description |
|
||||
| :------ | :------ | :--- | :------------------------------------------------------------ |
|
||||
| title | string | yes | Title of the post. Used in SEO. |
|
||||
| summary | string | yes | Short description of the post. Used in SEO. |
|
||||
| date | string | yes | Any string date that javascript can convert. Used in sorting |
|
||||
| tags | array | yes | Post topic. Array of strings. Used in filtering. |
|
||||
| draft | boolean | no | Hides the post from collections. Unpublished entry. |
|
||||
| demoUrl | string | no | A link to the deployed project, if applicable. |
|
||||
| repoUrl | string | no | A link to the repository, if applicable. |
|
||||
|
||||
Example project frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Astro Sphere"
|
||||
summary: "Astro Sphere, a portfolio and blog for designers and developers."
|
||||
date: "Mar 18 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Astro
|
||||
- Typescript
|
||||
- Javascript
|
||||
- Tailwind
|
||||
- SolidJS
|
||||
demoUrl: https://astro-sphere.vercel.app
|
||||
repoUrl: https://github.com/markhorn-dev/astro-sphere
|
||||
---
|
||||
```
|
||||
|
||||
### Write your content
|
||||
You've made it this far, all that is left to do is write your content beneath the frontmatter. Writing markdown will be covered in the next article.
|
||||
236
content/blog/04-astro-sphere-writing-markdown/index.md
Normal file
@@ -0,0 +1,236 @@
|
||||
---
|
||||
title: "Astro Sphere: Writing Markdown"
|
||||
summary: "Basic Markdown syntax that can be used when writing Markdown content in Astro Sphere."
|
||||
date: "Mar 13 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
- Markdown
|
||||
---
|
||||
|
||||
### Headings
|
||||
|
||||
```text
|
||||
# H1
|
||||
|
||||
## H2
|
||||
|
||||
### H3
|
||||
|
||||
#### H4
|
||||
|
||||
##### H5
|
||||
|
||||
###### H6
|
||||
|
||||
```
|
||||
|
||||
# H1
|
||||
|
||||
## H2
|
||||
|
||||
### H3
|
||||
|
||||
#### H4
|
||||
|
||||
##### H5
|
||||
|
||||
###### H6
|
||||
|
||||
### Paragraph
|
||||
|
||||
Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.
|
||||
|
||||
Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.
|
||||
|
||||
### Images
|
||||
|
||||
Relative image in the /public folder
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
Relative Image in the same folder as the markdown
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
## Blockquotes
|
||||
|
||||
The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations.
|
||||
|
||||
### Blockquote without attribution
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
||||
> **Note** that you can use _Markdown syntax_ within a blockquote.
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
||||
> **Note** that you can use _Markdown syntax_ within a blockquote.
|
||||
|
||||
### Blockquote with attribution
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
> Don't communicate by sharing memory, share memory by communicating.<br>
|
||||
> — <cite>Rob Pike[^1]</cite>
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
> Don't communicate by sharing memory, share memory by communicating.<br>
|
||||
> — <cite>Rob Pike[^1]</cite>
|
||||
|
||||
[^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.
|
||||
|
||||
## Tables
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
| Italics | Bold | Code |
|
||||
| --------- | -------- | ------ |
|
||||
| _italics_ | **bold** | `code` |
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
| Italics | Bold | Code |
|
||||
| --------- | -------- | ------ |
|
||||
| _italics_ | **bold** | `code` |
|
||||
|
||||
## Code Blocks
|
||||
|
||||
#### Syntax
|
||||
|
||||
we can use 3 backticks ``` in new line and write snippet and close with 3 backticks on new line and to highlight language specific syntac, write one word of language name after first 3 backticks, for eg. html, javascript, css, markdown, typescript, txt, bash
|
||||
|
||||
````markdown
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
````
|
||||
|
||||
Output
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## List Types
|
||||
|
||||
### Ordered List
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
1. First item
|
||||
2. Second item
|
||||
3. Third item
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
1. First item
|
||||
2. Second item
|
||||
3. Third item
|
||||
|
||||
### Unordered List
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
- List item
|
||||
- Another item
|
||||
- And another item
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
- List item
|
||||
- Another item
|
||||
- And another item
|
||||
|
||||
### Nested list
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
- Fruit
|
||||
- Apple
|
||||
- Orange
|
||||
- Banana
|
||||
- Dairy
|
||||
- Milk
|
||||
- Cheese
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
- Fruit
|
||||
- Apple
|
||||
- Orange
|
||||
- Banana
|
||||
- Dairy
|
||||
- Milk
|
||||
- Cheese
|
||||
|
||||
## Other Elements — abbr, sub, sup, kbd, mark
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
||||
|
||||
H<sub>2</sub>O
|
||||
|
||||
X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
|
||||
|
||||
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
|
||||
|
||||
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
||||
|
||||
H<sub>2</sub>O
|
||||
|
||||
X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
|
||||
|
||||
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
|
||||
|
||||
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
|
||||
BIN
content/blog/04-astro-sphere-writing-markdown/spongebob.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
16
content/blog/05-astro-sphere-writing-mdx/MyComponent.astro
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
type Props = {
|
||||
name: string
|
||||
}
|
||||
const { name } = Astro.props
|
||||
---
|
||||
|
||||
<div class="border p-4 bg-yellow-100 text-black">
|
||||
<div>
|
||||
Hello,
|
||||
<span class="font-semibold">
|
||||
{name}!!!
|
||||
</span>
|
||||
</div>
|
||||
<slot/>
|
||||
</div>
|
||||
53
content/blog/05-astro-sphere-writing-mdx/index.mdx
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: "Astro Sphere: Writing MDX"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 12 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
- Markdown
|
||||
- MDX
|
||||
---
|
||||
|
||||
MDX is a special flavor of Markdown that supports embedded JavaScript & JSX syntax. This unlocks the ability to [mix JavaScript and UI Components into your Markdown content](https://docs.astro.build/en/guides/markdown-content/#mdx-features) for things like interactive charts or alerts.
|
||||
|
||||
If you have existing content authored in MDX, this integration will hopefully make migrating to Astro a breeze.
|
||||
|
||||
## An astro component with props
|
||||
|
||||
```
|
||||
// Imported from relative path (same dir as markdown file)
|
||||
import MyComponent from "./MyComponent.astro"
|
||||
|
||||
<MyComponent name="You">
|
||||
Welcome to MDX
|
||||
</MyComponent>
|
||||
```
|
||||
|
||||
import MyComponent from "./MyComponent.astro"
|
||||
|
||||
<MyComponent name="You">
|
||||
Welcome to MDX
|
||||
</MyComponent>
|
||||
|
||||
|
||||
|
||||
## An interactive Solid Js component
|
||||
|
||||
```
|
||||
// Imported from components directory (src/components)
|
||||
import MyComponent from "@components/Counter"
|
||||
|
||||
// Don't forget the astro client:load directive
|
||||
<Counter client:load />
|
||||
```
|
||||
|
||||
import Counter from "@components/Counter"
|
||||
|
||||
<Counter client:load />
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
54
content/blog/06-astro-sphere-social-links/index.md
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: "Astro Sphere: Social media links"
|
||||
summary: "A quick tutorial on how to change, add or remove social media links"
|
||||
date: "Mar 11 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
|
||||
Astro Sphere comes preconfigured with social media links for Email, Github, Linked In and Twitter (X), but it's very easy to add more.
|
||||
|
||||
### Edit `consts.ts`
|
||||
|
||||
```js
|
||||
// consts.ts
|
||||
|
||||
export const SOCIALS: Socials = [
|
||||
{
|
||||
NAME: "Github",
|
||||
ICON: "github",
|
||||
TEXT: "markhorn-dev",
|
||||
HREF: "https://github.com/markhorn-dev/astro-sphere"
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| :---- | :--- | :------- | :---------- |
|
||||
| NAME | string | yes | Accessible name |
|
||||
| ICON | string | yes | Refers to the symbol id in `public/social.svg` |
|
||||
| TEXT | string | yes | Shorthand profile name |
|
||||
| HREF | string | yes | The link to the social media profile |
|
||||
|
||||
### Edit /public/social.svg
|
||||
|
||||
Simply add your own symbols to the svg sprite.
|
||||
|
||||
It is recommended that all styles be removed from new symbols added, or they may not show up correctly or conflict with Tailwind's classes.
|
||||
|
||||
The id should match the icon field as specified in your `consts.ts` file.
|
||||
|
||||
```html
|
||||
<!-- public/social.svg -->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<symbol id="github" viewBox="0 0 496 512">
|
||||
<path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
```
|
||||
45
content/config.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { defineCollection, z } from "astro:content"
|
||||
|
||||
const work = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
company: z.string(),
|
||||
role: z.string(),
|
||||
dateStart: z.coerce.date(),
|
||||
dateEnd: z.union([z.coerce.date(), z.string()]),
|
||||
}),
|
||||
})
|
||||
|
||||
const blog = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
summary: z.string(),
|
||||
date: z.coerce.date(),
|
||||
tags: z.array(z.string()),
|
||||
draft: z.boolean().optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
const projects = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
summary: z.string(),
|
||||
date: z.coerce.date(),
|
||||
tags: z.array(z.string()),
|
||||
draft: z.boolean().optional(),
|
||||
demoUrl: z.string().optional(),
|
||||
repoUrl: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
const legal = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
date: z.coerce.date(),
|
||||
}),
|
||||
})
|
||||
|
||||
export const collections = { work, blog, projects, legal }
|
||||
28
content/legal/privacy.md
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: "Privacy Policy"
|
||||
date: "03/07/2024"
|
||||
---
|
||||
|
||||
This Privacy Policy governs the manner in which [Your Company Name] collects, uses, maintains, and discloses information collected from users (each, a "User") of the [Your Website URL] website ("Site"). This privacy policy applies to the Site and all products and services offered by [Your Company Name].
|
||||
|
||||
#### Personal identification information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Non-personal identification information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Web browser cookies
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### How we use collected information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### How we protect your information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Sharing your personal information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Changes to this privacy policy
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
27
content/legal/terms.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: "Terms of Use"
|
||||
date: "03/07/2024"
|
||||
---
|
||||
|
||||
Please read these Terms of Use ("Terms", "Terms of Use") carefully before using the [Your Website URL] website (the "Service") operated by [Your Company Name] ("us", "we", or "our").
|
||||
|
||||
#### Agreement to Terms
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Intellectual Property Rights
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### User Representations
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Links to Other Websites
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Termination
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Governing Law
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Changes to These Terms of Use
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
16
content/projects/project-1/index.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "Project One"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 18 2022"
|
||||
draft: false
|
||||
tags:
|
||||
- Astro
|
||||
- Javascript
|
||||
- Typescript
|
||||
- Tailwind
|
||||
- SolidJs
|
||||
demoUrl: https://astro-sphere-demo.vercel.app
|
||||
repoUrl: https://github.com/markhorn-dev/astro-sphere
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
15
content/projects/project-2/index.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "Project Two"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 17 2022"
|
||||
draft: false
|
||||
tags:
|
||||
- Svelte
|
||||
- Sveltekit
|
||||
- Typescript
|
||||
- Tailwind
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
12
content/projects/project-3/index.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: "Project Three"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 16 2022"
|
||||
draft: false
|
||||
tags:
|
||||
- Vue
|
||||
- Javascript
|
||||
- Tailwind
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
31
content/projects/project-4/index.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: "Project Four"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 15 2022"
|
||||
draft: false
|
||||
tags:
|
||||
- React
|
||||
- Javascript
|
||||
- StyleX
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium.
|
||||
|
||||
Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas.
|
||||
|
||||
Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem.
|
||||
Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium.
|
||||
|
||||
Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas.
|
||||
|
||||
Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem.
|
||||
Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium.
|
||||
|
||||
Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas.
|
||||
|
||||
Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem.
|
||||
Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
11
content/work/apple.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
company: "Apple"
|
||||
role: "Software Engineer"
|
||||
dateStart: "01/01/2020"
|
||||
dateEnd: "11/27/2022"
|
||||
---
|
||||
|
||||
Voluptatem est quaerat voluptas praesentium ipsa dolorem dignissimos nulla ratione distinctio quae maiores eligendi nostrum? Quibusdam, debitis voluptatum, lorem ipsum dolor. Sit amet consectetur adipisicing elit. Iure illo neque tempora.
|
||||
|
||||
- Sit amet consectetur adipisicing elit. Iure illo neque tempora.
|
||||
- Quibusdam, debitis voluptatum, lorem ipsum
|
||||
10
content/work/facebook.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
company: "Facebook"
|
||||
role: "Intern"
|
||||
dateStart: "07/01/2019"
|
||||
dateEnd: "12/31/2019"
|
||||
---
|
||||
|
||||
Iure illo neque tempora, voluptatem est quaerat voluptas praesentium ipsa dolorem dignissimos nulla ratione distinctio quae maiores eligendi nostrum? Quibusdam, debitis voluptatum, lorem ipsum dolor. Sit amet consectetur adipisicing elit.
|
||||
|
||||
- Sit amet consectetur adipisicing elit.
|
||||
12
content/work/google.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
company: "Google"
|
||||
role: "Staff Software Engineer"
|
||||
dateStart: "11/27/2022"
|
||||
dateEnd: "Now"
|
||||
---
|
||||
|
||||
Sit amet consectetur adipisicing elit. Iure illo neque tempora, voluptatem est quaerat voluptas praesentium ipsa dolorem dignissimos nulla ratione distinctio quae maiores eligendi nostrum? Quibusdam, debitis voluptatum, lorem ipsum dolor.
|
||||
|
||||
- Aadipisicing elit. Iure illo neque tempora, voluptatem est.
|
||||
- dolorem dignissimos nulla ratione.
|
||||
- Quibusdam, debitis voluptatum, lorem ipsum dolor.
|
||||
11
content/work/mcdonalds.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
company: "McDonalds"
|
||||
role: "French Fryer"
|
||||
dateStart: "03/16/2018"
|
||||
dateEnd: "07/01/2019"
|
||||
---
|
||||
|
||||
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Iure illo neque tempora, voluptatem est quaerat voluptas praesentium ipsa dolorem dignissimos nulla ratione distinctio quae maiores eligendi nostrum? Quibusdam, debitis voluptatum.
|
||||
|
||||
- Quibusdam, debitis voluptatum.
|
||||
- amet consectetur adipisicing elit. Iure illo neque tempora.
|
||||
8082
package-lock.json
generated
Normal file
33
package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "plata-upravleniy-rf",
|
||||
"type": "module",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev:network": "astro dev --host",
|
||||
"start": "astro dev",
|
||||
"build": "astro check && astro build",
|
||||
"preview": "astro preview",
|
||||
"preview:network": "astro dev --host",
|
||||
"astro": "astro",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.5.10",
|
||||
"@astrojs/mdx": "^2.1.1",
|
||||
"@astrojs/rss": "^4.0.5",
|
||||
"@astrojs/sitemap": "^3.1.1",
|
||||
"@astrojs/solid-js": "^4.0.1",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"astro": "^4.4.13",
|
||||
"clsx": "^2.1.0",
|
||||
"fuse.js": "^7.0.0",
|
||||
"sharp": "^0.33.2",
|
||||
"solid-js": "^1.8.15",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
21
plata-upravleniy-rf/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Mark Horn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
89
plata-upravleniy-rf/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||

|
||||
|
||||
Astro Sphere is a static, minimalist, lightweight, lightning fast portfolio and blog theme based on my personal website.
|
||||
|
||||
It is primarily Astro, Tailwind and Typescript, with a very small amount of SolidJS for stateful components.
|
||||
|
||||
## 🚀 Deploy your own
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https://github.com/markhorn-dev/astro-sphere) [](https://app.netlify.com/start/deploy?repository=https://github.com/markhorn-dev/astro-sphere)
|
||||
|
||||
## 📋 Features
|
||||
|
||||
- ✅ 100/100 Lighthouse performance
|
||||
- ✅ Responsive
|
||||
- ✅ Accessible
|
||||
- ✅ SEO-friendly
|
||||
- ✅ Typesafe
|
||||
- ✅ Minimal style
|
||||
- ✅ Light/Dark Theme
|
||||
- ✅ Animated UI
|
||||
- ✅ Tailwind styling
|
||||
- ✅ Auto generated sitemap
|
||||
- ✅ Auto generated RSS Feed
|
||||
- ✅ Markdown support
|
||||
- ✅ MDX Support (components in your markdown)
|
||||
- ✅ Searchable content (posts and projects)
|
||||
|
||||
## 💯 Lighthouse score
|
||||

|
||||
|
||||
## 🕊️ Lightweight
|
||||
All pages under 100kb (including fonts)
|
||||
|
||||
## ⚡︎ Fast
|
||||
Rendered in ~40ms on localhost
|
||||
|
||||
## 📄 Configuration
|
||||
|
||||
The blog posts on the demo serve as the documentation and configuration.
|
||||
|
||||
## 💻 Commands
|
||||
|
||||
All commands are run from the root of the project, from a terminal:
|
||||
|
||||
Replace npm with your package manager of choice. `npm`, `pnpm`, `yarn`, `bun`, etc
|
||||
|
||||
| Command | Action |
|
||||
| :------------------------ | :----------------------------------------------- |
|
||||
| `npm install` | Installs dependencies |
|
||||
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
||||
| `npm run dev:network` | Starts dev server on local network |
|
||||
| `npm run sync` | Generates TypeScript types for all Astro modules.|
|
||||
| `npm run build` | Build your production site to `./dist/` |
|
||||
| `npm run preview` | Preview your build locally, before deploying |
|
||||
| `npm run preview:network` | Starts preview server on local network |
|
||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||
| `npm run astro -- --help` | Get help using the Astro CLI |
|
||||
| `npm run lint` | Run ESLint |
|
||||
| `npm run lint:fix` | Auto-fix ESLint issues |
|
||||
|
||||
## 🗺️ Roadmap
|
||||
|
||||
A few features I plan to implement
|
||||
- ⬜ Code Blocks - copy to clipboard
|
||||
- ⬜ Article Pages - Table of Contents
|
||||
- ⬜ Article Pages - Share on social media
|
||||
|
||||
## ✨ Acknowledgement
|
||||
|
||||
Theme inspired by [Paco Coursey](https://paco.me/), [Lee Robinson](https://leerob.io/) and [Hayden Bleasel](https://www.haydenbleasel.com/)
|
||||
|
||||
|
||||
## 🏛️ License
|
||||
|
||||
MIT
|
||||
|
||||
|
||||
# 1.0.1 Update
|
||||
|
||||
Added ability to run dev and preview on local network.
|
||||
added npm run dev:network
|
||||
added npm run preview:network
|
||||
|
||||
Added slightly more particle density in both light and dark mode.
|
||||
|
||||
Added subtle dark mode star and meteor animations.
|
||||
|
||||
Removed eslint config
|
||||
|
||||
5031
pnpm-lock.yaml
generated
Normal file
8
public/brand.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" >
|
||||
<defs>
|
||||
<symbol id="brand" viewBox="0 0 85 107">
|
||||
<path fill="#F041FF" d="M27.5894 91.1365C22.7555 86.7178 21.3444 77.4335 23.3583 70.7072C26.8503 74.948 31.6888 76.2914 36.7005 77.0497C44.4375 78.2199 52.0359 77.7822 59.2232 74.2459C60.0454 73.841 60.8052 73.3027 61.7036 72.7574C62.378 74.714 62.5535 76.6892 62.318 78.6996C61.7452 83.5957 59.3086 87.3778 55.4332 90.2448C53.8835 91.3916 52.2437 92.4167 50.6432 93.4979C45.7262 96.8213 44.3959 100.718 46.2435 106.386C46.2874 106.525 46.3267 106.663 46.426 107C43.9155 105.876 42.0817 104.24 40.6845 102.089C39.2087 99.8193 38.5066 97.3081 38.4696 94.5909C38.4511 93.2686 38.4511 91.9345 38.2733 90.6309C37.8391 87.4527 36.3471 86.0297 33.5364 85.9478C30.6518 85.8636 28.37 87.6469 27.7649 90.4554C27.7187 90.6707 27.6517 90.8837 27.5847 91.1341L27.5894 91.1365Z"/>
|
||||
<path fill="currentColor" d="M0 69.5866C0 69.5866 14.3139 62.6137 28.6678 62.6137L39.4901 29.1204C39.8953 27.5007 41.0783 26.3999 42.4139 26.3999C43.7495 26.3999 44.9325 27.5007 45.3377 29.1204L56.1601 62.6137C73.1601 62.6137 84.8278 69.5866 84.8278 69.5866C84.8278 69.5866 60.5145 3.35233 60.467 3.21944C59.7692 1.2612 58.5911 0 57.0029 0H27.8274C26.2392 0 25.1087 1.2612 24.3634 3.21944C24.3108 3.34983 0 69.5866 0 69.5866Z"/>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
9
public/favicon copy.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
</style>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 749 B |
9
public/favicon.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
</style>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 749 B |
BIN
public/fonts/atkinson-bold.woff
Normal file
BIN
public/fonts/atkinson-regular.woff
Normal file
12
public/js/animate.js
Normal file
@@ -0,0 +1,12 @@
|
||||
function animate() {
|
||||
const animateElements = document.querySelectorAll('.animate')
|
||||
|
||||
animateElements.forEach((element, index) => {
|
||||
setTimeout(() => {
|
||||
element.classList.add('show')
|
||||
}, index * 150)
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", animate)
|
||||
document.addEventListener("astro:after-swap", animate)
|
||||
96
public/js/bg.js
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
function generateParticles(n) {
|
||||
let value = `${getRandom(2560)}px ${getRandom(2560)}px #000`;
|
||||
for (let i = 2; i <= n; i++) {
|
||||
value += `, ${getRandom(2560)}px ${getRandom(2560)}px #000`;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function generateStars(n) {
|
||||
let value = `${getRandom(2560)}px ${getRandom(2560)}px #fff`;
|
||||
for (let i = 2; i <= n; i++) {
|
||||
value += `, ${getRandom(2560)}px ${getRandom(2560)}px #fff`;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function getRandom(max) {
|
||||
return Math.floor(Math.random() * max);
|
||||
}
|
||||
|
||||
function initBG() {
|
||||
const particlesSmall = generateParticles(1000);
|
||||
const particlesMedium = generateParticles(500);
|
||||
const particlesLarge = generateParticles(250);
|
||||
const particles1 = document.getElementById('particles1');
|
||||
const particles2 = document.getElementById('particles2');
|
||||
const particles3 = document.getElementById('particles3');
|
||||
|
||||
if (particles1) {
|
||||
particles1.style.cssText = `
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border-radius: 50%;
|
||||
box-shadow: ${particlesSmall};
|
||||
animation: animStar 50s linear infinite;
|
||||
`;
|
||||
}
|
||||
|
||||
if (particles2) {
|
||||
particles2.style.cssText = `
|
||||
width: 1.5px;
|
||||
height: 1.5px;
|
||||
border-radius: 50%;
|
||||
box-shadow: ${particlesMedium};
|
||||
animation: animateParticle 100s linear infinite;
|
||||
`;
|
||||
}
|
||||
|
||||
if (particles3) {
|
||||
particles3.style.cssText = `
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
border-radius: 50%;
|
||||
box-shadow: ${particlesLarge};
|
||||
animation: animateParticle 150s linear infinite;
|
||||
`;
|
||||
}
|
||||
|
||||
const starsSmall = generateStars(1000);
|
||||
const starsMedium = generateStars(500);
|
||||
const starsLarge = generateStars(250);
|
||||
const stars1 = document.getElementById('stars1');
|
||||
const stars2 = document.getElementById('stars2');
|
||||
const stars3 = document.getElementById('stars3');
|
||||
|
||||
if (stars1) {
|
||||
stars1.style.cssText = `
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border-radius: 50%;
|
||||
box-shadow: ${starsSmall};
|
||||
`;
|
||||
}
|
||||
|
||||
if (stars2) {
|
||||
stars2.style.cssText = `
|
||||
width: 1.5px;
|
||||
height: 1.5px;
|
||||
border-radius: 50%;
|
||||
box-shadow: ${starsMedium};
|
||||
`;
|
||||
}
|
||||
|
||||
if (stars3) {
|
||||
stars3.style.cssText = `
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
border-radius: 50%;
|
||||
box-shadow: ${starsLarge};
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('astro:after-swap', initBG);
|
||||
initBG();
|
||||
10
public/js/scroll.js
Normal file
@@ -0,0 +1,10 @@
|
||||
function onScroll() {
|
||||
const header = document.getElementById("header")
|
||||
if (window.scrollY > 0) {
|
||||
header.classList.add("scrolled")
|
||||
} else {
|
||||
header.classList.remove("scrolled")
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("scroll", onScroll)
|
||||
67
public/js/theme.js
Normal file
@@ -0,0 +1,67 @@
|
||||
function changeTheme() {
|
||||
const element = document.documentElement
|
||||
const theme = element.classList.contains("dark") ? "light" : "dark"
|
||||
|
||||
const css = document.createElement("style")
|
||||
|
||||
css.appendChild(
|
||||
document.createTextNode(
|
||||
`* {
|
||||
-webkit-transition: none !important;
|
||||
-moz-transition: none !important;
|
||||
-o-transition: none !important;
|
||||
-ms-transition: none !important;
|
||||
transition: none !important;
|
||||
}`,
|
||||
),
|
||||
)
|
||||
document.head.appendChild(css)
|
||||
|
||||
if (theme === "dark") {
|
||||
element.classList.add("dark")
|
||||
} else {
|
||||
element.classList.remove("dark")
|
||||
}
|
||||
|
||||
window.getComputedStyle(css).opacity
|
||||
document.head.removeChild(css)
|
||||
localStorage.theme = theme
|
||||
}
|
||||
|
||||
function preloadTheme() {
|
||||
const theme = (() => {
|
||||
const userTheme = localStorage.theme
|
||||
|
||||
if (userTheme === "light" || userTheme === "dark") {
|
||||
return userTheme
|
||||
} else {
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
|
||||
}
|
||||
})()
|
||||
|
||||
const element = document.documentElement
|
||||
|
||||
if (theme === "dark") {
|
||||
element.classList.add("dark")
|
||||
} else {
|
||||
element.classList.remove("dark")
|
||||
}
|
||||
|
||||
localStorage.theme = theme
|
||||
}
|
||||
|
||||
window.onload = () => {
|
||||
function initializeThemeButtons() {
|
||||
const headerThemeButton = document.getElementById("header-theme-button")
|
||||
const drawerThemeButton = document.getElementById("drawer-theme-button")
|
||||
headerThemeButton?.addEventListener("click", changeTheme)
|
||||
drawerThemeButton?.addEventListener("click", changeTheme)
|
||||
}
|
||||
|
||||
document.addEventListener("astro:after-swap", initializeThemeButtons)
|
||||
initializeThemeButtons()
|
||||
}
|
||||
|
||||
document.addEventListener("astro:after-swap", preloadTheme)
|
||||
|
||||
preloadTheme()
|
||||
BIN
public/open-graph.jpg
Normal file
|
After Width: | Height: | Size: 68 KiB |
4
public/robots.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: http://localhost:4321/sitemap-index.xml
|
||||
19
public/social.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<symbol id="email" viewBox="0 0 512 512">
|
||||
<path d="M64 112c-8.8 0-16 7.2-16 16v22.1L220.5 291.7c20.7 17 50.4 17 71.1 0L464 150.1V128c0-8.8-7.2-16-16-16H64zM48 212.2V384c0 8.8 7.2 16 16 16H448c8.8 0 16-7.2 16-16V212.2L322 328.8c-38.4 31.5-93.7 31.5-132 0L48 212.2zM0 128C0 92.7 28.7 64 64 64H448c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128z"/>
|
||||
</symbol>
|
||||
<symbol id="github" viewBox="0 0 496 512">
|
||||
<path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/>
|
||||
</symbol>
|
||||
<symbol id="linkedin" viewBox="0 0 448 512">
|
||||
<path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/>
|
||||
</symbol>
|
||||
<symbol id="youtube" viewBox="0 0 512 512">
|
||||
<path d="M549.7 124.1c-6.3-23.7-24.8-42.3-48.3-48.6C458.8 64 288 64 288 64S117.2 64 74.6 75.5c-23.5 6.3-42 24.9-48.3 48.6-11.4 42.9-11.4 132.3-11.4 132.3s0 89.4 11.4 132.3c6.3 23.7 24.8 41.5 48.3 47.8C117.2 448 288 448 288 448s170.8 0 213.4-11.5c23.5-6.3 42-24.2 48.3-47.8 11.4-42.9 11.4-132.3 11.4-132.3s0-89.4-11.4-132.3zm-317.5 213.5V175.2l142.7 81.2-142.7 81.2z"/>
|
||||
</symbol>
|
||||
<symbol id="telegram" viewBox="0 0 496 512">
|
||||
<path d="M248 8C111 8 0 119 0 256S111 504 248 504 496 393 496 256 385 8 248 8zM363 176.7c-3.7 39.2-19.9 134.4-28.1 178.3-3.5 18.6-10.3 24.8-16.9 25.4-14.4 1.3-25.3-9.5-39.3-18.7-21.8-14.3-34.2-23.2-55.3-37.2-24.5-16.1-8.6-25 5.3-39.5 3.7-3.8 67.1-61.5 68.3-66.7 .2-.7 .3-3.1-1.2-4.4s-3.6-.8-5.1-.5q-3.3 .7-104.6 69.1-14.8 10.2-26.9 9.9c-8.9-.2-25.9-5-38.6-9.1-15.5-5-27.9-7.7-26.8-16.3q.8-6.7 18.5-13.7 108.4-47.2 144.6-62.3c68.9-28.6 83.2-33.6 92.5-33.8 2.1 0 6.6 .5 9.6 2.9a10.5 10.5 0 0 1 3.5 6.7A43.8 43.8 0 0 1 363 176.7z"/>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
27
public/stack.svg
Normal file
@@ -0,0 +1,27 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<!-- astro icon -->
|
||||
<symbol id="astro" viewBox="0 0 85 107">
|
||||
<path d="M27.5894 91.1365C22.7555 86.7178 21.3444 77.4335 23.3583 70.7072C26.8503 74.948 31.6888 76.2914 36.7005 77.0497C44.4375 78.2199 52.0359 77.7822 59.2232 74.2459C60.0454 73.841 60.8052 73.3027 61.7036 72.7574C62.378 74.714 62.5535 76.6892 62.318 78.6996C61.7452 83.5957 59.3086 87.3778 55.4332 90.2448C53.8835 91.3916 52.2437 92.4167 50.6432 93.4979C45.7262 96.8213 44.3959 100.718 46.2435 106.386C46.2874 106.525 46.3267 106.663 46.426 107C43.9155 105.876 42.0817 104.24 40.6845 102.089C39.2087 99.8193 38.5066 97.3081 38.4696 94.5909C38.4511 93.2686 38.4511 91.9345 38.2733 90.6309C37.8391 87.4527 36.3471 86.0297 33.5364 85.9478C30.6518 85.8636 28.37 87.6469 27.7649 90.4554C27.7187 90.6707 27.6517 90.8837 27.5847 91.1341L27.5894 91.1365Z" fill="#F041FF"/>
|
||||
<path d="M0 69.5866C0 69.5866 14.3139 62.6137 28.6678 62.6137L39.4901 29.1204C39.8953 27.5007 41.0783 26.3999 42.4139 26.3999C43.7495 26.3999 44.9325 27.5007 45.3377 29.1204L56.1601 62.6137C73.1601 62.6137 84.8278 69.5866 84.8278 69.5866C84.8278 69.5866 60.5145 3.35233 60.467 3.21944C59.7692 1.2612 58.5911 0 57.0029 0H27.8274C26.2392 0 25.1087 1.2612 24.3634 3.21944C24.3108 3.34983 0 69.5866 0 69.5866Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<!-- javascript icon -->
|
||||
<symbol id="javascript" viewBox="0 0 630 630">
|
||||
<rect width="630" height="630" fill="#f7df1e"/>
|
||||
<path fill="black" d="m423.2 492.19c12.69 20.72 29.2 35.95 58.4 35.95 24.53 0 40.2-12.26 40.2-29.2 0-20.3-16.1-27.49-43.1-39.3l-14.8-6.35c-42.72-18.2-71.1-41-71.1-89.2 0-44.4 33.83-78.2 86.7-78.2 37.64 0 64.7 13.1 84.2 47.4l-46.1 29.6c-10.15-18.2-21.1-25.37-38.1-25.37-17.34 0-28.33 11-28.33 25.37 0 17.76 11 24.95 36.4 35.95l14.8 6.34c50.3 21.57 78.7 43.56 78.7 93 0 53.3-41.87 82.5-98.1 82.5-54.98 0-90.5-26.2-107.88-60.54zm-209.13 5.13c9.3 16.5 17.76 30.45 38.1 30.45 19.45 0 31.72-7.61 31.72-37.2v-201.3h59.2v202.1c0 61.3-35.94 89.2-88.4 89.2-47.4 0-74.85-24.53-88.81-54.075z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- typescript icon -->
|
||||
<symbol id="typescript" fill="none" viewBox="0 0 512 512">
|
||||
<rect fill="#3178c6" height="512" rx="50" width="512"/>
|
||||
<rect fill="#3178c6" height="512" rx="50" width="512"/>
|
||||
<path clip-rule="evenodd" fill="#fff" fill-rule="evenodd" d="m316.939 407.424v50.061c8.138 4.172 17.763 7.3 28.875 9.386s22.823 3.129 35.135 3.129c11.999 0 23.397-1.147 34.196-3.442 10.799-2.294 20.268-6.075 28.406-11.342 8.138-5.266 14.581-12.15 19.328-20.65s7.121-19.007 7.121-31.522c0-9.074-1.356-17.026-4.069-23.857s-6.625-12.906-11.738-18.225c-5.112-5.319-11.242-10.091-18.389-14.315s-15.207-8.213-24.18-11.967c-6.573-2.712-12.468-5.345-17.685-7.9-5.217-2.556-9.651-5.163-13.303-7.822-3.652-2.66-6.469-5.476-8.451-8.448-1.982-2.973-2.974-6.336-2.974-10.091 0-3.441.887-6.544 2.661-9.308s4.278-5.136 7.512-7.118c3.235-1.981 7.199-3.52 11.894-4.615 4.696-1.095 9.912-1.642 15.651-1.642 4.173 0 8.581.313 13.224.938 4.643.626 9.312 1.591 14.008 2.894 4.695 1.304 9.259 2.947 13.694 4.928 4.434 1.982 8.529 4.276 12.285 6.884v-46.776c-7.616-2.92-15.937-5.084-24.962-6.492s-19.381-2.112-31.066-2.112c-11.895 0-23.163 1.278-33.805 3.833s-20.006 6.544-28.093 11.967c-8.086 5.424-14.476 12.333-19.171 20.729-4.695 8.395-7.043 18.433-7.043 30.114 0 14.914 4.304 27.638 12.912 38.172 8.607 10.533 21.675 19.45 39.204 26.751 6.886 2.816 13.303 5.579 19.25 8.291s11.086 5.528 15.415 8.448c4.33 2.92 7.747 6.101 10.252 9.543 2.504 3.441 3.756 7.352 3.756 11.733 0 3.233-.783 6.231-2.348 8.995s-3.939 5.162-7.121 7.196-7.147 3.624-11.894 4.771c-4.748 1.148-10.303 1.721-16.668 1.721-10.851 0-21.597-1.903-32.24-5.71-10.642-3.806-20.502-9.516-29.579-17.13zm-84.159-123.342h64.22v-41.082h-179v41.082h63.906v182.918h50.874z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- tailwind icon -->
|
||||
<symbol id="tailwind" viewBox="0 0 47 40" fill="none">
|
||||
<path fill="#6366f1" d="M23.5 6.5C17.5 6.5 13.75 9.5 12.25 15.5C14.5 12.5 17.125 11.375 20.125 12.125C21.8367 12.5529 23.0601 13.7947 24.4142 15.1692C26.6202 17.4084 29.1734 20 34.75 20C40.75 20 44.5 17 46 11C43.75 14 41.125 15.125 38.125 14.375C36.4133 13.9471 35.1899 12.7053 33.8357 11.3308C31.6297 9.09158 29.0766 6.5 23.5 6.5ZM12.25 20C6.25 20 2.5 23 1 29C3.25 26 5.875 24.875 8.875 25.625C10.5867 26.0529 11.8101 27.2947 13.1642 28.6693C15.3702 30.9084 17.9234 33.5 23.5 33.5C29.5 33.5 33.25 30.5 34.75 24.5C32.5 27.5 29.875 28.625 26.875 27.875C25.1633 27.4471 23.9399 26.2053 22.5858 24.8307C20.3798 22.5916 17.8266 20 12.25 20Z"/>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
87
public/ui.svg
Normal file
@@ -0,0 +1,87 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<!-- menu -->
|
||||
<symbol id="menu" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<path d="M3 12h18"/>
|
||||
<path d="M3 6h18"/>
|
||||
<path d="M3 18h18"/>
|
||||
</symbol>
|
||||
|
||||
<!-- x -->
|
||||
<symbol id="x" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<path d="M18 6L6 18"/>
|
||||
<path d="M6 6l12 12"/>
|
||||
</symbol>
|
||||
|
||||
<!-- search -->
|
||||
<symbol id="search" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<path d="M11 17.25a6.25 6.25 0 110-12.5 6.25 6.25 0 010 12.5z"/>
|
||||
<path d="M16 16l4.5 4.5"/>
|
||||
</symbol>
|
||||
|
||||
<!-- rss -->
|
||||
<symbol id="rss" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<path d="M4 11a9 9 0 019 9"/>
|
||||
<path d="M4 4a16 16 0 0116 16"/>
|
||||
<circle cx="5" cy="19" r="1"/>
|
||||
</symbol>
|
||||
|
||||
<!-- sun -->
|
||||
<symbol id="sun" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<circle cx="12" cy="12" r="5"/>
|
||||
<path d="M12 1v2"/>
|
||||
<path d="M12 21v2"/>
|
||||
<path d="M4.22 4.22l1.42 1.42"/>
|
||||
<path d="M18.36 18.36l1.42 1.42"/>
|
||||
<path d="M1 12h2"/>
|
||||
<path d="M21 12h2"/>
|
||||
<path d="M4.22 19.78l1.42-1.42"/>
|
||||
<path d="M18.36 5.64l1.42-1.42"/>
|
||||
</symbol>
|
||||
|
||||
<!-- moon -->
|
||||
<symbol id="moon" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- square -->
|
||||
<symbol id="square" viewBox="0 0 448 512">
|
||||
<path d="M384 80c8.8 0 16 7.2 16 16V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V96c0-8.8 7.2-16 16-16H384zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- square-check -->
|
||||
<symbol id="square-check" viewBox="0 0 448 512">
|
||||
<path d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM337 209L209 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L303 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- calendar -->
|
||||
<symbol id="calendar" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24">
|
||||
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
|
||||
<path d="M16 2v4"/>
|
||||
<path d="M8 2v4"/>
|
||||
<path d="M3 10h18"/>
|
||||
</symbol>
|
||||
|
||||
<!-- book-open -->
|
||||
<symbol id="book-open" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24">
|
||||
<path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/>
|
||||
<path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- arrow-right -->
|
||||
<symbol id="arrow-right" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24">
|
||||
<path d="M5 12h14"/>
|
||||
<path d="M12 5l7 7-7 7"/>
|
||||
</symbol>
|
||||
|
||||
<!-- globe -->
|
||||
<symbol id="globe" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.268 14.0934C11.9051 13.4838 13.2303 12.2333 13.9384 10.6469C13.1192 10.7941 12.2138 10.9111 11.2469 10.9925C11.0336 12.2005 10.695 13.2621 10.268 14.0934ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16ZM8.48347 14.4823C8.32384 14.494 8.16262 14.5 8 14.5C7.83738 14.5 7.67616 14.494 7.51654 14.4823C7.5132 14.4791 7.50984 14.4759 7.50647 14.4726C7.2415 14.2165 6.94578 13.7854 6.67032 13.1558C6.41594 12.5744 6.19979 11.8714 6.04101 11.0778C6.67605 11.1088 7.33104 11.125 8 11.125C8.66896 11.125 9.32395 11.1088 9.95899 11.0778C9.80021 11.8714 9.58406 12.5744 9.32968 13.1558C9.05422 13.7854 8.7585 14.2165 8.49353 14.4726C8.49016 14.4759 8.4868 14.4791 8.48347 14.4823ZM11.4187 9.72246C12.5137 9.62096 13.5116 9.47245 14.3724 9.28806C14.4561 8.87172 14.5 8.44099 14.5 8C14.5 7.55901 14.4561 7.12828 14.3724 6.71194C13.5116 6.52755 12.5137 6.37904 11.4187 6.27753C11.4719 6.83232 11.5 7.40867 11.5 8C11.5 8.59133 11.4719 9.16768 11.4187 9.72246ZM10.1525 6.18401C10.2157 6.75982 10.25 7.36805 10.25 8C10.25 8.63195 10.2157 9.24018 10.1525 9.81598C9.46123 9.85455 8.7409 9.875 8 9.875C7.25909 9.875 6.53877 9.85455 5.84749 9.81598C5.7843 9.24018 5.75 8.63195 5.75 8C5.75 7.36805 5.7843 6.75982 5.84749 6.18401C6.53877 6.14545 7.25909 6.125 8 6.125C8.74091 6.125 9.46123 6.14545 10.1525 6.18401ZM11.2469 5.00748C12.2138 5.08891 13.1191 5.20593 13.9384 5.35306C13.2303 3.7667 11.9051 2.51622 10.268 1.90662C10.695 2.73788 11.0336 3.79953 11.2469 5.00748ZM8.48347 1.51771C8.4868 1.52089 8.49016 1.52411 8.49353 1.52737C8.7585 1.78353 9.05422 2.21456 9.32968 2.84417C9.58406 3.42562 9.80021 4.12856 9.95899 4.92219C9.32395 4.89118 8.66896 4.875 8 4.875C7.33104 4.875 6.67605 4.89118 6.04101 4.92219C6.19978 4.12856 6.41594 3.42562 6.67032 2.84417C6.94578 2.21456 7.2415 1.78353 7.50647 1.52737C7.50984 1.52411 7.51319 1.52089 7.51653 1.51771C7.67615 1.50597 7.83738 1.5 8 1.5C8.16262 1.5 8.32384 1.50597 8.48347 1.51771ZM5.73202 1.90663C4.0949 2.51622 2.76975 3.7667 2.06159 5.35306C2.88085 5.20593 3.78617 5.08891 4.75309 5.00748C4.96639 3.79953 5.30497 2.73788 5.73202 1.90663ZM4.58133 6.27753C3.48633 6.37904 2.48837 6.52755 1.62761 6.71194C1.54392 7.12828 1.5 7.55901 1.5 8C1.5 8.44099 1.54392 8.87172 1.62761 9.28806C2.48837 9.47245 3.48633 9.62096 4.58133 9.72246C4.52807 9.16768 4.5 8.59133 4.5 8C4.5 7.40867 4.52807 6.83232 4.58133 6.27753ZM4.75309 10.9925C3.78617 10.9111 2.88085 10.7941 2.06159 10.6469C2.76975 12.2333 4.0949 13.4838 5.73202 14.0934C5.30497 13.2621 4.96639 12.2005 4.75309 10.9925Z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- link -->
|
||||
<symbol id="link" viewBox="0 0 16 16">
|
||||
<path d="M8.46968 1.46968C10.1433 -0.203925 12.8567 -0.203923 14.5303 1.46968C16.2039 3.14329 16.2039 5.85674 14.5303 7.53034L12.0303 10.0303L10.9697 8.96968L13.4697 6.46968C14.5575 5.38186 14.5575 3.61816 13.4697 2.53034C12.3819 1.44252 10.6182 1.44252 9.53034 2.53034L7.03034 5.03034L5.96968 3.96968L8.46968 1.46968ZM11.5303 5.53034L5.53034 11.5303L4.46968 10.4697L10.4697 4.46968L11.5303 5.53034ZM1.46968 14.5303C3.14329 16.2039 5.85673 16.204 7.53034 14.5303L10.0303 12.0303L8.96968 10.9697L6.46968 13.4697C5.38186 14.5575 3.61816 14.5575 2.53034 13.4697C1.44252 12.3819 1.44252 10.6182 2.53034 9.53034L5.03034 7.03034L3.96968 5.96968L1.46968 8.46968C-0.203923 10.1433 -0.203925 12.8567 1.46968 14.5303Z"/>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
44
src/components/ArrowCard.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { formatDate } from "@lib/utils"
|
||||
import type { CollectionEntry } from "astro:content"
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<"blog"> | CollectionEntry<"projects">
|
||||
pill?: boolean
|
||||
}
|
||||
|
||||
export default function ArrowCard({entry, pill}: Props) {
|
||||
return (
|
||||
<a href={`/${entry.collection}/${entry.slug}`} class="group p-4 gap-3 flex items-center border rounded-lg hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 transition-colors duration-300 ease-in-out">
|
||||
<div class="w-full group-hover:text-black group-hover:dark:text-white blend">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
{pill &&
|
||||
<div class="text-sm capitalize px-2 py-0.5 rounded-full border border-black/15 dark:border-white/25">
|
||||
{entry.collection === "blog" ? "post" : "project"}
|
||||
</div>
|
||||
}
|
||||
<div class="text-sm uppercase">
|
||||
{formatDate(entry.data.date)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="font-semibold mt-3 text-black dark:text-white">
|
||||
{entry.data.title}
|
||||
</div>
|
||||
|
||||
<div class="text-sm line-clamp-2">
|
||||
{entry.data.summary}
|
||||
</div>
|
||||
<ul class="flex flex-wrap mt-2 gap-1">
|
||||
{entry.data.tags.map((tag:string) => ( // this line has an error; Parameter 'tag' implicitly has an 'any' type.ts(7006)
|
||||
<li class="text-xs uppercase py-0.5 px-1 rounded bg-black/5 dark:bg-white/20 text-black/75 dark:text-white/75">
|
||||
{tag}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white">
|
||||
<line x1="5" y1="12" x2="19" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-4 group-hover:translate-x-1 transition-all duration-300 ease-in-out" />
|
||||
<polyline points="12 5 19 12 12 19" class="translate-x-0 group-hover:translate-x-1 transition-all duration-300 ease-in-out" />
|
||||
</svg>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
68
src/components/BaseHead.astro
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
import { ViewTransitions } from "astro:transitions"
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
description: string
|
||||
image?: string
|
||||
}
|
||||
|
||||
const canonicalURL = new URL(Astro.url.pathname, Astro.site)
|
||||
|
||||
const { title, description, image = "/open-graph.jpg" } = Astro.props
|
||||
---
|
||||
|
||||
<!-- Global Metadata -->
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
<link rel="preload" href="/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin>
|
||||
<link rel="preload" href="/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin>
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>{title}</title>
|
||||
<meta name="title" content={title} />
|
||||
<meta name="description" content={description} />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={Astro.url} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={new URL(image, Astro.url)} />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content={Astro.url} />
|
||||
<meta property="twitter:title" content={title} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
||||
|
||||
<!-- Sitemap -->
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
|
||||
<!-- RSS Feed -->
|
||||
<link rel="alternate" type="application/rss+xml" title={title} href={`${Astro.site}rss.xml`}/>
|
||||
|
||||
<!-- Global Scripts -->
|
||||
<script is:inline src="/js/theme.js"></script>
|
||||
<script is:inline src="/js/scroll.js"></script>
|
||||
<script is:inline src="/js/animate.js"></script>
|
||||
|
||||
<!-- <ViewTransitions /> -->
|
||||
|
||||
<script>
|
||||
import type { TransitionBeforeSwapEvent } from "astro:transitions/client"
|
||||
document.addEventListener("astro:before-swap", (e) =>
|
||||
[
|
||||
...(e as TransitionBeforeSwapEvent).newDocument.head.querySelectorAll(
|
||||
"link[as=\"font\"]"
|
||||
),
|
||||
].forEach((link) => link.remove())
|
||||
)
|
||||
</script>
|
||||
72
src/components/Blog.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { CollectionEntry } from "astro:content"
|
||||
import { createEffect, createSignal, For } from "solid-js"
|
||||
import ArrowCard from "@components/ArrowCard"
|
||||
import { cn } from "@lib/utils"
|
||||
|
||||
type Props = {
|
||||
tags: string[]
|
||||
data: CollectionEntry<"blog">[]
|
||||
}
|
||||
|
||||
export default function Blog({ data, tags }: Props) {
|
||||
const [filter, setFilter] = createSignal(new Set<string>())
|
||||
const [posts, setPosts] = createSignal<CollectionEntry<"blog">[]>([])
|
||||
|
||||
createEffect(() => {
|
||||
setPosts(data.filter((entry) =>
|
||||
Array.from(filter()).every((value) =>
|
||||
entry.data.tags.some((tag:string) =>
|
||||
tag.toLowerCase() === String(value).toLowerCase()
|
||||
)
|
||||
)
|
||||
))
|
||||
})
|
||||
|
||||
function toggleTag(tag: string) {
|
||||
setFilter((prev) =>
|
||||
new Set(prev.has(tag)
|
||||
? [...prev].filter((t) => t !== tag)
|
||||
: [...prev, tag]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
||||
<div class="col-span-3 sm:col-span-1">
|
||||
<div class="sticky top-24">
|
||||
<div class="text-sm font-semibold uppercase mb-2 text-black dark:text-white">Filter</div>
|
||||
<ul class="flex flex-wrap sm:flex-col gap-1.5">
|
||||
<For each={tags}>
|
||||
{(tag) => (
|
||||
<li>
|
||||
<button onClick={() => toggleTag(tag)} class={cn("w-full px-2 py-1 rounded", "whitespace-nowrap overflow-hidden overflow-ellipsis", "flex gap-2 items-center", "bg-black/5 dark:bg-white/10", "hover:bg-black/10 hover:dark:bg-white/15", "transition-colors duration-300 ease-in-out", filter().has(tag) && "text-black dark:text-white")}>
|
||||
<svg class={cn("size-5 fill-black/50 dark:fill-white/50", "transition-colors duration-300 ease-in-out", filter().has(tag) && "fill-black dark:fill-white")}>
|
||||
<use href={`/ui.svg#square`} class={cn(!filter().has(tag) ? "block" : "hidden")} />
|
||||
<use href={`/ui.svg#square-check`} class={cn(filter().has(tag) ? "block" : "hidden")} />
|
||||
</svg>
|
||||
{tag}
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2">
|
||||
<div class="flex flex-col">
|
||||
<div class="text-sm uppercase mb-2">
|
||||
SHOWING {posts().length} OF {data.length} POSTS
|
||||
</div>
|
||||
<ul class="flex flex-col gap-3">
|
||||
{posts().map((post) => (
|
||||
<li>
|
||||
<ArrowCard entry={post} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
20
src/components/Container.astro
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
import { cn } from "@lib/utils"
|
||||
|
||||
type Props = {
|
||||
size: "sm" | "md" | "lg" | "xl" | "2xl"
|
||||
}
|
||||
|
||||
const { size } = Astro.props;
|
||||
---
|
||||
|
||||
<div class={cn(
|
||||
"w-full h-full mx-auto px-5",
|
||||
size === "sm" && "max-w-screen-sm",
|
||||
size === "md" && "max-w-screen-md",
|
||||
size === "lg" && "max-w-screen-lg",
|
||||
size === "xl" && "max-w-screen-xl",
|
||||
size === "2xl" && "max-w-screen-2xl",
|
||||
)}>
|
||||
<slot/>
|
||||
</div>
|
||||
21
src/components/Counter.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { createSignal } from "solid-js"
|
||||
|
||||
function CounterButton() {
|
||||
const [count, setCount] = createSignal(0)
|
||||
|
||||
const increment = () => setCount(count() + 1)
|
||||
|
||||
return (
|
||||
<div class="flex gap-4 items-center">
|
||||
<button onClick={increment} class="px-3 py-1 border border-black/25 dark:border-white/25 hover:bg-black/5 dark:hover:bg-white/15 blend">
|
||||
Increment
|
||||
</button>
|
||||
<div>
|
||||
Clicked {count()} {count() === 1 ? "time" : "times"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default CounterButton
|
||||
47
src/components/Drawer.astro
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
import { SITE, LINKS } from "@consts"
|
||||
import { cn } from "@lib/utils"
|
||||
const { pathname } = Astro.url
|
||||
const subpath = pathname.match(/[^/]+/g)
|
||||
---
|
||||
|
||||
<div id="drawer" class="fixed inset-0 h-0 z-40 overflow-hidden flex flex-col items-center justify-center md:hidden bg-neutral-100 dark:bg-neutral-900 transition-[height] duration-300 ease-in-out">
|
||||
<nav class="flex flex-col items-center space-y-2">
|
||||
{
|
||||
LINKS.map((LINK) => (
|
||||
<a href={LINK.HREF} class={cn("flex items-center justify-center px-3 py-1 rounded-full", "text-current hover:text-black dark:hover:text-white", "hover:bg-black/5 dark:hover:bg-white/20", "transition-colors duration-300 ease-in-out", pathname === LINK.HREF || "/" + subpath?.[0] === LINK.HREF ? "pointer-events-none bg-black dark:bg-white text-white dark:text-black" : "")}>
|
||||
{LINK.TEXT}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
|
||||
<div class="flex gap-1 mt-5">
|
||||
<a href="/search" aria-label={`Search blog posts and projects on ${SITE.TITLE}`} class={cn("size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out", pathname === "/search" || "/" + subpath?.[0] === "search" ? "pointer-events-none bg-black dark:bg-white text-white dark:text-black" : "")}>
|
||||
<svg class="size-full">
|
||||
<use href="/ui.svg#search"></use>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a href="/rss.xml" target="_blank" aria-label={`Rss feed for ${SITE.TITLE}`} class="size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out">
|
||||
<svg class="size-full">
|
||||
<use href="/ui.svg#rss"></use>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<button id="drawer-theme-button" aria-label={`Toggle light and dark theme`} class="size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out">
|
||||
<svg class="block dark:hidden size-full">
|
||||
<use href="/ui.svg#sun"></use>
|
||||
</svg>
|
||||
<svg class="hidden dark:block size-full">
|
||||
<use href="/ui.svg#moon"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#drawer.open {
|
||||
@apply h-full;
|
||||
}
|
||||
</style>
|
||||
104
src/components/Footer.astro
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
import { SITE, SOCIALS } from "@consts"
|
||||
import Container from "@components/Container.astro"
|
||||
---
|
||||
|
||||
<footer class="relative bg-white dark:bg-black">
|
||||
<div class="animate">
|
||||
<section class="py-5">
|
||||
<Container size="md">
|
||||
<div class="flex items-center justify-center sm:justify-end">
|
||||
<button id="back-to-top" aria-label="Back to top of page" class="group flex w-fit p-1.5 gap-1.5 text-sm items-center border rounded hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 transition-colors duration-300 ease-in-out">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white rotate-90">
|
||||
<line x1="19" y1="12" x2="5" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-3 group-hover:translate-x-0 transition-all duration-300 ease-in-out" />
|
||||
<polyline points="12 19 5 12 12 5" class="translate-x-1 group-hover:translate-x-0 transition-all duration-300 ease-in-out" />
|
||||
</svg>
|
||||
<div class="w-full group-hover:text-black group-hover:dark:text-white transition-colors duration-300 ease-in-out">
|
||||
В начало
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<section class=" py-5 overflow-hidden whitespace-nowrap border-t border-black/10 dark:border-white/25">
|
||||
<Container size="md">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<div class="flex flex-col items-center sm:items-start">
|
||||
<a href="/" class="flex gap-1 w-fit font-semibold text-current hover:text-black dark:hover:text-white transition-colors duration-300 ease-in-out">
|
||||
<svg class="size-6 fill-current">
|
||||
<use href="/brand.svg#brand"/>
|
||||
</svg>
|
||||
{SITE.TITLE}
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex gap-2 justify-center sm:justify-end items-center">
|
||||
<span class="relative flex h-3 w-3">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-300"></span>
|
||||
<span class="relative inline-flex rounded-full h-3 w-3 bg-green-500"></span>
|
||||
</span>
|
||||
Все системы в норме
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<section class=" py-5 overflow-hidden whitespace-nowrap border-t border-black/10 dark:border-white/25">
|
||||
<Container size="md">
|
||||
<div class="h-full grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<div class="order-2 sm:order-1 flex flex-col items-center justify-center sm:items-start">
|
||||
<div class="legal">
|
||||
<a href="/legal/terms" class="text-current hover:text-black dark:hover:text-white transition-colors duration-300 ease-in-out">
|
||||
Условия использования
|
||||
</a> |
|
||||
<a href="/legal/privacy" class="text-current hover:text-black dark:hover:text-white transition-colors duration-300 ease-in-out">
|
||||
Конфиденциальности
|
||||
</a>
|
||||
</div>
|
||||
<div class="text-sm mt-2">
|
||||
© 2024 | @iTKeyS
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-1 sm:order-2 flex justify-center sm:justify-end">
|
||||
<div class="flex flex-wrap gap-1 items-center justify-center">
|
||||
{
|
||||
SOCIALS.map((SOCIAL) => (
|
||||
<a
|
||||
href={SOCIAL.HREF}
|
||||
target="_blank"
|
||||
aria-label={`${SITE.TITLE} on ${SOCIAL.NAME}`}
|
||||
class="group size-10 rounded-full p-2 items-center justify-center hover:bg-black/5 dark:hover:bg-white/20 blend"
|
||||
>
|
||||
<svg class="size-full fill-current group-hover:fill-black group-hover:dark:fill-white blend">
|
||||
<use href={`/social.svg#${SOCIAL.ICON}`} />
|
||||
</svg>
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
|
||||
<script is:inline>
|
||||
function goBackToTop(event) {
|
||||
event.preventDefault()
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: "smooth"
|
||||
})
|
||||
}
|
||||
|
||||
function inintializeBackToTop() {
|
||||
const backToTop = document.getElementById("back-to-top")
|
||||
backToTop?.addEventListener("click", goBackToTop)
|
||||
}
|
||||
|
||||
document.addEventListener("astro:after-swap", inintializeBackToTop)
|
||||
inintializeBackToTop()
|
||||
</script>
|
||||
103
src/components/Header.astro
Normal file
@@ -0,0 +1,103 @@
|
||||
---
|
||||
import { SITE, LINKS } from "@consts"
|
||||
import { cn } from "@lib/utils"
|
||||
const { pathname } = Astro.url
|
||||
const subpath = pathname.match(/[^/]+/g)
|
||||
import Container from "@components/Container.astro"
|
||||
---
|
||||
|
||||
<header id="header" class="fixed top-0 w-full h-16 z-50 ">
|
||||
<Container size="md">
|
||||
<div class="relative h-full w-full">
|
||||
<div class="absolute left-0 top-1/2 -translate-y-1/2 flex gap-1 font-semibold">
|
||||
<a href="/" class="flex gap-1 text-current hover:text-black dark:hover:text-white transition-colors duration-300 ease-in-out">
|
||||
<svg class="size-6 fill-current">
|
||||
<use href="/brand.svg#brand"></use>
|
||||
</svg>
|
||||
<div>
|
||||
{SITE.TITLE}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<nav class="hidden md:flex items-center justify-center text-sm gap-1">
|
||||
{
|
||||
LINKS.map((LINK) => (
|
||||
<a href={LINK.HREF} class={cn("h-8 rounded-full px-3 text-current", "flex items-center justify-center", "transition-colors duration-300 ease-in-out", pathname === LINK.HREF || "/" + subpath?.[0] === LINK.HREF ? "bg-black dark:bg-white text-white dark:text-black" : "hover:bg-black/5 dark:hover:bg-white/20 hover:text-black dark:hover:text-white")}>
|
||||
{LINK.TEXT}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="buttons absolute right-0 top-1/2 -translate-y-1/2 flex gap-1">
|
||||
<a href="/search" aria-label={`Search blog posts and projects on ${SITE.TITLE}`} class={cn("hidden md:flex", "size-9 rounded-full p-2 items-center justify-center", "bg-transparent hover:bg-black/5 dark:hover:bg-white/20", "stroke-current hover:stroke-black hover:dark:stroke-white", "border border-black/10 dark:border-white/25", "transition-colors duration-300 ease-in-out", pathname === "/search" || "/" + subpath?.[0] === "/search" ? "pointer-events-none bg-black dark:bg-white text-white dark:text-black" : "")}>
|
||||
<svg class="size-full">
|
||||
<use href="/ui.svg#search"></use>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a href="/rss.xml" target="_blank" aria-label={`Rss feed for ${SITE.TITLE}`} class={cn("hidden md:flex", "size-9 rounded-full p-2 items-center justify-center", "bg-transparent hover:bg-black/5 dark:hover:bg-white/20", "stroke-current hover:stroke-black hover:dark:stroke-white", "border border-black/10 dark:border-white/25", "transition-colors duration-300 ease-in-out")}>
|
||||
<svg class="size-full">
|
||||
<use href="/ui.svg#rss"></use>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<button id="header-theme-button" aria-label={`Toggle light and dark theme`} class={cn("hidden md:flex", "size-9 rounded-full p-2 items-center justify-center", "bg-transparent hover:bg-black/5 dark:hover:bg-white/20", "stroke-current hover:stroke-black hover:dark:stroke-white", "border border-black/10 dark:border-white/25", "transition-colors duration-300 ease-in-out")}>
|
||||
<svg class="size-full block dark:hidden">
|
||||
<use href="/ui.svg#sun"></use>
|
||||
</svg>
|
||||
<svg class="size-full hidden dark:block">
|
||||
<use href="/ui.svg#moon"></use>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button id="header-drawer-button" aria-label={`Toggle drawer open and closed`} class={cn("flex md:hidden", "size-9 rounded-full p-2 items-center justify-center", "bg-transparent hover:bg-black/5 dark:hover:bg-white/20", "stroke-current hover:stroke-black hover:dark:stroke-white", "border border-black/10 dark:border-white/25", "transition-colors duration-300 ease-in-out")}>
|
||||
<svg id="drawer-open" class="size-full">
|
||||
<use href="/ui.svg#menu"></use>
|
||||
</svg>
|
||||
<svg id="drawer-close" class="size-full">
|
||||
<use href="/ui.svg#x"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</header>
|
||||
|
||||
<style>
|
||||
#header-drawer-button > #drawer-open {
|
||||
@apply block;
|
||||
}
|
||||
|
||||
#header-drawer-button > #drawer-close {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
#header-drawer-button.open > #drawer-open {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
#header-drawer-button.open > #drawer-close {
|
||||
@apply block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script is:inline>
|
||||
function toggleDrawer() {
|
||||
const drawer = document.getElementById("drawer")
|
||||
const drawerButton = document.getElementById("header-drawer-button")
|
||||
drawer?.classList.toggle("open")
|
||||
drawerButton?.classList.toggle("open")
|
||||
}
|
||||
|
||||
function initializeDrawerButton() {
|
||||
const drawerButton = document.getElementById("header-drawer-button")
|
||||
drawerButton?.addEventListener("click", toggleDrawer)
|
||||
}
|
||||
|
||||
document.addEventListener("astro:after-swap", initializeDrawerButton)
|
||||
initializeDrawerButton()
|
||||
</script>
|
||||
42
src/components/MeteorShower.astro
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
/**
|
||||
* Meteors.astro
|
||||
* This component creates meteors that are appended to the galaxy on interval.
|
||||
* Meteors are removed from the document after the animation is completed.
|
||||
* There are four (4) meteor shower containers, one for each diagonal direction.
|
||||
*/
|
||||
---
|
||||
|
||||
<div id="meteors">
|
||||
<!-- rotations defined in base.css & tailwind.config.mjs -->
|
||||
<div class="shower ur" />
|
||||
<div class="shower dr" />
|
||||
<div class="shower dl" />
|
||||
<div class="shower ul" />
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function createMeteor () {
|
||||
// create a meteor
|
||||
let meteor = document.createElement("div");
|
||||
meteor.setAttribute("class", "meteor");
|
||||
meteor.style.left = Math.round(Math.random() * window.innerWidth) + "px";
|
||||
meteor.style.top = Math.round(Math.random() * window.innerHeight) + "px";
|
||||
|
||||
// append the meteor to a random meteor shower (direction)
|
||||
const showers = document.querySelectorAll(".shower");
|
||||
if (showers.length > 0) {
|
||||
const random = Math.floor(Math.random() * showers.length);
|
||||
const shower = showers[random];
|
||||
shower.append(meteor);
|
||||
}
|
||||
|
||||
// remove the meteor after the animation duration
|
||||
setTimeout(() => {
|
||||
meteor.remove();
|
||||
}, 3500);
|
||||
}
|
||||
|
||||
// Create meteors on interval on two (2) seconds
|
||||
setInterval(createMeteor, 1500);
|
||||
</script>
|
||||
72
src/components/Projects.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { CollectionEntry } from "astro:content"
|
||||
import { createEffect, createSignal, For } from "solid-js"
|
||||
import ArrowCard from "@components/ArrowCard"
|
||||
import { cn } from "@lib/utils"
|
||||
|
||||
type Props = {
|
||||
tags: string[]
|
||||
data: CollectionEntry<"projects">[]
|
||||
}
|
||||
|
||||
export default function Projects({ data, tags }: Props) {
|
||||
const [filter, setFilter] = createSignal(new Set<string>())
|
||||
const [projects, setProjects] = createSignal<CollectionEntry<"projects">[]>([])
|
||||
|
||||
createEffect(() => {
|
||||
setProjects(data.filter((entry) =>
|
||||
Array.from(filter()).every((value) =>
|
||||
entry.data.tags.some((tag:string) =>
|
||||
tag.toLowerCase() === String(value).toLowerCase()
|
||||
)
|
||||
)
|
||||
))
|
||||
})
|
||||
|
||||
function toggleTag(tag: string) {
|
||||
setFilter((prev) =>
|
||||
new Set(prev.has(tag)
|
||||
? [...prev].filter((t) => t !== tag)
|
||||
: [...prev, tag]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
||||
<div class="col-span-3 sm:col-span-1">
|
||||
<div class="sticky top-24">
|
||||
<div class="text-sm font-semibold uppercase mb-2 text-black dark:text-white">Filter</div>
|
||||
<ul class="flex flex-wrap sm:flex-col gap-1.5">
|
||||
<For each={tags}>
|
||||
{(tag) => (
|
||||
<li>
|
||||
<button onClick={() => toggleTag(tag)} class={cn("w-full px-2 py-1 rounded", "whitespace-nowrap overflow-hidden overflow-ellipsis", "flex gap-2 items-center", "bg-black/5 dark:bg-white/10", "hover:bg-black/10 hover:dark:bg-white/15", "transition-colors duration-300 ease-in-out", filter().has(tag) && "text-black dark:text-white")}>
|
||||
<svg class={cn("size-5 fill-black/50 dark:fill-white/50", "transition-colors duration-300 ease-in-out", filter().has(tag) && "fill-black dark:fill-white")}>
|
||||
<use href={`/ui.svg#square`} class={cn(!filter().has(tag) ? "block" : "hidden")} />
|
||||
<use href={`/ui.svg#square-check`} class={cn(filter().has(tag) ? "block" : "hidden")} />
|
||||
</svg>
|
||||
{tag}
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2">
|
||||
<div class="flex flex-col">
|
||||
<div class="text-sm uppercase mb-2">
|
||||
SHOWING {projects().length} OF {data.length} PROJECTS
|
||||
</div>
|
||||
<ul class="flex flex-col gap-3">
|
||||
{projects().map((project) => (
|
||||
<li>
|
||||
<ArrowCard entry={project} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
58
src/components/Search.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { CollectionEntry } from "astro:content"
|
||||
import { createEffect, createSignal } from "solid-js"
|
||||
import Fuse from "fuse.js"
|
||||
import ArrowCard from "@components/ArrowCard"
|
||||
|
||||
type Props = {
|
||||
data: CollectionEntry<"blog">[]
|
||||
}
|
||||
|
||||
export default function Search({data}: Props) {
|
||||
const [query, setQuery] = createSignal("")
|
||||
const [results, setResults] = createSignal<CollectionEntry<"blog">[]>([])
|
||||
|
||||
const fuse = new Fuse(data, {
|
||||
keys: ["slug", "data.title", "data.summary", "data.tags"],
|
||||
includeMatches: true,
|
||||
minMatchCharLength: 2,
|
||||
threshold: 0.4,
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (query().length < 2) {
|
||||
setResults([])
|
||||
} else {
|
||||
setResults(fuse.search(query()).map((result) => result.item))
|
||||
}
|
||||
})
|
||||
|
||||
const onInput = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement
|
||||
setQuery(target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="flex flex-col">
|
||||
<div class="relative">
|
||||
<input name="search" type="text" value={query()} onInput={onInput} autocomplete="off" spellcheck={false} placeholder="What are you looking for?" class="w-full px-2.5 py-1.5 pl-10 rounded outline-none text-black dark:text-white bg-black/5 dark:bg-white/15 border border-black/10 dark:border-white/20 focus:border-black focus:dark:border-white"/>
|
||||
<svg class="absolute size-6 left-1.5 top-1/2 -translate-y-1/2 stroke-current">
|
||||
<use href={`/ui.svg#search`}/>
|
||||
</svg>
|
||||
</div>
|
||||
{(query().length >= 2 && results().length >= 1) && (
|
||||
<div class="mt-12">
|
||||
<div class="text-sm uppercase mb-2">
|
||||
Found {results().length} results for {`'${query()}'`}
|
||||
</div>
|
||||
<ul class="flex flex-col gap-3">
|
||||
{results().map(result => (
|
||||
<li>
|
||||
<ArrowCard entry={result} pill={true} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
18
src/components/StackCard.astro
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
type Props = {
|
||||
text: string
|
||||
icon: string
|
||||
href: string
|
||||
}
|
||||
|
||||
const { text, icon, href } = Astro.props
|
||||
---
|
||||
|
||||
<a href={href} target="_blank" class="w-fit px-3 py-2 group rounded border flex gap-2 items-center border-neutral-200 dark:border-neutral-700 hover:bg-neutral-100 hover:dark:bg-neutral-800 blend">
|
||||
<svg height={20} width={20}>
|
||||
<use href={`/stack.svg#${icon}`}></use>
|
||||
</svg>
|
||||
<span class="text-sm capitalize text-neutral-500 dark:text-neutral-400 group-hover:text-black group-hover:dark:text-white blend">
|
||||
{text}
|
||||
</span>
|
||||
</a>
|
||||
62
src/components/TwinklingStars.astro
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
/**
|
||||
* TwinkleStars.astro
|
||||
* This component creates twinkling stars that are appended to the galaxy on interval.
|
||||
* Twinkle stars are removed from the document after the animation is completed.
|
||||
* The svg below is just a template for the script to clone and append to the galaxy.
|
||||
*/
|
||||
---
|
||||
|
||||
<svg
|
||||
id="twinkle-star"
|
||||
class="template"
|
||||
width="149"
|
||||
height="149"
|
||||
viewBox="0 0 149 149"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="absolute left-full animate-twinkle"
|
||||
>
|
||||
<circle cx="74" cy="74" r="11" fill="white"/>
|
||||
<rect y="141.421" width="200" height="10" transform="rotate(-45 0 141.421)" fill="url(#paint0_linear_4_2)"/>
|
||||
<rect x="7.07107" width="200" height="10" transform="rotate(45 7.07107 0)" fill="url(#paint1_linear_4_2)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_4_2" x1="0" y1="146.421" x2="200" y2="146.421" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1E1E1E"/>
|
||||
<stop offset="0.445" stop-color="white"/>
|
||||
<stop offset="0.58721" stop-color="white"/>
|
||||
<stop offset="1" stop-color="#1E1E1E"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_4_2" x1="7.07107" y1="5" x2="207.071" y2="5" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1E1E1E"/>
|
||||
<stop offset="0.42" stop-color="white"/>
|
||||
<stop offset="0.555" stop-color="white"/>
|
||||
<stop offset="1" stop-color="#1E1E1E"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<script is:inline>
|
||||
// Generate a twinkle star and append it to the galaxy, remove it after animation.
|
||||
function generateTwinkleStar() {
|
||||
const twinkleStarTemplate = document.getElementById("twinkle-star")
|
||||
if (!twinkleStarTemplate) { return; }
|
||||
// Clone the twinkle star template and set its attributes.
|
||||
const twinkleStar = twinkleStarTemplate.cloneNode(true);
|
||||
twinkleStar.style.position = "absolute";
|
||||
twinkleStar.style.left = Math.floor(Math.random() * window.innerWidth) + "px";
|
||||
twinkleStar.style.top = Math.floor(Math.random() * (window.innerHeight/3)) + "px";
|
||||
twinkleStar.style.width = window.innerWidth < 768 ? Math.floor(Math.random() * (15 - 7.5 + 1) + 7.5) : Math.floor(Math.random() * (30 - 15 + 1) + 15) + "px";
|
||||
twinkleStar.style.height = twinkleStar.style.width;
|
||||
twinkleStar.classList.add("twinkle");
|
||||
document.getElementById("galaxy").appendChild(twinkleStar);
|
||||
|
||||
// Remove the twinkle star after the animation is completed.
|
||||
setTimeout(() => {
|
||||
twinkleStar.remove();
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
setInterval(generateTwinkleStar, 5000);
|
||||
</script>
|
||||
|
||||
87
src/consts.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import type { Site, Page, Links, Socials } from "@types"
|
||||
|
||||
// Global
|
||||
export const SITE: Site = {
|
||||
TITLE: "Плата Управления РФ",
|
||||
DESCRIPTION: "Время пришло! Для новых горизонтов возможностей!",
|
||||
AUTHOR: "iTKeyS",
|
||||
}
|
||||
|
||||
// Work Page
|
||||
export const WORK: Page = {
|
||||
TITLE: "Работа",
|
||||
DESCRIPTION: "Сдесь мы собираем задачи которые можем и возможно будем решать.",
|
||||
}
|
||||
|
||||
// Blog Page
|
||||
export const BLOG: Page = {
|
||||
TITLE: "Блог",
|
||||
DESCRIPTION: "В этом разделе мы рассказываем о ходе наших работ.",
|
||||
}
|
||||
|
||||
// Projects Page
|
||||
export const PROJECTS: Page = {
|
||||
TITLE: "Проекты",
|
||||
DESCRIPTION: "Этот раздел уже готовых комплексных задач с подробным описанием.",
|
||||
}
|
||||
|
||||
// Search Page
|
||||
export const SEARCH: Page = {
|
||||
TITLE: "Поиск",
|
||||
DESCRIPTION: "Поиск постов во вкладке проекты.",
|
||||
}
|
||||
|
||||
// Links
|
||||
export const LINKS: Links = [
|
||||
{
|
||||
TEXT: "Главная",
|
||||
HREF: "/",
|
||||
},
|
||||
{
|
||||
TEXT: "Работа",
|
||||
HREF: "/work",
|
||||
},
|
||||
{
|
||||
TEXT: "Блог",
|
||||
HREF: "/blog",
|
||||
},
|
||||
{
|
||||
TEXT: "Проекты",
|
||||
HREF: "/projects",
|
||||
},
|
||||
]
|
||||
|
||||
// Socials
|
||||
export const SOCIALS: Socials = [
|
||||
{
|
||||
NAME: "Email",
|
||||
ICON: "email",
|
||||
TEXT: "krasilnikoff.tihon@gmail.com",
|
||||
HREF: "mailto:krasilnikoff.tihon@gmail.com",
|
||||
},
|
||||
{
|
||||
NAME: "Github",
|
||||
ICON: "github",
|
||||
TEXT: "Plata_Upravleniya_RF",
|
||||
HREF: "https://git.fipi.pro/Plata_Upravleniya_RF"
|
||||
},
|
||||
{
|
||||
NAME: "YouTube",
|
||||
ICON: "youtube",
|
||||
TEXT: "@plata_upravleniya_rf",
|
||||
HREF: "https://www.youtube.com/@plata_upravleniya_rf",
|
||||
},
|
||||
{
|
||||
NAME: "Telegram",
|
||||
ICON: "telegram",
|
||||
TEXT: "plata_upravleniya_rf",
|
||||
HREF: "https://t.me/plata_upravleniya_rf",
|
||||
},
|
||||
{
|
||||
NAME: "Telegram BOT",
|
||||
ICON: "telegram",
|
||||
TEXT: "plata_upravleniya_rf_BOT",
|
||||
HREF: "https://t.me/plata_upravleniya_rf_bot",
|
||||
}
|
||||
]
|
||||
|
||||
51
src/content/blog/01-astro-sphere-file-structure/index.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: "Astro Sphere: File Structure"
|
||||
summary: "You'll find these directories and files in the project. What do they do?"
|
||||
date: "Mar 17 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
|
||||
A one line summary of what each file and directory is for:
|
||||
```js
|
||||
/
|
||||
├── public/ // Files publicly available to the browser
|
||||
│ ├── fonts/ // The default fonts for Astro Sphere
|
||||
│ │ └── atkinson-bold.woff // default font weight 700
|
||||
│ │ └── atkinson-regular.woff // default font weight 400
|
||||
│ ├── js/ // Javascript that will be imported into <head>
|
||||
│ │ └── animate.js // function for animating page elements
|
||||
│ │ └── bg.js // function for generating the background
|
||||
│ │ └── scroll.js // scroll handler for the header styles
|
||||
│ │ └── theme.js // controls the light and dark theme
|
||||
│ └── brand.svg //the icon that displays in header and footer
|
||||
│ └── favicon.svg //the icon that displays in the browser
|
||||
│ └── ui.svg // an svg sprite for all ui icons on the website
|
||||
│ └── social.svg // an svg sprite for all social media icons
|
||||
│ └── open-graph.jpg // the default image for open-graph
|
||||
│ └── robots.txt // for web crawlers and bots to index the website
|
||||
├── src/ // Everything that will be built for the website
|
||||
│ ├── components/ // All astro and SolidJs components
|
||||
│ ├── content/ // Contains all static markdown to be compiled
|
||||
│ │ | blog/ // Contains all blog post markdown
|
||||
│ │ | projects/ // Contains all projects markdown
|
||||
│ │ | work/ // Contains all work page markdown
|
||||
│ │ | legal/ // Contains all legal docs markdown
|
||||
│ │ └── config.ts // Contains the collection config for Astro
|
||||
│ ├── layouts/ // Reused layouts across the website
|
||||
│ └── pages/ // All of the pages on the website
|
||||
│ └── styles/ // CSS and global tailwind styles
|
||||
│ └── lib/ // Global helper functions
|
||||
│ └── consts.ts // Page metadata, general configuration
|
||||
│ └── types.ts // Types for consts.ts
|
||||
└── .gitignore // Files and directories to be ignored by Git
|
||||
└── .eslintignore // Files and directories to be ignored by ESLint
|
||||
└── eslintrc.cjs // ESLint configuration
|
||||
└── astro.config.mjs // Astro configuration
|
||||
└── tailwind.config.mjs // Tailwind configuration
|
||||
└── tsconfig.json // Typescript configuration
|
||||
└── package.json // All the installed packages
|
||||
```
|
||||
90
src/content/blog/02-astro-sphere-getting-started/index.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: "Astro Sphere: Getting Started"
|
||||
summary: "You've downloaded and installed the project. Let's hit the ground running."
|
||||
date: "Mar 16 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
|
||||
Astro Sphere is designed to be configurable. This article will cover the basics on
|
||||
configuring the site and make it personal.
|
||||
|
||||
### First let's change the url
|
||||
|
||||
```js
|
||||
//astro.config.mjs
|
||||
|
||||
export default defineConfig({
|
||||
site: "https://astro-sphere.vercel.app", // your domain here
|
||||
integrations: [mdx(), sitemap(), solidJs(), tailwind({ applyBaseStyles: false })],
|
||||
})
|
||||
```
|
||||
|
||||
### Next, Let's configure the Site
|
||||
|
||||
```js
|
||||
// src/consts.ts
|
||||
|
||||
export const SITE: Site = {
|
||||
TITLE: "Astro Sphere",
|
||||
DESCRIPTION: "Welcome to Astro Sphere, a portfolio and blog for designers and developers.",
|
||||
AUTHOR: "Mark Horn",
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
| :---------- | :----- | :--------------------------------------------------------------------- |
|
||||
| TITLE | String | The title of the website. Displayed in header and footer. Used in SEO. |
|
||||
| DESCRIPTION | String | The description of the index page of the website. Used in SEO. |
|
||||
| AUTHOR | String | Your name. |
|
||||
|
||||
### Change the branding
|
||||
|
||||
The browser icon is located in `/public/favicon.svg`
|
||||
|
||||
The header and footer branding icon is located in `/public/brand.svg` as a sprite with id="brand"
|
||||
|
||||
### The rest of the consts file
|
||||
|
||||
Each page has a metadata entry that is useful for SEO.
|
||||
|
||||
```js
|
||||
export const WORK: Page = {
|
||||
TITLE: "Work",
|
||||
DESCRIPTION: "Places I have worked.",
|
||||
}
|
||||
```
|
||||
|
||||
The links that are displayed in the header and drawer
|
||||
|
||||
```js
|
||||
export const LINKS: Links = [
|
||||
{ HREF: "/", TEXT: "Home" },
|
||||
{ HREF: "/work", TEXT: "Work" },
|
||||
{ HREF: "/blog", TEXT: "Blog" },
|
||||
{ HREF: "/projects", TEXT: "Projects" },
|
||||
]
|
||||
```
|
||||
|
||||
The social media links
|
||||
|
||||
```js
|
||||
export const SOCIALS: Socials = [
|
||||
{
|
||||
NAME: "Github",
|
||||
ICON: "github",
|
||||
TEXT: "markhorn-dev",
|
||||
HREF: "https://github.com/markhorn-dev/astro-sphere"
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| :---- | :--- | :------- | :---------- |
|
||||
| NAME | string | yes | Accessible name |
|
||||
| ICON | string | yes | Refers to the symbol id in `public/social.svg` |
|
||||
| TEXT | string | yes | Shorthand profile name |
|
||||
| HREF | string | yes | The link to the social media profile |
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: "Astro Sphere: Adding a new post or project."
|
||||
summary: "Adding a new article (blog post or project) is pretty easy."
|
||||
date: "Mar 14 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
### Basics
|
||||
|
||||
Create a folder in the respective collection you wish to create content. The name of the folder will be the slug in which your content will be found.
|
||||
|
||||
```text
|
||||
creating the following
|
||||
|
||||
/content/blog/my-new-post/index.md
|
||||
|
||||
will be published to
|
||||
|
||||
https://yourdomain.com/blog/my-new-post
|
||||
|
||||
```
|
||||
|
||||
### Frontmatter
|
||||
|
||||
Front matter is in yaml if you are familiar with the format. All posts and projects require frontmatter at the top of the document to be imported. All frontmatter must be inside triple dashes, similar to Astro format. See example below.
|
||||
|
||||
### Blog Collection
|
||||
|
||||
| Field | Type | Req? | Description |
|
||||
| :------ | :------ | :--- | :------------------------------------------------------------ |
|
||||
| title | string | yes | Title of the post. Used in SEO. |
|
||||
| summary | string | yes | Short description of the post. Used in SEO. |
|
||||
| date | string | yes | Any string date that javascript can convert. Used in sorting |
|
||||
| tags | array | yes | Post topic. Array of strings. Used in filtering. |
|
||||
| draft | boolean | no | Hides the post from collections. Unpublished entry. |
|
||||
|
||||
Example blog post frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Astro Sphere: Adding a new post or project."
|
||||
summary: "Adding a new article (blog post or project) is pretty easy."
|
||||
date: "Mar 18 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
```
|
||||
|
||||
### Projects Collection (extends Blog Collection)
|
||||
|
||||
| Field | Type | Req? | Description |
|
||||
| :------ | :------ | :--- | :------------------------------------------------------------ |
|
||||
| title | string | yes | Title of the post. Used in SEO. |
|
||||
| summary | string | yes | Short description of the post. Used in SEO. |
|
||||
| date | string | yes | Any string date that javascript can convert. Used in sorting |
|
||||
| tags | array | yes | Post topic. Array of strings. Used in filtering. |
|
||||
| draft | boolean | no | Hides the post from collections. Unpublished entry. |
|
||||
| demoUrl | string | no | A link to the deployed project, if applicable. |
|
||||
| repoUrl | string | no | A link to the repository, if applicable. |
|
||||
|
||||
Example project frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Astro Sphere"
|
||||
summary: "Astro Sphere, a portfolio and blog for designers and developers."
|
||||
date: "Mar 18 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Astro
|
||||
- Typescript
|
||||
- Javascript
|
||||
- Tailwind
|
||||
- SolidJS
|
||||
demoUrl: https://astro-sphere.vercel.app
|
||||
repoUrl: https://github.com/markhorn-dev/astro-sphere
|
||||
---
|
||||
```
|
||||
|
||||
### Write your content
|
||||
You've made it this far, all that is left to do is write your content beneath the frontmatter. Writing markdown will be covered in the next article.
|
||||
236
src/content/blog/04-astro-sphere-writing-markdown/index.md
Normal file
@@ -0,0 +1,236 @@
|
||||
---
|
||||
title: "Astro Sphere: Writing Markdown"
|
||||
summary: "Basic Markdown syntax that can be used when writing Markdown content in Astro Sphere."
|
||||
date: "Mar 13 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
- Markdown
|
||||
---
|
||||
|
||||
### Headings
|
||||
|
||||
```text
|
||||
# H1
|
||||
|
||||
## H2
|
||||
|
||||
### H3
|
||||
|
||||
#### H4
|
||||
|
||||
##### H5
|
||||
|
||||
###### H6
|
||||
|
||||
```
|
||||
|
||||
# H1
|
||||
|
||||
## H2
|
||||
|
||||
### H3
|
||||
|
||||
#### H4
|
||||
|
||||
##### H5
|
||||
|
||||
###### H6
|
||||
|
||||
### Paragraph
|
||||
|
||||
Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.
|
||||
|
||||
Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.
|
||||
|
||||
### Images
|
||||
|
||||
Relative image in the /public folder
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
Relative Image in the same folder as the markdown
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
## Blockquotes
|
||||
|
||||
The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations.
|
||||
|
||||
### Blockquote without attribution
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
||||
> **Note** that you can use _Markdown syntax_ within a blockquote.
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
||||
> **Note** that you can use _Markdown syntax_ within a blockquote.
|
||||
|
||||
### Blockquote with attribution
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
> Don't communicate by sharing memory, share memory by communicating.<br>
|
||||
> — <cite>Rob Pike[^1]</cite>
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
> Don't communicate by sharing memory, share memory by communicating.<br>
|
||||
> — <cite>Rob Pike[^1]</cite>
|
||||
|
||||
[^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.
|
||||
|
||||
## Tables
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
| Italics | Bold | Code |
|
||||
| --------- | -------- | ------ |
|
||||
| _italics_ | **bold** | `code` |
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
| Italics | Bold | Code |
|
||||
| --------- | -------- | ------ |
|
||||
| _italics_ | **bold** | `code` |
|
||||
|
||||
## Code Blocks
|
||||
|
||||
#### Syntax
|
||||
|
||||
we can use 3 backticks ``` in new line and write snippet and close with 3 backticks on new line and to highlight language specific syntac, write one word of language name after first 3 backticks, for eg. html, javascript, css, markdown, typescript, txt, bash
|
||||
|
||||
````markdown
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
````
|
||||
|
||||
Output
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## List Types
|
||||
|
||||
### Ordered List
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
1. First item
|
||||
2. Second item
|
||||
3. Third item
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
1. First item
|
||||
2. Second item
|
||||
3. Third item
|
||||
|
||||
### Unordered List
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
- List item
|
||||
- Another item
|
||||
- And another item
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
- List item
|
||||
- Another item
|
||||
- And another item
|
||||
|
||||
### Nested list
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
- Fruit
|
||||
- Apple
|
||||
- Orange
|
||||
- Banana
|
||||
- Dairy
|
||||
- Milk
|
||||
- Cheese
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
- Fruit
|
||||
- Apple
|
||||
- Orange
|
||||
- Banana
|
||||
- Dairy
|
||||
- Milk
|
||||
- Cheese
|
||||
|
||||
## Other Elements — abbr, sub, sup, kbd, mark
|
||||
|
||||
#### Syntax
|
||||
|
||||
```markdown
|
||||
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
||||
|
||||
H<sub>2</sub>O
|
||||
|
||||
X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
|
||||
|
||||
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
|
||||
|
||||
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
||||
|
||||
H<sub>2</sub>O
|
||||
|
||||
X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
|
||||
|
||||
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
|
||||
|
||||
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
|
||||
BIN
src/content/blog/04-astro-sphere-writing-markdown/spongebob.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
@@ -0,0 +1,16 @@
|
||||
---
|
||||
type Props = {
|
||||
name: string
|
||||
}
|
||||
const { name } = Astro.props
|
||||
---
|
||||
|
||||
<div class="border p-4 bg-yellow-100 text-black">
|
||||
<div>
|
||||
Hello,
|
||||
<span class="font-semibold">
|
||||
{name}!!!
|
||||
</span>
|
||||
</div>
|
||||
<slot/>
|
||||
</div>
|
||||
53
src/content/blog/05-astro-sphere-writing-mdx/index.mdx
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: "Astro Sphere: Writing MDX"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 12 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
- Markdown
|
||||
- MDX
|
||||
---
|
||||
|
||||
MDX is a special flavor of Markdown that supports embedded JavaScript & JSX syntax. This unlocks the ability to [mix JavaScript and UI Components into your Markdown content](https://docs.astro.build/en/guides/markdown-content/#mdx-features) for things like interactive charts or alerts.
|
||||
|
||||
If you have existing content authored in MDX, this integration will hopefully make migrating to Astro a breeze.
|
||||
|
||||
## An astro component with props
|
||||
|
||||
```
|
||||
// Imported from relative path (same dir as markdown file)
|
||||
import MyComponent from "./MyComponent.astro"
|
||||
|
||||
<MyComponent name="You">
|
||||
Welcome to MDX
|
||||
</MyComponent>
|
||||
```
|
||||
|
||||
import MyComponent from "./MyComponent.astro"
|
||||
|
||||
<MyComponent name="You">
|
||||
Welcome to MDX
|
||||
</MyComponent>
|
||||
|
||||
|
||||
|
||||
## An interactive Solid Js component
|
||||
|
||||
```
|
||||
// Imported from components directory (src/components)
|
||||
import MyComponent from "@components/Counter"
|
||||
|
||||
// Don't forget the astro client:load directive
|
||||
<Counter client:load />
|
||||
```
|
||||
|
||||
import Counter from "@components/Counter"
|
||||
|
||||
<Counter client:load />
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
54
src/content/blog/06-astro-sphere-social-links/index.md
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: "Astro Sphere: Social media links"
|
||||
summary: "A quick tutorial on how to change, add or remove social media links"
|
||||
date: "Mar 11 2024"
|
||||
draft: false
|
||||
tags:
|
||||
- Tutorial
|
||||
- Astro
|
||||
- Astro Sphere
|
||||
---
|
||||
|
||||
Astro Sphere comes preconfigured with social media links for Email, Github, Linked In and Twitter (X), but it's very easy to add more.
|
||||
|
||||
### Edit `consts.ts`
|
||||
|
||||
```js
|
||||
// consts.ts
|
||||
|
||||
export const SOCIALS: Socials = [
|
||||
{
|
||||
NAME: "Github",
|
||||
ICON: "github",
|
||||
TEXT: "markhorn-dev",
|
||||
HREF: "https://github.com/markhorn-dev/astro-sphere"
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| :---- | :--- | :------- | :---------- |
|
||||
| NAME | string | yes | Accessible name |
|
||||
| ICON | string | yes | Refers to the symbol id in `public/social.svg` |
|
||||
| TEXT | string | yes | Shorthand profile name |
|
||||
| HREF | string | yes | The link to the social media profile |
|
||||
|
||||
### Edit /public/social.svg
|
||||
|
||||
Simply add your own symbols to the svg sprite.
|
||||
|
||||
It is recommended that all styles be removed from new symbols added, or they may not show up correctly or conflict with Tailwind's classes.
|
||||
|
||||
The id should match the icon field as specified in your `consts.ts` file.
|
||||
|
||||
```html
|
||||
<!-- public/social.svg -->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<symbol id="github" viewBox="0 0 496 512">
|
||||
<path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
```
|
||||
45
src/content/config.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { defineCollection, z } from "astro:content"
|
||||
|
||||
const work = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
company: z.string(),
|
||||
role: z.string(),
|
||||
dateStart: z.coerce.date(),
|
||||
dateEnd: z.union([z.coerce.date(), z.string()]),
|
||||
}),
|
||||
})
|
||||
|
||||
const blog = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
summary: z.string(),
|
||||
date: z.coerce.date(),
|
||||
tags: z.array(z.string()),
|
||||
draft: z.boolean().optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
const projects = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
summary: z.string(),
|
||||
date: z.coerce.date(),
|
||||
tags: z.array(z.string()),
|
||||
draft: z.boolean().optional(),
|
||||
demoUrl: z.string().optional(),
|
||||
repoUrl: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
const legal = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
date: z.coerce.date(),
|
||||
}),
|
||||
})
|
||||
|
||||
export const collections = { work, blog, projects, legal }
|
||||
28
src/content/legal/privacy.md
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: "Privacy Policy"
|
||||
date: "03/07/2024"
|
||||
---
|
||||
|
||||
This Privacy Policy governs the manner in which [Your Company Name] collects, uses, maintains, and discloses information collected from users (each, a "User") of the [Your Website URL] website ("Site"). This privacy policy applies to the Site and all products and services offered by [Your Company Name].
|
||||
|
||||
#### Personal identification information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Non-personal identification information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Web browser cookies
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### How we use collected information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### How we protect your information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Sharing your personal information
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Changes to this privacy policy
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
27
src/content/legal/terms.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: "Terms of Use"
|
||||
date: "03/07/2024"
|
||||
---
|
||||
|
||||
Please read these Terms of Use ("Terms", "Terms of Use") carefully before using the [Your Website URL] website (the "Service") operated by [Your Company Name] ("us", "we", or "our").
|
||||
|
||||
#### Agreement to Terms
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Intellectual Property Rights
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### User Representations
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Links to Other Websites
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Termination
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Governing Law
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
|
||||
#### Changes to These Terms of Use
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet massa ut neque consequat congue. Sed id ipsum vitae sem imperdiet suscipit. Nulla facilisi. Morbi quis nibh at nunc pulvinar rhoncus. Proin porttitor dapibus dolor, id fermentum urna eleifend et. In feugiat pretium erat nec vestibulum.
|
||||
16
src/content/projects/project-1/index.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "Project One"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 18 2022"
|
||||
draft: false
|
||||
tags:
|
||||
- Astro
|
||||
- Javascript
|
||||
- Typescript
|
||||
- Tailwind
|
||||
- SolidJs
|
||||
demoUrl: https://astro-sphere-demo.vercel.app
|
||||
repoUrl: https://github.com/markhorn-dev/astro-sphere
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
15
src/content/projects/project-2/index.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "Project Two"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 17 2022"
|
||||
draft: false
|
||||
tags:
|
||||
- Svelte
|
||||
- Sveltekit
|
||||
- Typescript
|
||||
- Tailwind
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
12
src/content/projects/project-3/index.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: "Project Three"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 16 2022"
|
||||
draft: false
|
||||
tags:
|
||||
- Vue
|
||||
- Javascript
|
||||
- Tailwind
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
31
src/content/projects/project-4/index.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: "Project Four"
|
||||
summary: "Lorem ipsum dolor sit amet"
|
||||
date: "Mar 15 2022"
|
||||
draft: false
|
||||
tags:
|
||||
- React
|
||||
- Javascript
|
||||
- StyleX
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium.
|
||||
|
||||
Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas.
|
||||
|
||||
Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem.
|
||||
Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium.
|
||||
|
||||
Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas.
|
||||
|
||||
Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem.
|
||||
Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium.
|
||||
|
||||
Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas.
|
||||
|
||||
Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem.
|
||||
Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
12
src/content/work/Мониторинг ЖКХ.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
company: "Мониторинг ЖКХ"
|
||||
role: "комплекс устройств опроса"
|
||||
dateStart: "01/01/2023"
|
||||
dateEnd: "11/27/2025"
|
||||
---
|
||||
|
||||
В городе Иркутске внедрили систему мониторинга ЖКХ. Датчики тепла и воды передают данные на гркпповое устройство, далее на центральный сервер. Алгоритмы анализируют потребление и предупреждают о возможных утечках.
|
||||
|
||||
- Беспроводной интерфейс позводяет размещать датчики в любом месте.
|
||||
- Неограниченное колличество датчиков.
|
||||
- Оповещение с выделенного сервера, позволяет получать свежую информацию об всех неисправностях.
|
||||
12
src/content/work/Система вызова персонала.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
company: "Система вызова персонала"
|
||||
role: "Комплекс пультового управления"
|
||||
dateStart: "01/01/2020"
|
||||
dateEnd: "10/21/2023"
|
||||
---
|
||||
|
||||
В частной клинике внедрили систему автоматического вызова персонала. Если датчики обнаруживают падение пациента или аномалию, они отправляют сигнал на пульт оператора. Это спасает жизни!
|
||||
Так же дополнительное размещение обородувани во все кабинеты позволили оповещать персонал об необходимой помощи всех категорий врачей и охраны.
|
||||
|
||||
- Беспроводной интерфейс позволил маштабировать сеть на нестандартную форму здания без дополнительной покладки линий
|
||||
- Выделенный сервер позволяет собирать все журналы вызово.
|
||||
12
src/content/work/Телеграм коммандер.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
company: "Телеграм коммандер"
|
||||
role: "Программный Комплекс управления"
|
||||
dateStart: "01/01/2020"
|
||||
dateEnd: "10/21/2023"
|
||||
---
|
||||
|
||||
Инженеры создали бота для управления домашними устройствами через Telegram. Он принимает команды от пользователя и включает свет, регулирует температуру и даже готовит кофе. Удобно и современно!
|
||||
|
||||
- Универсальное средство управления экономит ваше время.
|
||||
- Выделенный сервер позволяет контролировать внештатную ситуацию.
|
||||
- Сцанарное управление дает возможность выстравивать алгоритмы последовательноти ваших действий.
|
||||
2
src/env.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
58
src/layouts/ArticleBottomLayout.astro
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
import { type CollectionEntry, getCollection } from "astro:content"
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<"blog"> | CollectionEntry<"projects">
|
||||
}
|
||||
|
||||
// Get the requested entry
|
||||
const { entry } = Astro.props
|
||||
const { collection } = entry
|
||||
const { Content } = await entry.render()
|
||||
|
||||
// Get the next and prev entries (modulo to wrap index)
|
||||
const items = (await getCollection(collection))
|
||||
.filter(post => !post.data.draft)
|
||||
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime())
|
||||
const index = items.findIndex(x => x.slug === entry.slug)
|
||||
const prev = items[(index - 1 + items.length) % items.length]
|
||||
const next = items[(index + 1) % items.length]
|
||||
---
|
||||
|
||||
<div>
|
||||
<article>
|
||||
<Content/>
|
||||
</article>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<a href={`/${prev.collection}/${prev.slug}`} class="group p-4 gap-3 flex items-center border rounded-lg hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 blend">
|
||||
<div class="order-2 w-full h-full group-hover:text-black group-hover:dark:text-white blend">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<div class="text-sm uppercase">
|
||||
Prev
|
||||
</div>
|
||||
</div>
|
||||
<div class="font-semibold mt-3 text-black dark:text-white">
|
||||
{prev.data.title}
|
||||
</div>
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="order-1 stroke-current group-hover:stroke-black group-hover:dark:stroke-white rotate-180">
|
||||
<line x1="5" y1="12" x2="19" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-4 group-hover:translate-x-1 transition-all duration-300 ease-in-out" />
|
||||
<polyline points="12 5 19 12 12 19" class="translate-x-0 group-hover:translate-x-1 transition-all duration-300 ease-in-out" />
|
||||
</svg>
|
||||
</a>
|
||||
<a href={`/${next.collection}/${next.slug}`} class="group p-4 gap-3 flex items-center border rounded-lg hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 transition-colors duration-300 ease-in-out">
|
||||
<div class="w-full h-full text-right group-hover:text-black group-hover:dark:text-white blend">
|
||||
<div class="text-sm uppercase">
|
||||
Next
|
||||
</div>
|
||||
<div class="font-semibold mt-3 text-black dark:text-white">
|
||||
{next.data.title}
|
||||
</div>
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white">
|
||||
<line x1="5" y1="12" x2="19" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-4 group-hover:translate-x-1 transition-all duration-300 ease-in-out" />
|
||||
<polyline points="12 5 19 12 12 19" class="translate-x-0 group-hover:translate-x-1 transition-all duration-300 ease-in-out" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
71
src/layouts/ArticleTopLayout.astro
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
import type { CollectionEntry } from "astro:content"
|
||||
import { formatDate, readingTime } from "@lib/utils"
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<"projects"> | CollectionEntry<"blog">
|
||||
}
|
||||
|
||||
const { entry } = Astro.props
|
||||
const { collection, data, body } = entry
|
||||
const { title, summary, date } = data
|
||||
|
||||
const demoUrl = collection === "projects" ? data.demoUrl : null
|
||||
const repoUrl = collection === "projects" ? data.repoUrl : null
|
||||
---
|
||||
|
||||
<div>
|
||||
<a href={`/${collection}`} class="group w-fit p-1.5 gap-1.5 text-sm flex items-center border rounded hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 transition-colors duration-300 ease-in-out">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white">
|
||||
<line x1="19" y1="12" x2="5" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-3 group-hover:translate-x-0 transition-all duration-300 ease-in-out" />
|
||||
<polyline points="12 19 5 12 12 5" class="translate-x-1 group-hover:translate-x-0 transition-all duration-300 ease-in-out" />
|
||||
</svg>
|
||||
<div class="w-full group-hover:text-black group-hover:dark:text-white transition-colors duration-300 ease-in-out">
|
||||
Back to {collection}
|
||||
</div>
|
||||
</a>
|
||||
<div class="flex flex-wrap text-sm uppercase mt-12 gap-3 opacity-75">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="size-5 stroke-current">
|
||||
<use href="/ui.svg#calendar"/>
|
||||
</svg>
|
||||
{formatDate(date)}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="size-5 stroke-current">
|
||||
<use href="/ui.svg#book-open"/>
|
||||
</svg>
|
||||
{readingTime(body)}
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="text-3xl font-semibold text-black dark:text-white mt-2">
|
||||
{title}
|
||||
</h1>
|
||||
<div class="mt-1">
|
||||
{summary}
|
||||
</div>
|
||||
{(demoUrl || repoUrl) &&
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
{demoUrl &&
|
||||
<a href={demoUrl} target="_blank" class="group flex gap-2 items-center px-3 py-1.5 truncate rounded text-xs md:text-sm lg:text-base border border-black/25 dark:border-white/25 hover:bg-black/5 hover:dark:bg-white/15 blend">
|
||||
<svg class="size-4">
|
||||
<use href="/ui.svg#globe" class="fill-current group-hover:fill-black group-hover:dark:fill-white blend"/>
|
||||
</svg>
|
||||
<span class="text-current group-hover:text-black group-hover:dark:text-white blend">
|
||||
See Demo
|
||||
</span>
|
||||
</a>
|
||||
}
|
||||
{repoUrl &&
|
||||
<a href={repoUrl} target="_blank" class="group flex gap-2 items-center px-3 py-1.5 truncate rounded text-xs md:text-sm lg:text-base border border-black/25 dark:border-white/25 hover:bg-black/5 hover:dark:bg-white/15 blend">
|
||||
<svg class="size-4">
|
||||
<use href="/ui.svg#link" class="fill-current group-hover:fill-black group-hover:dark:fill-white blend"/>
|
||||
</svg>
|
||||
<span class="text-current group-hover:text-black group-hover:dark:text-white blend">
|
||||
See Repository
|
||||
</span>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
9
src/layouts/BottomLayout.astro
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
import Container from "@components/Container.astro"
|
||||
---
|
||||
|
||||
<div class="flex-1 py-5">
|
||||
<Container size="md">
|
||||
<slot/>
|
||||
</Container>
|
||||
</div>
|
||||
24
src/layouts/PageLayout.astro
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
import "@styles/global.css"
|
||||
import BaseHead from "@components/BaseHead.astro"
|
||||
import Header from "@components/Header.astro"
|
||||
import Footer from "@components/Footer.astro"
|
||||
import Drawer from "@components/Drawer.astro"
|
||||
const { title, description } = Astro.props
|
||||
import { SITE } from "@consts"
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<BaseHead title={`${title} | ${SITE.TITLE}`} description={description} />
|
||||
</head>
|
||||
<body>
|
||||
<Header />
|
||||
<Drawer />
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
9
src/layouts/TopLayout.astro
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
import Container from "@components/Container.astro"
|
||||
---
|
||||
|
||||
<div class="pt-36 pb-5">
|
||||
<Container size="md">
|
||||
<slot/>
|
||||
</Container>
|
||||
</div>
|
||||
21
src/lib/utils.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
export function formatDate(date: Date) {
|
||||
return Intl.DateTimeFormat("en-US", {
|
||||
month: "short",
|
||||
day: "2-digit",
|
||||
year: "numeric"
|
||||
}).format(date)
|
||||
}
|
||||
|
||||
export function readingTime(html: string) {
|
||||
const textOnly = html.replace(/<[^>]+>/g, "")
|
||||
const wordCount = textOnly.split(/\s+/).length
|
||||
const readingTimeMinutes = ((wordCount / 200) + 1).toFixed()
|
||||
return `${readingTimeMinutes} min read`
|
||||
}
|
||||
35
src/pages/blog/[...slug].astro
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
import { type CollectionEntry, getCollection } from "astro:content"
|
||||
import PageLayout from "@layouts/PageLayout.astro"
|
||||
import TopLayout from "@layouts/TopLayout.astro"
|
||||
import BottomLayout from "@layouts/BottomLayout.astro"
|
||||
import ArticleTopLayout from "@layouts/ArticleTopLayout.astro"
|
||||
import ArticleBottomLayout from "@layouts/ArticleBottomLayout.astro"
|
||||
|
||||
// Create the static blog pages
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection("blog")
|
||||
return posts.map((post) => ({
|
||||
params: { slug: post.slug },
|
||||
props: post,
|
||||
}))
|
||||
}
|
||||
|
||||
// Get the requested post
|
||||
type Props = CollectionEntry<"blog">
|
||||
const post = Astro.props
|
||||
const { title, summary } = post.data
|
||||
---
|
||||
|
||||
<PageLayout title={title} description={summary}>
|
||||
<TopLayout>
|
||||
<div class="animate">
|
||||
<ArticleTopLayout entry={post}/>
|
||||
</div>
|
||||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<ArticleBottomLayout entry={post} />
|
||||
</div>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
30
src/pages/blog/index.astro
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
import { getCollection } from "astro:content"
|
||||
import PageLayout from "@layouts/PageLayout.astro"
|
||||
import TopLayout from "@layouts/TopLayout.astro"
|
||||
import BottomLayout from "@layouts/BottomLayout.astro"
|
||||
import Blog from "@components/Blog"
|
||||
import { BLOG } from "@consts"
|
||||
|
||||
const posts = (await getCollection("blog"))
|
||||
.filter(post => !post.data.draft)
|
||||
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime())
|
||||
|
||||
const tags = [...new Set(posts.flatMap(post => post.data.tags))]
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
---
|
||||
|
||||
<PageLayout title={BLOG.TITLE} description={BLOG.DESCRIPTION}>
|
||||
<TopLayout>
|
||||
<div class="animate page-heading">
|
||||
{BLOG.TITLE}
|
||||
</div>
|
||||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<Blog client:load tags={tags} data={posts} />
|
||||
</div>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
|
||||
|
||||
225
src/pages/index.astro
Normal file
@@ -0,0 +1,225 @@
|
||||
---
|
||||
import { getCollection } from "astro:content"
|
||||
import PageLayout from "@layouts/PageLayout.astro"
|
||||
import ArrowCard from "@components/ArrowCard"
|
||||
import StackCard from "@components/StackCard.astro"
|
||||
import { SITE, SOCIALS } from "@consts"
|
||||
import TwinklingStars from "@components/TwinklingStars.astro"
|
||||
import MeteorShower from "@components/MeteorShower.astro"
|
||||
|
||||
const posts = (await getCollection("blog"))
|
||||
.filter(post => !post.data.draft)
|
||||
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime())
|
||||
.slice(0,3)
|
||||
|
||||
const projects = (await getCollection("projects"))
|
||||
.filter(project => !project.data.draft)
|
||||
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime())
|
||||
.slice(0,3)
|
||||
|
||||
const stack = [
|
||||
{
|
||||
text: "Astro",
|
||||
icon: "astro",
|
||||
href: "https://astro.build"
|
||||
},
|
||||
{
|
||||
text: "Javascript",
|
||||
icon: "javascript",
|
||||
href: "https://www.javascript.com"
|
||||
},
|
||||
{
|
||||
text: "Typescript",
|
||||
icon: "typescript",
|
||||
href: "https://www.typescriptlang.org"
|
||||
},
|
||||
{
|
||||
text: "Tailwind",
|
||||
icon: "tailwind",
|
||||
href: "https://tailwindcss.com"
|
||||
},
|
||||
]
|
||||
---
|
||||
|
||||
<PageLayout title="Home" description={SITE.DESCRIPTION}>
|
||||
|
||||
<!-- Light Mode: Particles -->
|
||||
<div class='absolute inset-0 block dark:hidden'>
|
||||
<div id='particles1' class='fixed inset-0'></div>
|
||||
<div id='particles2' class='fixed inset-0'></div>
|
||||
<div id='particles3' class='fixed inset-0'></div>
|
||||
</div>
|
||||
|
||||
<!-- Dark Theme: Stars -->
|
||||
<div class='absolute inset-0 bg-black hidden dark:block'>
|
||||
<div id='stars1' class='fixed inset-0'></div>
|
||||
<div id='stars2' class='fixed inset-0'></div>
|
||||
<div id='stars3' class='fixed inset-0'></div>
|
||||
</div>
|
||||
|
||||
<!-- Dark Theme: Twinkling Stars / Metors -->
|
||||
<div id="galaxy" class="fixed inset-0">
|
||||
<div class="hidden dark:block">
|
||||
<TwinklingStars/>
|
||||
<MeteorShower/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script is:inline src="/js/bg.js"></script>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="relative h-screen w-full">
|
||||
<div id="planetcont" class='animate absolute inset-0 top-1/4 overflow-hidden'>
|
||||
<div id="crescent" class='absolute top-0 left-1/2 -translate-x-1/2 w-[250vw] min-h-[100vh] aspect-square rounded-full p-[1px] bg-gradient-to-b from-black/25 dark:from-white/75 from-0% to-transparent to-5%'>
|
||||
<div id="planet" class='w-full h-full bg-white dark:bg-black rounded-full p-[1px] overflow-hidden flex justify-center'>
|
||||
<div id="blur" class='w-full h-20 rounded-full bg-neutral-900/25 dark:bg-white/25 blur-3xl'/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="animate absolute h-full w-full flex items-center justify-center">
|
||||
<div class='relative w-full h-full flex items-center justify-center'>
|
||||
<div class='p-5 text-center'>
|
||||
<p class='animated text-lg md:text-xl lg:text-2xl font-semibold opacity-75'>
|
||||
Время пришло!
|
||||
</p>
|
||||
<p class='animated text-2xl md:text-3xl lg:text-4xl font-bold uppercase text-black dark:text-white'>
|
||||
Для новых горизонтов возможностей!
|
||||
</p>
|
||||
<p class='animated text-sm md:text-base lg:text-lg opacity-75'>
|
||||
Мы расскажем вам про новое поколение ПЛАТ УПРАВЛЕНИЯ.
|
||||
</p>
|
||||
<div id="ctaButtons" class='animated flex flex-wrap gap-4 justify-center mt-5'>
|
||||
<a href='/blog' class='py-2 px-4 rounded truncate text-xs md:text-sm lg:text-base bg-black dark:bg-white text-white dark:text-black hover:opacity-75 blend'>
|
||||
Читать блог
|
||||
</a>
|
||||
<a href='/work' class='py-2 px-4 truncate rounded text-xs md:text-sm lg:text-base border border-black/25 dark:border-white/25 hover:bg-black/5 hover:dark:bg-white/15 blend'>
|
||||
Промсмотреть работу
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="relative bg-white dark:bg-black">
|
||||
<div class="mx-auto max-w-screen-sm p-5 space-y-24 pb-16">
|
||||
|
||||
<!-- About Section -->
|
||||
<section class="animate">
|
||||
<article>
|
||||
<p>Мы команда <b><i>инженеров</i></b>, <b><i>програмистов</i></b>, <b><i>архитекторов</i></b>, <b><i>конструкторов</i></b>, <b><i>тестировщиков</i></b>, которвые собрались для общего дела.</p>
|
||||
<p>Проектирование и изготовление печатных плат – это важный этап в создании электронных устройств. Наша компания специализируется на разработке и программировании плат управления, которые могут быть частью различных устройств, от беспилотных летательных аппаратов (БПЛА) до умных домов и систем оповещения.</p>
|
||||
<p><b>Вот несколько ключевых аспектов</b>, <b>которые следует учесть при проектировании и изготовлении печатных плат</b>:</p>
|
||||
<p>
|
||||
<b>Определение правил проектирования платы:</b>
|
||||
<p>Прежде чем начать размещение компонентов, важно определить правила проектирования печатной платы. Это включает в себя выбор метода изготовления, определение стека платы и установку ограничений для обеспечения производительности и надежности.</p>
|
||||
<b>Размещение компонентов:</b>
|
||||
<p>Хорошее размещение компонентов обеспечивает решаемость и простоту трассировки. Группировка компонентов по типу помогает предотвратить необходимость долгой трассировки по всей плате.</p>
|
||||
<b>Расположение питания и заземления:</b>
|
||||
<p>Важно правильно разместить питание и заземление в стеке платы. Это включает в себя учет смешанных сигналов и обеспечение надежной работы.</p>
|
||||
<b>Соблюдение механических ограничений:</b>
|
||||
<p>Расположение разъемов и соблюдение размеров корпуса также важно для успешного проектирования.</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<!-- Blog Preview Section -->
|
||||
<section class="animate">
|
||||
<div class="space-y-4">
|
||||
<div class="flex justify-between">
|
||||
<p class="font-semibold text-black dark:text-white">
|
||||
Наши последние посты
|
||||
</p>
|
||||
<a href="/blog" class="w-fit col-span-3 group flex gap-1 items-center underline decoration-[.5px] decoration-black/25 dark:decoration-white/50 hover:decoration-black dark:hover:decoration-white text-black dark:text-white underline-offset-2 blend">
|
||||
<span class="text-black/75 dark:text-white/75 group-hover:text-black group-hover:dark:text-white blend">
|
||||
Все посты
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="space-y-4">
|
||||
{posts.map((post) => (
|
||||
<li>
|
||||
<ArrowCard entry={post} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Tech Stack Section -->
|
||||
<section class="animate">
|
||||
<div class="space-y-4">
|
||||
<p class="font-semibold text-black dark:text-white">
|
||||
Сайт сделан на следующих технологиях
|
||||
</p>
|
||||
<div class="flex flex-wrap items-center gap-2 mt-5">
|
||||
{stack.map(item => (
|
||||
<StackCard
|
||||
text={item.text}
|
||||
icon={item.icon}
|
||||
href={item.href}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
Демонстрируя реактивность и статичность, специального фреймворка
|
||||
<a href="https://www.solidjs.com/" target="_blank" class="w-fit group underline decoration-[.5px] decoration-black/25 dark:decoration-white/50 hover:decoration-black dark:hover:decoration-white text-black dark:text-white underline-offset-2 blend">
|
||||
<span class="text-black/75 dark:text-white/75 group-hover:text-black group-hover:dark:text-white blend">
|
||||
SolidJS
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Project Preview Section -->
|
||||
<section class="animate">
|
||||
<div class="space-y-4">
|
||||
<div class="flex justify-between">
|
||||
<p class="font-semibold text-black dark:text-white">
|
||||
Последние проекты
|
||||
</p>
|
||||
<a href="/projects" class="w-fit col-span-3 group flex gap-1 items-center underline decoration-[.5px] decoration-black/25 dark:decoration-white/50 hover:decoration-black dark:hover:decoration-white text-black dark:text-white underline-offset-2 blend">
|
||||
<span class="text-black/75 dark:text-white/75 group-hover:text-black group-hover:dark:text-white blend">
|
||||
Все проекты
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="space-y-4">
|
||||
{projects.map((project) => (
|
||||
<li>
|
||||
<ArrowCard entry={project} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Contact Section -->
|
||||
<section class="animate">
|
||||
<div>
|
||||
<p class="font-semibold text-black dark:text-white">
|
||||
Для связи
|
||||
</p>
|
||||
<p>
|
||||
у нас есть email и телеграм бот обратной связи, так же есть каналы в telegram, youtube, github.
|
||||
</p>
|
||||
<div class="grid grid-cols-4 gap-y-2 mt-4 auto-cols-min">
|
||||
{SOCIALS.map(social => (
|
||||
<div class="col-span-1 flex items-center gap-1">
|
||||
<span class="whitespace-nowrap truncate">
|
||||
{social.NAME}
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-span-3 truncate">
|
||||
<a href={social.HREF} target="_blank" class="w-fit col-span-3 group flex gap-1 items-center underline decoration-[.5px] decoration-black/25 dark:decoration-white/50 hover:decoration-black dark:hover:decoration-white text-black dark:text-white underline-offset-2 blend">
|
||||
<span class="text-black/75 dark:text-white/75 group-hover:text-black group-hover:dark:text-white blend">
|
||||
{social.TEXT}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</PageLayout>
|
||||
42
src/pages/legal/[...slug].astro
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
import { type CollectionEntry, getCollection } from "astro:content"
|
||||
import PageLayout from "@layouts/PageLayout.astro"
|
||||
import TopLayout from "@layouts/TopLayout.astro"
|
||||
import BottomLayout from "@layouts/BottomLayout.astro"
|
||||
import { formatDate } from "@lib/utils"
|
||||
import { SITE } from "@consts"
|
||||
|
||||
// Create the static pages for legal docs
|
||||
export async function getStaticPaths() {
|
||||
const docs = await getCollection("legal")
|
||||
return docs.map((doc) => ({
|
||||
params: { slug: doc.slug },
|
||||
props: doc,
|
||||
}))
|
||||
}
|
||||
|
||||
// Get the requested legal doc
|
||||
type Props = CollectionEntry<"legal">;
|
||||
const doc = Astro.props
|
||||
const { title, date } = doc.data
|
||||
const { Content } = await doc.render();
|
||||
|
||||
---
|
||||
|
||||
<PageLayout title={title} description={`${title} for ${SITE.TITLE}`}>
|
||||
<TopLayout>
|
||||
<div class="animate">
|
||||
<div class="page-heading">
|
||||
{title}
|
||||
</div>
|
||||
<p class="font-normal opacity-75">
|
||||
Last updated: {formatDate(date)}
|
||||
</p>
|
||||
</div>
|
||||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<article class="animate">
|
||||
<Content/>
|
||||
</article>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
35
src/pages/projects/[...slug].astro
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
import { type CollectionEntry, getCollection } from "astro:content"
|
||||
import PageLayout from "@layouts/PageLayout.astro"
|
||||
import TopLayout from "@layouts/TopLayout.astro"
|
||||
import BottomLayout from "@layouts/BottomLayout.astro"
|
||||
import ArticleTopLayout from "@layouts/ArticleTopLayout.astro"
|
||||
import ArticleBottomLayout from "@layouts/ArticleBottomLayout.astro"
|
||||
|
||||
// Create the static projects pages
|
||||
export async function getStaticPaths() {
|
||||
const projects = await getCollection("projects")
|
||||
return projects.map((project) => ({
|
||||
params: { slug: project.slug },
|
||||
props: project,
|
||||
}))
|
||||
}
|
||||
|
||||
// Get the requested project
|
||||
type Props = CollectionEntry<"projects">
|
||||
const project = Astro.props
|
||||
const { title, summary } = project.data
|
||||
---
|
||||
|
||||
<PageLayout title={title} description={summary}>
|
||||
<TopLayout>
|
||||
<div class="animate">
|
||||
<ArticleTopLayout entry={project} />
|
||||
</div>
|
||||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<ArticleBottomLayout entry={project} />
|
||||
</div>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
28
src/pages/projects/index.astro
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
import { getCollection } from "astro:content"
|
||||
import PageLayout from "@layouts/PageLayout.astro"
|
||||
import TopLayout from "@layouts/TopLayout.astro"
|
||||
import BottomLayout from "@layouts/BottomLayout.astro"
|
||||
import Projects from "@components/Projects"
|
||||
import { PROJECTS } from "@consts"
|
||||
|
||||
const projects = (await getCollection("projects"))
|
||||
.filter(project => !project.data.draft)
|
||||
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime())
|
||||
|
||||
const tags = [...new Set(projects.flatMap(project => project.data.tags))]
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
---
|
||||
|
||||
<PageLayout title={PROJECTS.TITLE} description={PROJECTS.DESCRIPTION}>
|
||||
<TopLayout>
|
||||
<div class="animate page-heading">
|
||||
{PROJECTS.TITLE}
|
||||
</div>
|
||||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<Projects client:load tags={tags} data={projects} />
|
||||
</div>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
16
src/pages/robots.txt.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { APIRoute } from "astro"
|
||||
|
||||
const robotsTxt = `
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: ${new URL("sitemap-index.xml", import.meta.env.SITE).href}
|
||||
`.trim()
|
||||
|
||||
export const GET: APIRoute = () => {
|
||||
return new Response(robotsTxt, {
|
||||
headers: {
|
||||
"Content-Type": "text/plain; charset=utf-8",
|
||||
},
|
||||
})
|
||||
}
|
||||
30
src/pages/rss.xml.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import rss from "@astrojs/rss"
|
||||
import { getCollection } from "astro:content"
|
||||
import { SITE } from "@consts"
|
||||
|
||||
type Context = {
|
||||
site: string
|
||||
}
|
||||
|
||||
export async function GET(context: Context) {
|
||||
const posts = await getCollection("blog")
|
||||
const projects = await getCollection("projects")
|
||||
|
||||
const items = [...posts, ...projects]
|
||||
|
||||
items.sort((a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime())
|
||||
|
||||
return rss({
|
||||
title: SITE.TITLE,
|
||||
description: SITE.DESCRIPTION,
|
||||
site: context.site,
|
||||
items: items.map((item) => ({
|
||||
title: item.data.title,
|
||||
description: item.data.summary,
|
||||
pubDate: item.data.date,
|
||||
link: item.slug.startsWith("blog")
|
||||
? `/blog/${item.slug}/`
|
||||
: `/projects/${item.slug}/`,
|
||||
})),
|
||||
})
|
||||
}
|
||||
29
src/pages/search/index.astro
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
import { type CollectionEntry, getCollection } from "astro:content"
|
||||
import PageLayout from "@layouts/PageLayout.astro"
|
||||
import TopLayout from "@layouts/TopLayout.astro"
|
||||
import BottomLayout from "@layouts/BottomLayout.astro"
|
||||
import Search from "@components/Search"
|
||||
import { SEARCH } from "@consts"
|
||||
|
||||
const posts = (await getCollection("blog"))
|
||||
.filter(post => !post.data.draft)
|
||||
|
||||
const projects = (await getCollection("projects"))
|
||||
.filter(post => !post.data.draft)
|
||||
|
||||
const data = [...posts, ...projects] as CollectionEntry<"blog">[]
|
||||
---
|
||||
|
||||
<PageLayout title={SEARCH.TITLE} description={SEARCH.DESCRIPTION}>
|
||||
<TopLayout>
|
||||
<div class="animate page-heading">
|
||||
{SEARCH.TITLE}
|
||||
</div>
|
||||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<Search client:load data={data}/>
|
||||
</div>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
59
src/pages/work/index.astro
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
import { getCollection } from "astro:content"
|
||||
import PageLayout from "@layouts/PageLayout.astro"
|
||||
import TopLayout from "@layouts/TopLayout.astro"
|
||||
import BottomLayout from "@layouts/BottomLayout.astro"
|
||||
import { WORK } from "@consts"
|
||||
|
||||
const collection = await getCollection("work")
|
||||
|
||||
collection.sort((a, b) => new Date(b.data.dateStart).getTime() - new Date(a.data.dateStart).getTime())
|
||||
|
||||
const work = await Promise.all(
|
||||
collection.map(async (item) => {
|
||||
const { Content } = await item.render()
|
||||
return { ...item, Content }
|
||||
})
|
||||
)
|
||||
|
||||
function formatWorkDate(input: Date | string) {
|
||||
if (typeof input === "string") return input
|
||||
|
||||
const month = input.toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
})
|
||||
|
||||
const year = new Date(input).getFullYear()
|
||||
return `${month} ${year}`
|
||||
}
|
||||
---
|
||||
|
||||
<PageLayout title={WORK.TITLE} description={WORK.DESCRIPTION}>
|
||||
<TopLayout>
|
||||
<div class="animate page-heading">
|
||||
{WORK.TITLE}
|
||||
</div>
|
||||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<ul>
|
||||
{
|
||||
work.map((entry) => (
|
||||
<li class="animate border-b border-black/10 dark:border-white/25 mt-4 py-8 first-of-type:mt-0 first-of-type:pt-0 last-of-type:border-none">
|
||||
<div class="text-sm uppercase mb-4">
|
||||
{formatWorkDate(entry.data.dateStart)} - {formatWorkDate(entry.data.dateEnd)}
|
||||
</div>
|
||||
<div class="text-black dark:text-white font-semibold">
|
||||
{entry.data.company}
|
||||
</div>
|
||||
<div class="text-sm font-semibold">
|
||||
{entry.data.role}
|
||||
</div>
|
||||
<article class="prose dark:prose-invert">
|
||||
<entry.Content />
|
||||
</article>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
150
src/styles/global.css
Normal file
@@ -0,0 +1,150 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
@font-face {
|
||||
font-family: "Atkinson";
|
||||
src: url("/fonts/atkinson-regular.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Atkinson";
|
||||
src: url("/fonts/atkinson-bold.woff") format("woff");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
color-scheme: light;
|
||||
background-color: white;
|
||||
font-family: "Atkinson", sans-serif;
|
||||
|
||||
}
|
||||
|
||||
html.dark {
|
||||
color-scheme: dark;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply h-full w-full antialiased;
|
||||
@apply bg-white dark:bg-black;
|
||||
@apply text-black/75 dark:text-white/75;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply relative flex flex-col;
|
||||
}
|
||||
|
||||
main {
|
||||
@apply flex flex-col flex-1 bg-white dark:bg-black;
|
||||
}
|
||||
|
||||
header {
|
||||
@apply border-b;
|
||||
@apply transition-all duration-300 ease-in-out;
|
||||
}
|
||||
|
||||
header:not(.scrolled) {
|
||||
@apply bg-transparent border-transparent;
|
||||
}
|
||||
|
||||
header.scrolled {
|
||||
@apply bg-white/75 dark:bg-black/50;
|
||||
@apply border-black/10 dark:border-white/25;
|
||||
@apply backdrop-blur-sm saturate-200;
|
||||
}
|
||||
|
||||
article {
|
||||
@apply prose dark:prose-invert max-w-full pb-12;
|
||||
}
|
||||
|
||||
.page-heading {
|
||||
@apply font-semibold text-black dark:text-white;
|
||||
}
|
||||
|
||||
.blend {
|
||||
@apply transition-all duration-300 ease-in-out;
|
||||
}
|
||||
|
||||
/** Light theme particles on home page */
|
||||
@keyframes animateParticle {
|
||||
from {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
to {
|
||||
transform: translateY(-2000px);
|
||||
}
|
||||
}
|
||||
|
||||
/** styles for public /animation.js */
|
||||
.animate {
|
||||
opacity: 0;
|
||||
transform: translateY(50px);
|
||||
transition: opacity 1s ease, transform 1s ease;
|
||||
}
|
||||
|
||||
.animate.show {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
article img {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* TWINKLE STARS
|
||||
*/
|
||||
|
||||
#twinkle-star.template {
|
||||
@apply absolute -left-full; /* hide offscreen */
|
||||
}
|
||||
|
||||
#twinkle-star.twinkle {
|
||||
@apply animate-twinkle; /* defined in tailwind.config */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Meteors
|
||||
*/
|
||||
|
||||
#meteors .shower {
|
||||
@apply absolute inset-0 top-0;;
|
||||
@apply left-1/2 -translate-x-1/2;
|
||||
@apply w-screen aspect-square;
|
||||
}
|
||||
|
||||
#meteors .meteor {
|
||||
@apply animate-meteor; /* defined in tailwind.config */
|
||||
@apply absolute top-1/2 left-1/2 w-px h-[75vh];
|
||||
@apply bg-gradient-to-b from-white to-transparent;
|
||||
}
|
||||
|
||||
#meteors .shower.ur {
|
||||
@apply rotate-45;
|
||||
}
|
||||
|
||||
#meteors .shower.dr {
|
||||
@apply rotate-135;
|
||||
}
|
||||
|
||||
#meteors .shower.dl {
|
||||
@apply rotate-225;
|
||||
}
|
||||
|
||||
#meteors .shower.ul {
|
||||
@apply rotate-315;
|
||||
}
|
||||
20
src/types.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export type Page = {
|
||||
TITLE: string
|
||||
DESCRIPTION: string
|
||||
}
|
||||
|
||||
export interface Site extends Page {
|
||||
AUTHOR: string
|
||||
}
|
||||
|
||||
export type Links = {
|
||||
TEXT: string
|
||||
HREF: string
|
||||
}[]
|
||||
|
||||
export type Socials = {
|
||||
NAME: string
|
||||
ICON: string
|
||||
TEXT: string
|
||||
HREF: string
|
||||
}[]
|
||||
61
tailwind.config.mjs
Normal file
@@ -0,0 +1,61 @@
|
||||
import defaultTheme from "tailwindcss/defaultTheme"
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: ["class"],
|
||||
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
"sans": ["Atkinson", ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
typography: {
|
||||
DEFAULT: {
|
||||
css: {
|
||||
maxWidth: "full",
|
||||
},
|
||||
},
|
||||
},
|
||||
rotate: {
|
||||
"45": "45deg",
|
||||
"135": "135deg",
|
||||
"225": "225deg",
|
||||
"315": "315deg",
|
||||
},
|
||||
animation: {
|
||||
twinkle: "twinkle 2s ease-in-out forwards",
|
||||
meteor: "meteor 3s ease-in-out forwards",
|
||||
},
|
||||
keyframes: {
|
||||
twinkle: {
|
||||
"0%": {
|
||||
opacity: 0,
|
||||
transform: "rotate(0deg)"
|
||||
},
|
||||
"50%": {
|
||||
opacity: 1,
|
||||
transform: "rotate(180deg)"
|
||||
},
|
||||
"100%": {
|
||||
opacity: 0,
|
||||
transform: "rotate(360deg)"
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
"0%": {
|
||||
opacity: 0,
|
||||
transform: "translateY(200%)"
|
||||
},
|
||||
"50%": {
|
||||
opacity: 1
|
||||
},
|
||||
"100%": {
|
||||
opacity: 0,
|
||||
transform: "translateY(0)"
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("@tailwindcss/typography")],
|
||||
}
|
||||