├── README.md ├── .husky ├── commit-msg └── pre-commit ├── firestore.indexes.json ├── .env.production ├── .firebaserc ├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── assets │ ├── pop.mp3 │ ├── blog │ │ ├── hello-world │ │ │ └── banner.jpg │ │ ├── custom-layout-in-nextjs │ │ │ └── banner.jpg │ │ └── data-fetching-in-nextjs │ │ │ └── banner.jpg │ └── projects │ │ └── twitter-clone │ │ └── banner.png └── site.webmanifest ├── firebase.json ├── .prettierignore ├── commitlint.config.ts ├── renovate.json ├── src ├── components │ ├── ui │ │ ├── accent.tsx │ │ ├── loading.tsx │ │ ├── lazy-image.tsx │ │ ├── button.tsx │ │ └── tooltip.tsx │ ├── content │ │ ├── mdx-components.tsx │ │ ├── views-counter.tsx │ │ ├── table-of-contents.tsx │ │ ├── custom-pre.tsx │ │ └── likes-counter.tsx │ ├── layout │ │ ├── layout.tsx │ │ ├── header.tsx │ │ ├── footer.tsx │ │ └── content-layout.tsx │ ├── link │ │ ├── custom-link.tsx │ │ └── unstyled-link.tsx │ ├── common │ │ ├── app-head.tsx │ │ ├── theme-switch.tsx │ │ ├── seo.tsx │ │ └── currently-playing-card.tsx │ ├── guestbook │ │ ├── guestbook-card.tsx │ │ ├── guestbook-form.tsx │ │ └── guestbook-entry.tsx │ ├── blog │ │ ├── blog-tag.tsx │ │ ├── blog-stats.tsx │ │ ├── subscribe-card.tsx │ │ ├── blog-card.tsx │ │ └── sort-listbox.tsx │ ├── project │ │ ├── project-card.tsx │ │ ├── project-stats.tsx │ │ └── tech-icons.tsx │ ├── statistics │ │ ├── sort-icon.tsx │ │ └── table.tsx │ └── modal │ │ ├── modal.tsx │ │ └── image-preview.tsx ├── pages │ ├── _document.tsx │ ├── api │ │ ├── auth │ │ │ └── [...nextauth].ts │ │ ├── content │ │ │ └── [type].ts │ │ ├── statistics │ │ │ └── [type].ts │ │ ├── views │ │ │ └── [slug].ts │ │ ├── guestbook │ │ │ ├── [id].tsx │ │ │ └── index.ts │ │ └── likes │ │ │ └── [slug].ts │ ├── subscribe.tsx │ ├── _app.tsx │ ├── projects.tsx │ ├── 404.tsx │ ├── blog │ │ ├── hello-world.mdx │ │ ├── custom-layout-in-nextjs.mdx │ │ └── data-fetching-in-nextjs.mdx │ ├── statistics.tsx │ ├── guestbook.tsx │ ├── projects │ │ └── twitter-clone.mdx │ ├── design.tsx │ ├── about.tsx │ ├── index.tsx │ └── blog.tsx ├── lib │ ├── hooks │ │ ├── use-mounted.ts │ │ ├── use-modal.ts │ │ ├── use-currently-playing.ts │ │ ├── use-local-storage.ts │ │ ├── use-session-storage.ts │ │ ├── use-content-likes.ts │ │ ├── use-heading-data.ts │ │ ├── use-content-views.ts │ │ ├── use-guestbook.ts │ │ ├── use-active-heading.ts │ │ ├── use-currently-playing-sse.ts │ │ └── use-lanyard.ts │ ├── types │ │ ├── currently-playing.ts │ │ ├── statistics.ts │ │ ├── github.ts │ │ ├── contents.ts │ │ ├── helper.ts │ │ ├── guestbook.ts │ │ ├── meta.ts │ │ └── api.ts │ ├── firebase │ │ ├── collections.ts │ │ └── app.ts │ ├── fetcher.ts │ ├── helper-server-node.ts │ ├── env.ts │ ├── env-server.ts │ ├── helper.ts │ ├── transition.ts │ ├── helper-server.ts │ ├── mdx.ts │ ├── mdx-utils.ts │ ├── format.ts │ └── api.ts ├── styles │ ├── nprogress.scss │ ├── table.scss │ ├── mdx.scss │ └── globals.scss └── middleware.ts ├── .prettierrc.mjs ├── firestore.rules ├── postcss.config.mjs ├── .env.development ├── .gitignore ├── tailwind.config.ts ├── tsconfig.json ├── .github └── workflows │ └── deployment.yaml ├── next.config.mjs ├── package.json └── eslint.config.ts /README.md: -------------------------------------------------------------------------------- 1 | # Portofolio 2 | 3 | Coming soon... 4 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no -- commitlint --edit $1 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm run type-check 2 | npm run lint 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /firestore.indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "indexes": [], 3 | "fieldOverrides": [] 4 | } 5 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | # Preview URL 2 | NEXT_PUBLIC_URL=https://$NEXT_PUBLIC_VERCEL_URL 3 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "portofolio-ccrsxx" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccrsxx/portofolio/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccrsxx/portofolio/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccrsxx/portofolio/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/assets/pop.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccrsxx/portofolio/HEAD/public/assets/pop.mp3 -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "firestore": { 3 | "rules": "firestore.rules", 4 | "indexes": "firestore.indexes.json" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /public/assets/blog/hello-world/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccrsxx/portofolio/HEAD/public/assets/blog/hello-world/banner.jpg -------------------------------------------------------------------------------- /public/assets/projects/twitter-clone/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccrsxx/portofolio/HEAD/public/assets/projects/twitter-clone/banner.png -------------------------------------------------------------------------------- /public/assets/blog/custom-layout-in-nextjs/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccrsxx/portofolio/HEAD/public/assets/blog/custom-layout-in-nextjs/banner.jpg -------------------------------------------------------------------------------- /public/assets/blog/data-fetching-in-nextjs/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccrsxx/portofolio/HEAD/public/assets/blog/data-fetching-in-nextjs/banner.jpg -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # cache 2 | ./mypy_cache 3 | 4 | # testing 5 | /coverage 6 | 7 | # next.js 8 | /.next/ 9 | /out/ 10 | 11 | # production 12 | /build 13 | -------------------------------------------------------------------------------- /commitlint.config.ts: -------------------------------------------------------------------------------- 1 | import type { UserConfig } from '@commitlint/types'; 2 | 3 | export default { 4 | extends: ['@commitlint/config-conventional'] 5 | } satisfies UserConfig; 6 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base", "schedule:weekly", "group:allNonMajor"], 4 | "timezone": "Asia/Jakarta" 5 | } 6 | -------------------------------------------------------------------------------- /src/components/ui/accent.tsx: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren } from 'react'; 2 | 3 | export function Accent({ children }: PropsWithChildren): React.JSX.Element { 4 | return {children}; 5 | } 6 | -------------------------------------------------------------------------------- /.prettierrc.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | export default /** @satisfies {import('prettier').Config} */ ({ 4 | plugins: ['prettier-plugin-tailwindcss'], 5 | singleQuote: true, 6 | jsxSingleQuote: true, 7 | trailingComma: 'none' 8 | }); 9 | -------------------------------------------------------------------------------- /src/components/content/mdx-components.tsx: -------------------------------------------------------------------------------- 1 | import { CustomLink } from '@components/link/custom-link'; 2 | import { CustomPre } from './custom-pre'; 3 | import type { MDXComponents } from 'mdx/types'; 4 | 5 | export const components: MDXComponents = { 6 | a: CustomLink, 7 | pre: CustomPre 8 | }; 9 | -------------------------------------------------------------------------------- /firestore.rules: -------------------------------------------------------------------------------- 1 | rules_version = '2'; 2 | service cloud.firestore { 3 | match /databases/{database}/documents { 4 | match /contents/{slug} { 5 | allow read, create, update: if true; 6 | } 7 | 8 | match /guestbook/{guestbookId} { 9 | allow read, create, delete: if true; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document'; 2 | 3 | export default function Document(): React.JSX.Element { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** 4 | * @typedef {Object} Config 5 | * @property {Record<'tailwindcss' | 'autoprefixer', Record>} plugins 6 | */ 7 | 8 | /** @type {Config} */ 9 | const config = { 10 | plugins: { 11 | tailwindcss: {}, 12 | autoprefixer: {} 13 | } 14 | }; 15 | 16 | export default config; 17 | -------------------------------------------------------------------------------- /src/components/layout/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Footer } from './footer'; 2 | import { Header } from './header'; 3 | import type { PropsWithChildren } from 'react'; 4 | 5 | export function Layout({ children }: PropsWithChildren): React.JSX.Element { 6 | return ( 7 | <> 8 |
9 | {children} 10 |