Skip to content

Commit

Permalink
feat: ⚡️ add duckdb integration and dark mode support
Browse files Browse the repository at this point in the history
Initial setup with DuckDB for data loading and theme toggle component for dark mode
  • Loading branch information
davidgasquez committed Jan 3, 2025
1 parent 0fbe6c7 commit 09f7cab
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 33 deletions.
81 changes: 81 additions & 0 deletions web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"astro": "astro"
},
"dependencies": {
"@duckdb/node-api": "^1.1.3-alpha.8",
"astro": "^5.1.1"
}
}
6 changes: 3 additions & 3 deletions web/src/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
79 changes: 79 additions & 0 deletions web/src/components/ThemeToggle.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
---

<button id="themeToggle">
<svg width="30px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
class="sun"
fill-rule="evenodd"
d="M12 17.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0 1.5a7 7 0 1 0 0-14 7 7 0 0 0 0 14zm12-7a.8.8 0 0 1-.8.8h-2.4a.8.8 0 0 1 0-1.6h2.4a.8.8 0 0 1 .8.8zM4 12a.8.8 0 0 1-.8.8H.8a.8.8 0 0 1 0-1.6h2.5a.8.8 0 0 1 .8.8zm16.5-8.5a.8.8 0 0 1 0 1l-1.8 1.8a.8.8 0 0 1-1-1l1.7-1.8a.8.8 0 0 1 1 0zM6.3 17.7a.8.8 0 0 1 0 1l-1.7 1.8a.8.8 0 1 1-1-1l1.7-1.8a.8.8 0 0 1 1 0zM12 0a.8.8 0 0 1 .8.8v2.5a.8.8 0 0 1-1.6 0V.8A.8.8 0 0 1 12 0zm0 20a.8.8 0 0 1 .8.8v2.4a.8.8 0 0 1-1.6 0v-2.4a.8.8 0 0 1 .8-.8zM3.5 3.5a.8.8 0 0 1 1 0l1.8 1.8a.8.8 0 1 1-1 1L3.5 4.6a.8.8 0 0 1 0-1zm14.2 14.2a.8.8 0 0 1 1 0l1.8 1.7a.8.8 0 0 1-1 1l-1.8-1.7a.8.8 0 0 1 0-1z"
></path>
<path
class="moon"
fill-rule="evenodd"
d="M16.5 6A10.5 10.5 0 0 1 4.7 16.4 8.5 8.5 0 1 0 16.4 4.7l.1 1.3zm-1.7-2a9 9 0 0 1 .2 2 9 9 0 0 1-11 8.8 9.4 9.4 0 0 1-.8-.3c-.4 0-.8.3-.7.7a10 10 0 0 0 .3.8 10 10 0 0 0 9.2 6 10 10 0 0 0 4-19.2 9.7 9.7 0 0 0-.9-.3c-.3-.1-.7.3-.6.7a9 9 0 0 1 .3.8z"
></path>
</svg>
</button>

<style>
#themeToggle {
border: 0;
background: none;
}

#themeToggle:hover {
cursor: pointer;
opacity: 0.6;
}

.sun {
fill: black;
}
.moon {
fill: transparent;
}

:global(.dark) .sun {
fill: transparent;
}
:global(.dark) .moon {
fill: white;
}
</style>

<script>
const theme = (() => {
if (
typeof localStorage !== "undefined" &&
localStorage.getItem("theme")
) {
return localStorage.getItem("theme") ?? "light";
}
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
return "dark";
}
return "light";
})();

if (theme === "light") {
document.documentElement.classList.remove("dark");
} else {
document.documentElement.classList.add("dark");
}

window.localStorage.setItem("theme", theme);

const handleToggleClick = () => {
const element = document.documentElement;
element.classList.toggle("dark");

const isDark = element.classList.contains("dark");
localStorage.setItem("theme", isDark ? "dark" : "light");
};

