diff --git a/.eslintrc b/.eslintrc index eceaff4..fc82bf2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -87,7 +87,8 @@ "unused-imports/no-unused-vars": [ "error", { "argsIgnorePattern": "^_" } - ] + ], + "import/no-extraneous-dependencies": "off" // mjs is only used by Astro for configuration, false positive } }, // Configuration for Astro diff --git a/.prettierrc b/.prettierrc index a7be249..a5d482b 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,5 +2,13 @@ "tabWidth": 4, "semi": true, "singleQuote": true, - "plugins": ["prettier-plugin-tailwindcss"] + "plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-astro"], + "overrides": [ + { + "files": "*.astro", + "options": { + "parser": "astro" + } + } + ] } diff --git a/package.json b/package.json index 92ffe3c..40a25d1 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "thinc-roadmap", + "name": "thinc-knowledge", "type": "module", "scripts": { "dev": "astro dev", @@ -18,8 +18,10 @@ "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", "astro": "^3.2.2", + "get-src": "^1.0.1", "react": "^18.0.0", "react-dom": "^18.0.0", + "rss-parser": "^3.13.0", "tailwind-merge": "^1.14.0", "tailwindcss": "^3.0.24" }, @@ -37,6 +39,7 @@ "eslint-plugin-unused-imports": "^3.0.0", "prettier": "^3.0.3", "prettier-plugin-astro": "^0.12.0", - "prettier-plugin-tailwindcss": "^0.5.5" + "prettier-plugin-tailwindcss": "^0.5.5", + "react-icons": "^4.11.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 91179a9..62abaee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,12 +25,18 @@ dependencies: astro: specifier: ^3.2.2 version: 3.2.2 + get-src: + specifier: ^1.0.1 + version: 1.0.1 react: specifier: ^18.0.0 version: 18.2.0 react-dom: specifier: ^18.0.0 version: 18.2.0(react@18.2.0) + rss-parser: + specifier: ^3.13.0 + version: 3.13.0 tailwind-merge: specifier: ^1.14.0 version: 1.14.0 @@ -81,6 +87,9 @@ devDependencies: prettier-plugin-tailwindcss: specifier: ^0.5.5 version: 0.5.5(prettier-plugin-astro@0.12.0)(prettier@3.0.3) + react-icons: + specifier: ^4.11.0 + version: 4.11.0(react@18.2.0) packages: @@ -2089,6 +2098,10 @@ packages: dev: false optional: true + /entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: false + /es-abstract@1.22.2: resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==} engines: {node: '>= 0.4'} @@ -2831,6 +2844,11 @@ packages: has-symbols: 1.0.3 dev: true + /get-src@1.0.1: + resolution: {integrity: sha512-fwaOEu3rOB1tBwbQGp1g3IJSgNFCYLxEivr3j6YaDQFVgALOiB3AXlXtMewycWKPeLq03x+0ShQY+wm87cP1BQ==} + engines: {node: '>=4'} + dev: false + /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -4796,6 +4814,14 @@ packages: scheduler: 0.23.0 dev: false + /react-icons@4.11.0(react@18.2.0): + resolution: {integrity: sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: true + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: true @@ -4810,7 +4836,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: false /read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -5023,6 +5048,13 @@ packages: fsevents: 2.3.3 dev: false + /rss-parser@3.13.0: + resolution: {integrity: sha512-7jWUBV5yGN3rqMMj7CZufl/291QAhvrrGpDNE4k/02ZchL0npisiYYqULF71jCEKoIiHvK/Q2e6IkDwPziT7+w==} + dependencies: + entities: 2.2.0 + xml2js: 0.5.0 + dev: false + /run-applescript@5.0.0: resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} engines: {node: '>=12'} @@ -5987,6 +6019,19 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + dependencies: + sax: 1.3.0 + xmlbuilder: 11.0.1 + dev: false + + /xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + dev: false + /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: false diff --git a/public/blog-placeholder-1.jpg b/public/blog-placeholder-1.jpg deleted file mode 100644 index 74d4009..0000000 Binary files a/public/blog-placeholder-1.jpg and /dev/null differ diff --git a/public/blog-placeholder-2.jpg b/public/blog-placeholder-2.jpg deleted file mode 100644 index c4214b0..0000000 Binary files a/public/blog-placeholder-2.jpg and /dev/null differ diff --git a/public/blog-placeholder-3.jpg b/public/blog-placeholder-3.jpg deleted file mode 100644 index fbe2ac0..0000000 Binary files a/public/blog-placeholder-3.jpg and /dev/null differ diff --git a/public/blog-placeholder-4.jpg b/public/blog-placeholder-4.jpg deleted file mode 100644 index f4fc88e..0000000 Binary files a/public/blog-placeholder-4.jpg and /dev/null differ diff --git a/public/blog-placeholder-5.jpg b/public/blog-placeholder-5.jpg deleted file mode 100644 index c564674..0000000 Binary files a/public/blog-placeholder-5.jpg and /dev/null differ diff --git a/public/blog-placeholder-about.jpg b/public/blog-placeholder-about.jpg deleted file mode 100644 index cf5f685..0000000 Binary files a/public/blog-placeholder-about.jpg and /dev/null differ diff --git a/public/favicon.svg b/public/favicon.svg index f157bd1..7ea9d72 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1,9 +1,17 @@ - - - + + + + + + + + + + \ No newline at end of file diff --git a/public/images/2023-background.png b/public/images/2023-background.png new file mode 100644 index 0000000..ef2c3b7 Binary files /dev/null and b/public/images/2023-background.png differ diff --git a/public/images/404.png b/public/images/404.png new file mode 100644 index 0000000..b7996dd Binary files /dev/null and b/public/images/404.png differ diff --git a/public/images/thinc-logo.svg b/public/images/thinc-logo.svg new file mode 100644 index 0000000..bfc243b --- /dev/null +++ b/public/images/thinc-logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/components/Section.tsx b/src/components/Section.tsx index 057d0d7..b1ad49f 100644 --- a/src/components/Section.tsx +++ b/src/components/Section.tsx @@ -3,15 +3,21 @@ import { twMerge } from 'tailwind-merge'; export const Section = ({ children, className, + prose, }: { children: React.ReactNode; - className: string; + className?: string; + prose?: boolean; }) => { return ( -
-
{children}
+
+
+ {children} +
); }; diff --git a/src/components/blog/BlogCard.tsx b/src/components/blog/BlogCard.tsx new file mode 100644 index 0000000..cec420e --- /dev/null +++ b/src/components/blog/BlogCard.tsx @@ -0,0 +1,23 @@ +export const BlogCard = ({ + title, + link, + imgSrc, +}: { + title: string; + link: string; + imgSrc: string; +}) => { + return ( + +
+ +
+

{title}

+
+ ); +}; diff --git a/src/components/roadmap/LevelTag.tsx b/src/components/roadmap/LevelTag.tsx new file mode 100644 index 0000000..0ef3324 --- /dev/null +++ b/src/components/roadmap/LevelTag.tsx @@ -0,0 +1,23 @@ +export const LevelTag = ({ level }: { level: string }) => { + const colorSchema = { + beginner: '#4ade80', + intermediate: '#fbbf24', + advanced: '#ef4444', + }; + + const color = colorSchema as Record; + + return ( +
+
+ {level} +
+
+ ); +}; diff --git a/src/components/roadmap/RoadmapCard.tsx b/src/components/roadmap/RoadmapCard.tsx new file mode 100644 index 0000000..6868bf2 --- /dev/null +++ b/src/components/roadmap/RoadmapCard.tsx @@ -0,0 +1,40 @@ +import { twMerge } from 'tailwind-merge'; + +import { LevelTag } from './LevelTag'; + +export const RoadmapCard = ({ + className, + slug, + level, + title, + description, +}: { + className?: string; + slug: string; + level: string; + title: string; + description: string; +}) => { + return ( +
+ +
+ + +

+ {title} +

+

{description}

+
+
+
+ ); +}; diff --git a/src/consts.ts b/src/consts.ts index b4b49db..22911e4 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -1,5 +1,5 @@ // Place any global data in this file. // You can import this data from anywhere in your site by using the `import` keyword. -export const SITE_TITLE = 'Thinc Roadmap'; -export const SITE_DESCRIPTION = 'Thinc First Act Roadmap'; +export const SITE_TITLE = 'Thinc Knowledgee'; +export const SITE_DESCRIPTION = 'Thinc Knowledge'; diff --git a/src/content/blog/first-post.md b/src/content/blog/first-post.md deleted file mode 100644 index 3066715..0000000 --- a/src/content/blog/first-post.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 'First post' -description: 'Lorem ipsum dolor sit amet' -pubDate: 'Jul 08 2022' -heroImage: '/blog-placeholder-3.jpg' ---- - -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. - -Morbi tristique senectus et netus. Id semper risus in hendrerit gravida rutrum quisque non tellus. Habitasse platea dictumst quisque sagittis purus sit amet. Tellus molestie nunc non blandit massa. Cursus vitae congue mauris rhoncus. Accumsan tortor posuere ac ut. Fringilla urna porttitor rhoncus dolor. Elit ullamcorper dignissim cras tincidunt lobortis. In cursus turpis massa tincidunt dui ut ornare lectus. Integer feugiat scelerisque varius morbi enim nunc. Bibendum neque egestas congue quisque egestas diam. Cras ornare arcu dui vivamus arcu felis bibendum. Dignissim suspendisse in est ante in nibh mauris. Sed tempus urna et pharetra pharetra massa massa ultricies mi. - -Mollis nunc sed id semper risus in. Convallis a cras semper auctor neque. Diam sit amet nisl suscipit. Lacus viverra vitae congue eu consequat ac felis donec. Egestas integer eget aliquet nibh praesent tristique magna sit amet. Eget magna fermentum iaculis eu non diam. In vitae turpis massa sed elementum. Tristique et egestas quis ipsum suspendisse ultrices. Eget lorem dolor sed viverra ipsum. Vel turpis nunc eget lorem dolor sed viverra. Posuere ac ut consequat semper viverra nam. Laoreet suspendisse interdum consectetur libero id faucibus. Diam phasellus vestibulum lorem sed risus ultricies tristique. Rhoncus dolor purus non enim praesent elementum facilisis. Ultrices tincidunt arcu non sodales neque. Tempus egestas sed sed risus pretium quam vulputate. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare. Fringilla urna porttitor rhoncus dolor purus non. Amet dictum sit amet justo donec enim. - -Mattis ullamcorper velit sed ullamcorper morbi tincidunt. Tortor posuere ac ut consequat semper viverra. Tellus mauris a diam maecenas sed enim ut sem viverra. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Arcu ac tortor dignissim convallis aenean et tortor at. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Egestas tellus rutrum tellus pellentesque eu. Fusce ut placerat orci nulla pellentesque dignissim enim sit amet. Ut enim blandit volutpat maecenas volutpat blandit aliquam etiam. Id donec ultrices tincidunt arcu. Id cursus metus aliquam eleifend mi. - -Tempus quam pellentesque nec nam aliquam sem. Risus at ultrices mi tempus imperdiet. Id porta nibh venenatis cras sed felis eget velit. Ipsum a arcu cursus vitae. Facilisis magna etiam tempor orci eu lobortis elementum. Tincidunt dui ut ornare lectus sit. Quisque non tellus orci ac. Blandit libero volutpat sed cras. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin gravida. Egestas integer eget aliquet nibh praesent tristique magna. diff --git a/src/content/blog/markdown-style-guide.md b/src/content/blog/markdown-style-guide.md deleted file mode 100644 index 6533a0c..0000000 --- a/src/content/blog/markdown-style-guide.md +++ /dev/null @@ -1,214 +0,0 @@ ---- -title: 'Markdown Style Guide' -description: 'Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro.' -pubDate: 'Jul 01 2022' -heroImage: '/blog-placeholder-1.jpg' ---- - -Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro. - -## Headings - -The following HTML `

