diff --git a/.gitignore b/.gitignore
index 5e0628f..652c866 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-public
# build output
dist/
diff --git a/public/favicon.svg b/public/favicon.svg
new file mode 100644
index 0000000..0f39062
--- /dev/null
+++ b/public/favicon.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/resume.pdf b/public/resume.pdf
new file mode 100644
index 0000000..5b0e5de
Binary files /dev/null and b/public/resume.pdf differ
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..da95c4e
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,5 @@
+User-agent: Googlebot
+Disallow: /nogooglebot/
+
+User-agent: *
+Allow: /
\ No newline at end of file
diff --git a/public/toggle-theme.js b/public/toggle-theme.js
new file mode 100644
index 0000000..146af33
--- /dev/null
+++ b/public/toggle-theme.js
@@ -0,0 +1,76 @@
+const primaryColorScheme = ""; // "light" | "dark"
+
+// Get theme data from local storage
+const currentTheme = localStorage.getItem("theme");
+
+function getPreferTheme() {
+ // return theme value in local storage if it is set
+ if (currentTheme) return currentTheme;
+
+ // return primary color scheme if it is set
+ if (primaryColorScheme) return primaryColorScheme;
+
+ // return user device's prefer color scheme
+ return window.matchMedia("(prefers-color-scheme: dark)").matches
+ ? "dark"
+ : "light";
+}
+
+let themeValue = getPreferTheme();
+
+function setPreference() {
+ localStorage.setItem("theme", themeValue);
+ reflectPreference();
+}
+
+function reflectPreference() {
+ document.firstElementChild.setAttribute("data-theme", themeValue);
+
+ document.querySelector("#theme-btn")?.setAttribute("aria-label", themeValue);
+
+ // Get a reference to the body element
+ const body = document.body;
+
+ // Check if the body element exists before using getComputedStyle
+ if (body) {
+ // Get the computed styles for the body element
+ const computedStyles = window.getComputedStyle(body);
+
+ // Get the background color property
+ const bgColor = computedStyles.backgroundColor;
+
+ // Set the background color in
+ document
+ .querySelector("meta[name='theme-color']")
+ ?.setAttribute("content", bgColor);
+ }
+}
+
+// set early so no page flashes / CSS is made aware
+reflectPreference();
+
+window.onload = () => {
+ function setThemeFeature() {
+ // set on load so screen readers can get the latest value on the button
+ reflectPreference();
+
+ // now this script can find and listen for clicks on the control
+ document.querySelector("#theme-btn")?.addEventListener("click", () => {
+ themeValue = themeValue === "light" ? "dark" : "light";
+ setPreference();
+ });
+ }
+
+ setThemeFeature();
+
+ // Runs on view transitions navigation
+ document.addEventListener("astro:after-swap", setThemeFeature);
+};
+
+// sync with system changes
+window
+ .matchMedia("(prefers-color-scheme: dark)")
+ .addEventListener("change", ({ matches: isDark }) => {
+ themeValue = isDark ? "dark" : "light";
+ setPreference();
+ });
diff --git a/src/pages/index.xml.ts b/src/pages/index.xml.ts
new file mode 100644
index 0000000..796695a
--- /dev/null
+++ b/src/pages/index.xml.ts
@@ -0,0 +1,21 @@
+import rss from "@astrojs/rss";
+import { getCollection } from "astro:content";
+import getSortedPosts from "@utils/getSortedPosts";
+import slugify from "@utils/slugify";
+import { SITE } from "@config";
+
+export async function GET() {
+ const posts = await getCollection("posts");
+ const sortedPosts = getSortedPosts(posts);
+ return rss({
+ title: SITE.title,
+ description: SITE.desc,
+ site: SITE.website,
+ items: sortedPosts.map(({ data }) => ({
+ link: `posts/${slugify(data)}`,
+ title: data.title,
+ description: data.description,
+ pubDate: new Date(data.date),
+ })),
+ });
+}