document
.getElementById("themeToggle")
?.addEventListener("click", handleToggleClick);
</script>
37 changes: 37 additions & 0 deletions web/src/content.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { DuckDBInstance } from '@duckdb/node-api';
import { defineCollection, z } from 'astro:content';

const countries = defineCollection({
schema: z.object({
id: z.string(),
name: z.string(),
data: z.any(),
}),

loader: async () => {
const instance = await DuckDBInstance.create("/tmp/datadex.duckdb");
const connection = await instance.connect();

await connection.run(`
create table if not exists world_development_indicators as
select * from 'https://huggingface.co/datasets/datonic/world_development_indicators/resolve/main/data/world_development_indicators.parquet'
`);

const reader = await connection.runAndReadAll(`
select distinct country_code, country_name
from world_development_indicators
where country_code is not null
`);

const data = reader.getRows();

console.log(data);

return data.map((country: any) => ({
id: country[0],
name: country[1]
}));
}
});

export const collections = { countries };
44 changes: 34 additions & 10 deletions web/src/layouts/Layout.astro
Original file line number Diff line number Diff line change
@@ -1,23 +1,47 @@
---
import "../styles.css";
import ThemeToggle from "../components/ThemeToggle.astro";
---

<!doctype html>
<html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Datadex</title>
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
<script is:inline>
const theme = (() => {
if (typeof localStorage !== "undefined") {
const storedTheme = localStorage.getItem("theme");
if (storedTheme) {
return storedTheme;
}
}
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
return "dark";
}
return "light";
})();
document.documentElement.classList[
theme === "dark" ? "add" : "remove"
]("dark");
</script>
</head>
<body>
<div style="position: fixed; top: 1rem; right: 1rem; z-index: 999;">
<ThemeToggle />
</div>
<slot />
<footer
style="position: relative; width: 100%; text-align: center; padding: 10px 0; margin-top: 20px;"
>
<p>
<a href="mailto:[email protected]">Reach Out</a> or explore
the project <a href="https://github.com/datonic/datadex"
>on GitHub</a
>.
</p>
</footer>
</body>

<footer
style="position: relative; width: 100%; text-align: center; padding: 10px 0; margin-top: 20px;"
>
<p>
<a href="mailto:[email protected]">Reach Out</a> or explore the
project <a href="https://github.com/datonic/datadex">on GitHub</a>.
</p>
</footer>
</html>
69 changes: 69 additions & 0 deletions web/src/pages/countries/[...id].astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
import { getCollection, render } from "astro:content";
import { DuckDBInstance } from "@duckdb/node-api";
import Layout from "../../layouts/Layout.astro";
export async function getStaticPaths() {
const countries = await getCollection("countries");
return countries.map((country) => ({
params: { id: country.id },
props: { country },
}));
}
const instance = await DuckDBInstance.create("/tmp/datadex.duckdb");
const connection = await instance.connect();
await connection.run(`
create table if not exists world_development_indicators as
select * from 'https://huggingface.co/datasets/datonic/world_development_indicators/resolve/main/data/world_development_indicators.parquet'
`);
const reader = await connection.runAndReadAll(`
select
country_name,
country_code,
indicator_name,
year,
indicator_value
from world_development_indicators
where country_code = '${Astro.params.id}'
order by indicator_name desc, year desc
limit 10
`);
const rows = reader.getRows();
const { country } = Astro.props;
const { Content } = await render(country);
---

<Layout>
<h1>{country.data.name}</h1>

<table>
<thead>
<tr>
<th>Country Name</th>
<th>Country Code</th>
<th>Indicator Name</th>
<th>Year</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{
rows.map((row) => (
<tr>
<td>{row[0]}</td>
<td>{row[1]}</td>
<td>{row[2]}</td>
<td>{row[3]}</td>
<td>{row[4]}</td>
</tr>
))
}
</tbody>
</table>

<Content />
</Layout>
Loading

0 comments on commit 09f7cab

Please sign in to comment.