`—`

` elements represent six levels of section headings. `

` is the highest section level while `

` is the lowest. - -# 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 - -#### Syntax - -```markdown -![Alt text](./full/or/relative/path/of/image) -``` - -#### Output - -![blog placeholder](/blog-placeholder-about.jpg) - -## 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.
-> — Rob Pike[^1] -``` - -#### Output - -> Don't communicate by sharing memory, share memory by communicating.
-> — Rob Pike[^1] - -[^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 - - - - - Example HTML5 Document - - -

Test

- - -``` -```` - -Output - -```html - - - - - Example HTML5 Document - - -

Test

- - -``` - -## 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 -GIF is a bitmap image format. - -H2O - -Xn + Yn = Zn - -Press CTRL+ALT+Delete to end the session. - -Most salamanders are nocturnal, and hunt for insects, worms, and other small creatures. -``` - -#### Output - -GIF is a bitmap image format. - -H2O - -Xn + Yn = Zn - -Press CTRL+ALT+Delete to end the session. - -Most salamanders are nocturnal, and hunt for insects, worms, and other small creatures. diff --git a/src/content/blog/second-post.md b/src/content/blog/second-post.md deleted file mode 100644 index 19a9105..0000000 --- a/src/content/blog/second-post.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 'Second post' -description: 'Lorem ipsum dolor sit amet' -pubDate: 'Jul 22 2022' -heroImage: '/blog-placeholder-4.jpg' ---- - -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. - -Morbi tristique senectus et netus. Id semper risus in hendrerit gravida rutrum quisque non tellus. Habitasse platea dictumst quisque sagittis purus sit amet. Tellus molestie nunc non blandit massa. Cursus vitae congue mauris rhoncus. Accumsan tortor posuere ac ut. Fringilla urna porttitor rhoncus dolor. Elit ullamcorper dignissim cras tincidunt lobortis. In cursus turpis massa tincidunt dui ut ornare lectus. Integer feugiat scelerisque varius morbi enim nunc. Bibendum neque egestas congue quisque egestas diam. Cras ornare arcu dui vivamus arcu felis bibendum. Dignissim suspendisse in est ante in nibh mauris. Sed tempus urna et pharetra pharetra massa massa ultricies mi. - -Mollis nunc sed id semper risus in. Convallis a cras semper auctor neque. Diam sit amet nisl suscipit. Lacus viverra vitae congue eu consequat ac felis donec. Egestas integer eget aliquet nibh praesent tristique magna sit amet. Eget magna fermentum iaculis eu non diam. In vitae turpis massa sed elementum. Tristique et egestas quis ipsum suspendisse ultrices. Eget lorem dolor sed viverra ipsum. Vel turpis nunc eget lorem dolor sed viverra. Posuere ac ut consequat semper viverra nam. Laoreet suspendisse interdum consectetur libero id faucibus. Diam phasellus vestibulum lorem sed risus ultricies tristique. Rhoncus dolor purus non enim praesent elementum facilisis. Ultrices tincidunt arcu non sodales neque. Tempus egestas sed sed risus pretium quam vulputate. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare. Fringilla urna porttitor rhoncus dolor purus non. Amet dictum sit amet justo donec enim. - -Mattis ullamcorper velit sed ullamcorper morbi tincidunt. Tortor posuere ac ut consequat semper viverra. Tellus mauris a diam maecenas sed enim ut sem viverra. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Arcu ac tortor dignissim convallis aenean et tortor at. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Egestas tellus rutrum tellus pellentesque eu. Fusce ut placerat orci nulla pellentesque dignissim enim sit amet. Ut enim blandit volutpat maecenas volutpat blandit aliquam etiam. Id donec ultrices tincidunt arcu. Id cursus metus aliquam eleifend mi. - -Tempus quam pellentesque nec nam aliquam sem. Risus at ultrices mi tempus imperdiet. Id porta nibh venenatis cras sed felis eget velit. Ipsum a arcu cursus vitae. Facilisis magna etiam tempor orci eu lobortis elementum. Tincidunt dui ut ornare lectus sit. Quisque non tellus orci ac. Blandit libero volutpat sed cras. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin gravida. Egestas integer eget aliquet nibh praesent tristique magna. diff --git a/src/content/blog/third-post.md b/src/content/blog/third-post.md deleted file mode 100644 index 463cd25..0000000 --- a/src/content/blog/third-post.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 'Third post' -description: 'Lorem ipsum dolor sit amet' -pubDate: 'Jul 15 2022' -heroImage: '/blog-placeholder-2.jpg' ---- - -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. - -Morbi tristique senectus et netus. Id semper risus in hendrerit gravida rutrum quisque non tellus. Habitasse platea dictumst quisque sagittis purus sit amet. Tellus molestie nunc non blandit massa. Cursus vitae congue mauris rhoncus. Accumsan tortor posuere ac ut. Fringilla urna porttitor rhoncus dolor. Elit ullamcorper dignissim cras tincidunt lobortis. In cursus turpis massa tincidunt dui ut ornare lectus. Integer feugiat scelerisque varius morbi enim nunc. Bibendum neque egestas congue quisque egestas diam. Cras ornare arcu dui vivamus arcu felis bibendum. Dignissim suspendisse in est ante in nibh mauris. Sed tempus urna et pharetra pharetra massa massa ultricies mi. - -Mollis nunc sed id semper risus in. Convallis a cras semper auctor neque. Diam sit amet nisl suscipit. Lacus viverra vitae congue eu consequat ac felis donec. Egestas integer eget aliquet nibh praesent tristique magna sit amet. Eget magna fermentum iaculis eu non diam. In vitae turpis massa sed elementum. Tristique et egestas quis ipsum suspendisse ultrices. Eget lorem dolor sed viverra ipsum. Vel turpis nunc eget lorem dolor sed viverra. Posuere ac ut consequat semper viverra nam. Laoreet suspendisse interdum consectetur libero id faucibus. Diam phasellus vestibulum lorem sed risus ultricies tristique. Rhoncus dolor purus non enim praesent elementum facilisis. Ultrices tincidunt arcu non sodales neque. Tempus egestas sed sed risus pretium quam vulputate. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare. Fringilla urna porttitor rhoncus dolor purus non. Amet dictum sit amet justo donec enim. - -Mattis ullamcorper velit sed ullamcorper morbi tincidunt. Tortor posuere ac ut consequat semper viverra. Tellus mauris a diam maecenas sed enim ut sem viverra. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Arcu ac tortor dignissim convallis aenean et tortor at. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Egestas tellus rutrum tellus pellentesque eu. Fusce ut placerat orci nulla pellentesque dignissim enim sit amet. Ut enim blandit volutpat maecenas volutpat blandit aliquam etiam. Id donec ultrices tincidunt arcu. Id cursus metus aliquam eleifend mi. - -Tempus quam pellentesque nec nam aliquam sem. Risus at ultrices mi tempus imperdiet. Id porta nibh venenatis cras sed felis eget velit. Ipsum a arcu cursus vitae. Facilisis magna etiam tempor orci eu lobortis elementum. Tincidunt dui ut ornare lectus sit. Quisque non tellus orci ac. Blandit libero volutpat sed cras. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin gravida. Egestas integer eget aliquet nibh praesent tristique magna. diff --git a/src/content/config.ts b/src/content/config.ts index 23e5233..baa993f 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -1,15 +1,12 @@ import { defineCollection, z } from 'astro:content'; -const blog = defineCollection({ +const roadmap = defineCollection({ // Type-check frontmatter using a schema schema: z.object({ title: z.string(), description: z.string(), - // Transform string to Date object - pubDate: z.coerce.date(), - updatedDate: z.coerce.date().optional(), - heroImage: z.string().optional(), + level: z.string(), }), }); -export const collections = { blog }; +export const collections = { roadmap }; diff --git a/src/content/roadmap/backend-beginner.md b/src/content/roadmap/backend-beginner.md new file mode 100644 index 0000000..906a12e --- /dev/null +++ b/src/content/roadmap/backend-beginner.md @@ -0,0 +1,15 @@ +--- +title: 'Backend Developer' +description: 'เส้นทางการเรียนรู้สู่การเตรียมพร้อมเป็น Backend Developer + ฉบับพื้นฐาน' +level: 'beginner' +--- + +Coming Soon! + + diff --git a/src/content/roadmap/frontend-beginner.md b/src/content/roadmap/frontend-beginner.md new file mode 100644 index 0000000..b427355 --- /dev/null +++ b/src/content/roadmap/frontend-beginner.md @@ -0,0 +1,63 @@ +--- +title: 'Frontend Developer' +description: 'เส้นทางการเรียนรู้สู่การเตรียมพร้อมเป็น Frontend Developer + ฉบับพื้นฐาน' +level: 'beginner' +--- + +ก่อนอื่นเลยต้องบอกว่า Roadmap ของ Frontend Developer นั้นสามารถเรียนรู้
ให้จบได้ภายในเวลาเพียง 1 ชั่วโมง เท่านั้นซึ่งแนะนำมาก ๆ ให้ทุกคนลองเรียนดูก่อนที่จะมางาน Thinc First Act + +โดยในบทความนี้จะมีลิงก์ไปยังเว็บไซต์อื่น ๆ ซึ่งแบ่งออกเป็นประเภทดังนี้ + +| ลิงก์ | เวลา | เนื้อหา | | +| ----------- | ---------- | ----------------- | ------------------------------------------------------------------------------------------------------------ | +| ลิงก์แรก | น้อยที่สุด | สรุปและเข้าใจง่าย | วีดีโอที่สั้นและสรุปเนื้อหาให้เข้าได้ง่าย | +| ลิงก์ที่สอง | ปานกลาง | ครอบคลุม | วีดีโอที่ยาว สามารถเข้าใจง่าย และครอบคลุมเนื้อหาทั้งหมด | +| ลิงก์ที่สาม | - | ครบถ้วนมากที่สุด | เว็บไซต์ที่สามารถเรียนรู้ได้ด้วยตัวเองและเนื้อหาครบถ้วนมากที่สุด
สามารถกลับมาดูเพื่อทวนได้เรื่อย ๆ เลย | + +และในแต่ละหัวข้อจะมีลิงก์ที่ต่อยอดจากพื้นฐานเพื่อเรียนรู้เพิ่มเติมต่อได้ + +## Fundamentals + +HTML CSS และ JavaScript นั้นคือ 3 ภาษาที่สามารถเรียกได้ว่าสำคัญที่สุดเลยในการสร้างเว็บไซต์ + +### HTML + +HTML หรือ HyperText Markup Language คือภาษาพื้นฐานที่เป็นเหมือนกับโครงสร้างของเว็บไซต์
ซึ่งเป็นภาษาที่ง่ายที่สุดในการเรียนรู้ + +- [มาเรียนเขียนเว็บด้วย HTML 5 !! ฉบับที่เร็วที่สุด !](https://www.youtube.com/watch?v=-jzu5YH6OMQ) +- [HTML Full Course - Build a Website Tutorial](https://www.youtube.com/watch?v=pQN-pnXPaVg) +- [W3Schools: Learn HTML](https://www.w3schools.com/html/html_intro.asp) + +Tips: ถ้าหากว่าอยากต่อยอดสกิลในการเขียน HTML สามารถเรียนรู้ได้จากการเรียนรู้เกี่ยวกับ Semantic HTML และ SEO ได้ + +- [Why & When to Use Semantic HTML Elements over Divs](https://www.youtube.com/watch?v=bOUhq46fd5g) +- [Complete SEO Course for Beginners: Learn to Rank #1 in Google](https://www.youtube.com/watch?v=xsVTqzratPs) + +### CSS + +CSS หรือ Cascading Style Sheets คือภาษาที่ใช้ในการจัดรูปแบบหน้าเว็บไซต์ ให้มีความสวยงาม + +ภาษานี้อาจจะเป็นภาษาที่ใช้เวลานานในการเรียนรู้ แต่เพียงแค่รู้พื้นฐานก็สามารถใช้งานได้แล้ว และสามารถเรียนรู้เพิ่มเติมได้ต่อไประหว่างการทำงานได้ไม่ยากเลย + +- [มาหัดเขียน CSS3 ที่ช่วยให้เว็บสวยขึ้น แบบไว ๆ ใน 10 นาที](https://www.youtube.com/watch?v=9H6ubALp8vo2) +- [CSS Masterclass](https://www.youtube.com/watch?v=FqmB-Zj2-PA) +- [W3Schools: Learn CSS](https://www.w3schools.com/css/) + +Tips: อย่าลืมทำความรู้จักกับการออกแบบเว็บไซต์ให้เป็น Responsive เพื่อให้สามารถรองรับในอุปกรณ์ต่าง ๆ ได้ + +- [5 simple tips to making responsive layouts the easy way](https://www.youtube.com/watch?v=VQraviuwbzU) + +### JavaScript + +สุดท้ายแล้ว JavaScript คือภาษาที่สามารถทำให้เราสามารถเขียนโปรแกรมให้เว็บไซต์ของเราทำงานได้ + +JavaScript นั้นถือว่าเป็นภาษาที่ยากที่สุดใน 3 ภาษา แต่ก็เป็นภาษาที่เราจะได้ใช้งานและต่อยอดต่อไปในเนื้อหาต่อ ๆ ไป + +- [JavaScript Tutorial for Beginners: Learn JavaScript in 1 Hour](https://www.youtube.com/watch?v=W6NZfCO5SIk) +- [Learn JavaScript - Full Course for Beginners](https://www.youtube.com/watch?v=PkZNo7MFNFg) +- [The Modern JavaScript Tutorial](https://javascript.info/) + +Tips: สุดท้ายเราลองมานำ 3 ภาษาที่เรียนมาทั้งหมดมาใช้งานร่วมกันดูผ่านตัวอย่างเล็ก ๆ นี้ได้เลย + +- [Build a Netflix Landing Page Clone with HTML, CSS & JS](https://www.youtube.com/watch?v=P7t13SGytRk) diff --git a/src/pages/404.astro b/src/pages/404.astro new file mode 100644 index 0000000..218a603 --- /dev/null +++ b/src/pages/404.astro @@ -0,0 +1,8 @@ +--- +import Base from '@/templates/Base.astro'; +import { NotFound } from '@/partials/NotFound'; +--- + + + + diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro new file mode 100644 index 0000000..a81d6e1 --- /dev/null +++ b/src/pages/blog/index.astro @@ -0,0 +1,9 @@ +--- +import Base from '@/templates/Base.astro'; +import { Blogs, Title } from '@/partials/blog/Blog'; +--- + + + + <Blogs /> +</Base> diff --git a/src/pages/index.astro b/src/pages/index.astro index 8b6dc41..08df0e5 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,9 +1,13 @@ --- -import Base from "@/templates/Base.astro"; -import { Hero, Roadmap } from "@/partials/Landing"; +import { getCollection } from 'astro:content'; +import { Hero, Roadmaps, Blogs } from '@/partials/Landing'; +import Base from '@/templates/Base.astro'; + +const roadmaps = await getCollection('roadmap'); --- <Base title="Thinc Roadmap" description="Thinc Roadmap"> <Hero /> - <Roadmap /> + <Roadmaps roadmaps={roadmaps} /> + <Blogs client:load /> </Base> diff --git a/src/pages/roadmap.astro b/src/pages/roadmap.astro deleted file mode 100644 index 7287801..0000000 --- a/src/pages/roadmap.astro +++ /dev/null @@ -1,7 +0,0 @@ ---- -import Base from "@/templates/Base.astro"; ---- - -<Base title="Thinc Roadmap" description="Thinc Roadmap"> - <p>Thinc Roadmap</p> -</Base> diff --git a/src/pages/roadmap/[...slug].astro b/src/pages/roadmap/[...slug].astro new file mode 100644 index 0000000..472abd8 --- /dev/null +++ b/src/pages/roadmap/[...slug].astro @@ -0,0 +1,22 @@ +--- +import { type CollectionEntry, getCollection } from 'astro:content'; +import { Section } from '@/components/Section'; +import Base from '@/templates/Base.astro'; +import Roadmap from '@/templates/Roadmap.astro'; + +export async function getStaticPaths() { + const roadmaps = await getCollection('roadmap'); + return roadmaps.map((roadmap) => ({ + params: { slug: roadmap.slug }, + props: roadmap, + })); +} +type Props = CollectionEntry<'roadmap'>; + +const roadmap = Astro.props; +const { Content } = await roadmap.render(); +--- + +<Roadmap {...roadmap.data}> + <Content /> +</Roadmap> diff --git a/src/pages/roadmap/index.astro b/src/pages/roadmap/index.astro new file mode 100644 index 0000000..c922e06 --- /dev/null +++ b/src/pages/roadmap/index.astro @@ -0,0 +1,12 @@ +--- +import { getCollection } from 'astro:content'; +import Base from '@/templates/Base.astro'; +import { Title, Roadmaps } from '@/partials/roadmap/Roadmap'; + +const roadmaps = await getCollection('roadmap'); +--- + +<Base title="Thinc Roadmap" description="Thinc Roadmap"> + <Title /> + <Roadmaps roadmaps={roadmaps} /> +</Base> diff --git a/src/pages/rss.xml.ts b/src/pages/rss.xml.ts deleted file mode 100644 index 7faf0f6..0000000 --- a/src/pages/rss.xml.ts +++ /dev/null @@ -1,17 +0,0 @@ -import rss from '@astrojs/rss'; -import { getCollection } from 'astro:content'; - -import { SITE_DESCRIPTION, SITE_TITLE } from '../consts'; - -export async function GET(context: any) { - const posts = await getCollection('blog'); - return rss({ - title: SITE_TITLE, - description: SITE_DESCRIPTION, - site: context.site, - items: posts.map((post) => ({ - ...post.data, - link: `/blog/${post.slug}/`, - })), - }); -} diff --git a/src/partials/Footer.tsx b/src/partials/Footer.tsx index c11432b..90b8e56 100644 --- a/src/partials/Footer.tsx +++ b/src/partials/Footer.tsx @@ -1,7 +1,17 @@ export const Footer = () => { return ( - <section className="flex w-full justify-center px-4"> - <div className="w-full max-w-screen-lg">Footer</div> + <section className="flex w-full justify-center"> + <div className="flex w-full max-w-screen-lg flex-col items-center px-8 pb-20 pt-10"> + <div className="w-24"> + <img + className="h-full w-auto select-none" + src="/images/thinc-logo-alt.svg" + alt="Thinc Logo" + loading="eager" + /> + </div> + <p className="mb-0 mt-4 text-slate-400">© THINC. 2023</p> + </div> </section> ); }; diff --git a/src/partials/Header.tsx b/src/partials/Header.tsx deleted file mode 100644 index 60f165f..0000000 --- a/src/partials/Header.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export const Header = () => { - return ( - <header className="flex w-full justify-center px-6 md:px-4"> - <div className="h-20 w-full max-w-screen-lg py-6 md:h-24"> - <img - className="h-full w-auto" - src="/images/thinc-logo-alt.svg" - alt="Thinc Logo" - loading="eager" - /> - </div> - </header> - ); -}; diff --git a/src/partials/Landing.tsx b/src/partials/Landing.tsx index c5d1fbe..62381a7 100644 --- a/src/partials/Landing.tsx +++ b/src/partials/Landing.tsx @@ -1,44 +1,131 @@ +// @ts-ignore +import getSrc from 'get-src'; +import Parser from 'rss-parser'; + +import { BlogCard } from '@/components/blog/BlogCard'; +import { RoadmapCard } from '@/components/roadmap/RoadmapCard'; import { Section } from '@/components/Section'; export const Hero = () => { return ( - <Section className="h-[65vh] bg-gradient-to-b from-thinc-blue to-slate-950 md:h-[70vh]"> + <Section className="h-[60vh] bg-gradient-to-b from-thinc-blue to-slate-950 md:h-[65vh]"> <div className="flex flex-col items-center space-y-6 py-16 text-center md:py-20"> + <span className="-mb-3.5 font-semibold uppercase text-thinc-accent"> + Get Ready For + </span> <h1 className="text-3xl font-semibold md:text-5xl"> Thinc First Act 2023 </h1> <p className="max-w-xl text-slate-400"> - Lorem ipsum dolor sit amet consectetur adipisicing elit. - Adipisci beatae eveniet vero a consectetur pariatur at - laboriosam perferendis libero dolorum autem non blanditiis - nostrum. + กิจกรรมที่พี่ ๆ ในชมรม Thinc. + จะมาสอนและแชร์วิชาในการพัฒนาโปรแกรมพร้อมทั้งวิธีการ + Implement ผลงานตัวเองในแบบพื้นฐานที่สุด + ในหลากหลายสายงานอย่าง Frontend, Backend, Project Manager, + และ UX/UI </p> + <div className="pt-10"> + <a + href="https://thinc.in.th/link/first_act" + target="_blank" + rel="noopener noreferrer" + className="rounded-lg bg-slate-50 px-8 py-3 font-semibold text-thinc-blue" + > + ลงทะเบียน + </a> + </div> </div> </Section> ); }; -export const Roadmap = () => { +export const Roadmaps = ({ + roadmaps, +}: { + roadmaps: { + id: string; + slug: string; + data: { + title: string; + description: string; + level: string; + }; + }[]; +}) => { return ( - <Section className="min-h-screen bg-white text-slate-600"> + <Section className="bg-white pb-10 text-slate-600"> <div className="flex w-full flex-col space-y-16"> <div className="space-y-6"> - <h2 className="text-xl font-bold text-slate-800 md:text-2xl"> - Developer Roadmap - </h2> - <div className="h-40 w-full cursor-pointer rounded-lg border-2 bg-slate-50"></div> - <div className="h-40 w-full cursor-pointer rounded-lg border-2 bg-slate-50"></div> - <div className="relative h-40 select-none opacity-80"> + <div className="space-y-1"> + <h2 className="text-xl font-bold text-slate-800 md:text-2xl"> + Developer Roadmap + </h2> + <p> + แหล่งรวมเส้นทางในการเริ่มต้นเรียนรู้ทักษะการเขียนโปรแกรมและพัฒนาซอฟต์แวร์ + </p> + </div> + {roadmaps?.map((roadmap) => ( + <RoadmapCard + key={roadmap.id} + slug={roadmap.slug} + level={roadmap.data.level} + title={roadmap.data.title} + description={roadmap.data.description} + /> + ))} + {/* <div className="relative h-40 select-none opacity-80"> <div className="absolute z-10 grid h-full w-full place-content-center bg-gradient-to-b from-transparent to-white"></div> <div className="absolute grid h-full w-full place-content-center rounded-lg border-2 bg-slate-50"> <p>Coming Soon...</p> </div> - </div> + </div> */} </div> + </div> + </Section> + ); +}; + +const parser = new Parser(); +const feed = await parser.parseURL('https://medium.com/feed/thinc-org'); +const blogs = feed.items.slice(0, 4).map((item) => { + const imgSrc = getSrc(item['content:encoded']).replace('/1024/', '/400/'); + const content = item['content:encodedSnippet']; + return { + title: item.title, + date: item.pubDate, + creator: item.creator, + link: item.link, + imgSrc, + content, + }; +}); + +export const Blogs = () => { + return ( + <Section className="border-t bg-slate-50 pb-10 text-slate-600"> + <div className="flex w-full flex-col space-y-16"> <div className="space-y-6"> - <h2 className="text-xl font-bold text-slate-800 md:text-2xl"> - Blogs - </h2> + <div className="space-y-1"> + <h2 className="text-xl font-bold text-slate-800 md:text-2xl"> + Blogs + </h2> + <p> + บทความให้ความรู้สำหรับการพัฒนาซอฟต์แวร์จากพี่ ๆ + ในชมรม + </p> + </div> + + <div className="grid grid-cols-2 gap-8"> + {blogs.map((blog) => { + return ( + <BlogCard + key={blog.title} + title={blog.title ?? ''} + link={blog.link ?? ''} + imgSrc={blog.imgSrc} + /> + ); + })} + </div> </div> </div> </Section> diff --git a/src/partials/Navigation.tsx b/src/partials/Navigation.tsx new file mode 100644 index 0000000..46f1ade --- /dev/null +++ b/src/partials/Navigation.tsx @@ -0,0 +1,67 @@ +import { useState } from 'react'; +import { FiInstagram, FiMenu, FiX } from 'react-icons/fi'; + +export const Navigation = () => { + const [showNav, setShowNav] = useState(false); + + return ( + <> + {showNav && ( + <div className="fixed inset-0 z-50 flex flex-col bg-gradient-to-b from-thinc-blue to-slate-950 sm:hidden"> + <div className="flex justify-end px-8 pt-9"> + <button + onClick={() => setShowNav(false)} + className="grid h-10 place-content-center rounded-lg border border-slate-700 px-3 text-lg text-slate-400 duration-200 hover:bg-slate-800" + > + <FiX /> + </button> + </div> + </div> + )} + <header className="flex w-full justify-center drop-shadow-md"> + <div className="flex w-full max-w-screen-lg items-center justify-between px-8 sm:h-24"> + <div className="flex items-center space-x-12"> + <div className="h-20 py-5"> + <a href="/"> + <img + className="h-full w-auto select-none" + src="/images/thinc-logo-alt.svg" + alt="Thinc Logo" + loading="eager" + /> + </a> + </div> + <div className="mt-4 hidden items-center space-x-8 text-slate-400 sm:flex"> + <a href="/roadmap">Roadmap</a> + <a href="/blog">Blog</a> + </div> + </div> + <div className="flex items-center space-x-4 sm:mt-4"> + <a + href="https://thinc.in.th" + target="_blank" + rel="noopener noreferrer" + className="hidden h-8 place-content-center rounded-lg border border-slate-700 px-3 text-sm text-slate-400 duration-200 hover:bg-slate-800 sm:grid" + > + Main Site + </a> + <a + href="https://www.instagram.com/thinc.in.th" + target="_blank" + rel="noopener noreferrer" + className="hidden h-8 place-content-center rounded-lg border border-slate-700 px-2.5 text-slate-400 duration-200 hover:bg-slate-800 sm:grid" + > + <FiInstagram /> + </a> + <button + onClick={() => setShowNav(true)} + className="grid h-10 place-content-center rounded-lg border border-slate-700 px-3 text-lg text-slate-400 duration-200 hover:bg-slate-800 sm:hidden" + > + <FiMenu /> + </button> + </div> + </div> + </header> + </> + ); +}; diff --git a/src/partials/NotFound.tsx b/src/partials/NotFound.tsx new file mode 100644 index 0000000..422da9a --- /dev/null +++ b/src/partials/NotFound.tsx @@ -0,0 +1,7 @@ +export const NotFound = () => { + return ( + <div className="grid h-screen w-full place-content-center bg-thinc-blue"> + <img src="/images/404.png" alt="404" /> + </div> + ); +}; diff --git a/src/partials/blog/Blog.tsx b/src/partials/blog/Blog.tsx new file mode 100644 index 0000000..fc1a245 --- /dev/null +++ b/src/partials/blog/Blog.tsx @@ -0,0 +1,52 @@ +// @ts-ignore +import getSrc from 'get-src'; +import Parser from 'rss-parser'; + +import { BlogCard } from '@/components/blog/BlogCard'; +import { Section } from '@/components/Section'; + +export const Title = () => { + return ( + <Section className="bg-white py-4 text-slate-600"> + <h1 className="text-2xl font-semibold text-slate-800 sm:text-5xl"> + Thinc Blogs + </h1> + <p className="mt-2"> + บทความให้ความรู้สำหรับการพัฒนาซอฟต์แวร์จากพี่ ๆ ในชมรม + </p> + </Section> + ); +}; + +const parser = new Parser(); +const feed = await parser.parseURL('https://medium.com/feed/thinc-org'); +const blogs = feed.items.slice(0, 4).map((item) => { + const imgSrc = getSrc(item['content:encoded']).replace('/1024/', '/400/'); + const content = item['content:encodedSnippet']; + return { + title: item.title, + date: item.pubDate, + creator: item.creator, + link: item.link, + imgSrc, + content, + }; +}); +export const Blogs = () => { + return ( + <Section className="h-screen border-t bg-slate-50"> + <div className="grid grid-cols-2 gap-8"> + {blogs.map((blog) => { + return ( + <BlogCard + key={blog.title} + title={blog.title ?? ''} + link={blog.link ?? ''} + imgSrc={blog.imgSrc} + /> + ); + })} + </div> + </Section> + ); +}; diff --git a/src/partials/roadmap/Header.tsx b/src/partials/roadmap/Header.tsx new file mode 100644 index 0000000..53231c0 --- /dev/null +++ b/src/partials/roadmap/Header.tsx @@ -0,0 +1,24 @@ +export const Header = ({ + title, + description, +}: { + title: string; + description: string; +}) => { + return ( + <div className="flex w-full max-w-screen-lg flex-col px-8 pb-8 pt-6 md:flex-row md:items-end md:justify-between"> + <div> + <span className="text-sm font-bold uppercase text-thinc-accent"> + Roadmap + </span> + <h1 className="mt-0 text-3xl font-semibold text-white"> + {title} + </h1> + <p className="mt-0.5 text-slate-400 md:text-lg"> + {description} + </p> + </div> + <button></button> + </div> + ); +}; diff --git a/src/partials/roadmap/Roadmap.tsx b/src/partials/roadmap/Roadmap.tsx new file mode 100644 index 0000000..3e7a110 --- /dev/null +++ b/src/partials/roadmap/Roadmap.tsx @@ -0,0 +1,47 @@ +import { RoadmapCard } from '@/components/roadmap/RoadmapCard'; +import { Section } from '@/components/Section'; + +export const Title = () => { + return ( + <Section className="bg-white py-4 text-slate-600"> + <h1 className="text-2xl font-semibold text-slate-800 sm:text-5xl"> + Developer Roadmaps + </h1> + <p className="mt-2"> + แหล่งรวมเส้นทางในการเริ่มต้นเรียนรู้ทักษะการเขียนโปรแกรมและพัฒนา + Software + </p> + </Section> + ); +}; + +export const Roadmaps = ({ + roadmaps, +}: { + roadmaps: { + id: string; + slug: string; + data: { + title: string; + description: string; + level: string; + }; + }[]; +}) => { + return ( + <Section className="h-screen border-t bg-slate-50"> + <div className="space-y-6"> + {roadmaps?.map((roadmap) => ( + <RoadmapCard + key={roadmap.id} + slug={roadmap.slug} + level={roadmap.data.level} + title={roadmap.data.title} + description={roadmap.data.description} + className="bg-white" + /> + ))} + </div> + </Section> + ); +}; diff --git a/src/styles/content.css b/src/styles/content.css new file mode 100644 index 0000000..604ea0e --- /dev/null +++ b/src/styles/content.css @@ -0,0 +1,77 @@ +.content body { + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.7; +} +.content h1, +.content h2, +.content h3 { + font-weight: 700; + margin: 3rem 0 1rem 0; + line-height: 1.2; + color: #1e293b; +} +.content h1 { + font-size: 2em; +} +.content h2 { + font-size: 1.8em; +} +.content h3 { + font-size: 1.4em; +} + +.content strong, +.content b { + font-weight: 700; +} +.content a { + color: #0f172a; + font-weight: 500; + text-decoration: underline; +} +.content a:hover { + color: #334155; +} +.content p { + margin-bottom: 1em; + color: #334155; +} +.content code { + padding: 2px 5px; + background-color: #303030; + border-radius: 2px; +} +.content pre { + padding: 1.5em; + border-radius: 8px; +} +.content pre > code { + all: unset; +} +.content blockquote { + border-left: 4px solid #fec92b; + padding: 0 0 0 20px; + margin: 0px; +} +.content hr { + border: none; + border-top: 1px solid rgb(var(--gray-light)); +} +.content ul { + margin: -0.2em 0 3em 0; +} +.content ul li::before { + content: '\2022'; + opacity: 0.3; + font-size: 1.3em; + padding-right: 0.5em; +} +.content table { + text-align: left; + margin-bottom: 1em; +} +.content table th, +.content table td { + padding: 0.5em 1em; +} diff --git a/src/templates/Base.astro b/src/templates/Base.astro index f0247b3..43be8ae 100644 --- a/src/templates/Base.astro +++ b/src/templates/Base.astro @@ -1,61 +1,35 @@ --- -import '@/styles/global.css' -import { Header } from "@/partials/Header"; -import { Footer } from "@/partials/Footer"; +import { Footer } from '@/partials/Footer'; +import { Navigation } from '@/partials/Navigation'; +import BaseHead from '@/templates/BaseHead.astro'; export interface Props { title: string; description: string; + hideNav?: boolean; + hideFooter?: boolean; image?: string; } -const canonicalURL = new URL(Astro.url.pathname, Astro.site); - -const { title, description, image = "/blog-placeholder-1.jpg" } = Astro.props; +const { + title, + description, + hideNav, + hideFooter, + image = '/blog-placeholder-1.jpg', +} = Astro.props; --- -<!doctype html> <html lang="th"> <head> - <!-- 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} /> - - <!-- Font preloads --> - <link rel="preconnect" href="https://fonts.googleapis.com"> - <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> - <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Thai:wght@100;200;300;400;500;600;700&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet"> - - <!-- Canonical URL --> - <link rel="canonical" href={canonicalURL} /> - - <!-- Primary Meta Tags --> - <title>{title} - - - - - - - - - - - - - - - - - + -
+ {!hideNav && }
-