diff options
author | 2022-11-01 16:20:04 +0000 | |
---|---|---|
committer | 2022-11-01 16:20:04 +0000 | |
commit | 4e2bd173932c231697a17a3098dc22ef3e481525 (patch) | |
tree | 0cf7877436a1463d78dad231ef28ebd8116225fc /examples/hackernews | |
parent | bb6e8800094dc59841eb3b345fcb8baca9e17ce9 (diff) | |
download | astro-4e2bd173932c231697a17a3098dc22ef3e481525.tar.gz astro-4e2bd173932c231697a17a3098dc22ef3e481525.tar.zst astro-4e2bd173932c231697a17a3098dc22ef3e481525.zip |
Adds a Hackernews example site (#5213)
* adds the hackernews example - TODO add readme content
* refactor: moving styles from root.css into components
* chore: add README content
* chore: lint fixes + prettier-plugin-astro@0.4.0
* Update examples/hackernews/README.md
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
* lint: remove unused variable
* nit: adding check command to example
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
Diffstat (limited to 'examples/hackernews')
22 files changed, 845 insertions, 0 deletions
diff --git a/examples/hackernews/.gitignore b/examples/hackernews/.gitignore new file mode 100644 index 000000000..7329a851d --- /dev/null +++ b/examples/hackernews/.gitignore @@ -0,0 +1,20 @@ +# build output +dist/ +.output/ + +# 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 diff --git a/examples/hackernews/.vscode/extensions.json b/examples/hackernews/.vscode/extensions.json new file mode 100644 index 000000000..22a15055d --- /dev/null +++ b/examples/hackernews/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode"], + "unwantedRecommendations": [] +} diff --git a/examples/hackernews/.vscode/launch.json b/examples/hackernews/.vscode/launch.json new file mode 100644 index 000000000..d64220976 --- /dev/null +++ b/examples/hackernews/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/examples/hackernews/README.md b/examples/hackernews/README.md new file mode 100644 index 000000000..aeb16745a --- /dev/null +++ b/examples/hackernews/README.md @@ -0,0 +1,57 @@ +# Astro Starter Kit: Hackernews + +``` +npm create astro@latest -- --template hackernews +``` + +[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/hackernews) + +> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun! + +## 🚀 Project Structure + +Inside of your Astro project, you'll see the following folders and files: + +``` +/ +├── public/ +│ └── favicon.svg +├── src/ +│ ├── components/ +│ ├── layouts/ +│ │ └── Layout.astro +│ └── pages/ + └── stories/ + └── [id].astro + └── users/ + └── [id].astro +│ └── [...stories].astro +└── package.json +``` + +Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. Because the list of stories and users is always changing, dynamic routes like `[id].astro` are used to build pages when a specific page is requested. + +There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. + +Any static assets, like images, can be placed in the `public/` directory. + +## Server-side rendering (SSR) + +This project uses the [`@astrojs/node`](https://docs.astro.build/en/guides/integrations-guide/node/) adapter to deploy the SSR site to Node targets. Check out Astro's [deployment docs](https://docs.astro.build/en/guides/deploy/) for details on other adapters and hosting environments. + +## 🧞 Commands + +All commands are run from the root of the project, from a terminal: + +| Command | Action | +| :--------------------- | :----------------------------------------------- | +| `npm install` | Installs dependencies | +| `npm run dev` | Starts local dev server at `localhost:3000` | +| `npm run build` | Build your production site to `./dist/` | +| `npm run preview` | Preview your build locally, before deploying | +| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | +| `npm run astro --help` | Get help using the Astro CLI | + +## 👀 Want to learn more? + +Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). diff --git a/examples/hackernews/astro.config.mjs b/examples/hackernews/astro.config.mjs new file mode 100644 index 000000000..68ba7fac5 --- /dev/null +++ b/examples/hackernews/astro.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from 'astro/config'; +import node from '@astrojs/node'; + +// https://astro.build/config +export default defineConfig({ + output: 'server', + adapter: node({ + mode: 'standalone', + }), +}); diff --git a/examples/hackernews/package.json b/examples/hackernews/package.json new file mode 100644 index 000000000..ae79e4bfd --- /dev/null +++ b/examples/hackernews/package.json @@ -0,0 +1,18 @@ +{ + "name": "@example/hackernews", + "type": "module", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "check": "astro check && tsc", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/node": "^2.0.1", + "astro": "^1.5.2" + } +} diff --git a/examples/hackernews/public/favicon.svg b/examples/hackernews/public/favicon.svg new file mode 100644 index 000000000..0f3906297 --- /dev/null +++ b/examples/hackernews/public/favicon.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 36 36"> + <path fill="#000" d="M22.25 4h-8.5a1 1 0 0 0-.96.73l-5.54 19.4a.5.5 0 0 0 .62.62l5.05-1.44a2 2 0 0 0 1.38-1.4l3.22-11.66a.5.5 0 0 1 .96 0l3.22 11.67a2 2 0 0 0 1.38 1.39l5.05 1.44a.5.5 0 0 0 .62-.62l-5.54-19.4a1 1 0 0 0-.96-.73Z"/> + <path fill="url(#gradient)" d="M18 28a7.63 7.63 0 0 1-5-2c-1.4 2.1-.35 4.35.6 5.55.14.17.41.07.47-.15.44-1.8 2.93-1.22 2.93.6 0 2.28.87 3.4 1.72 3.81.34.16.59-.2.49-.56-.31-1.05-.29-2.46 1.29-3.25 3-1.5 3.17-4.83 2.5-6-.67.67-2.6 2-5 2Z"/> + <defs> + <linearGradient id="gradient" x1="16" x2="16" y1="32" y2="24" gradientUnits="userSpaceOnUse"> + <stop stop-color="#000"/> + <stop offset="1" stop-color="#000" stop-opacity="0"/> + </linearGradient> + </defs> + <style> + @media (prefers-color-scheme:dark){:root{filter:invert(100%)}} + </style> +</svg> diff --git a/examples/hackernews/sandbox.config.json b/examples/hackernews/sandbox.config.json new file mode 100644 index 000000000..9178af77d --- /dev/null +++ b/examples/hackernews/sandbox.config.json @@ -0,0 +1,11 @@ +{ + "infiniteLoopProtection": true, + "hardReloadOnChange": false, + "view": "browser", + "template": "node", + "container": { + "port": 3000, + "startScript": "start", + "node": "14" + } +} diff --git a/examples/hackernews/src/components/Comment.astro b/examples/hackernews/src/components/Comment.astro new file mode 100644 index 000000000..50fa3e9e4 --- /dev/null +++ b/examples/hackernews/src/components/Comment.astro @@ -0,0 +1,59 @@ +--- +import For from './For.astro'; +import Show from './Show.astro'; +import Toggle from './Toggle.astro'; +import type { IComment } from '../types.js'; + +export interface Props { + comment: IComment; +} + +const { comment } = Astro.props; +--- + +<li> + <div class="by"> + <a href={`/users/${comment.user}`}>{comment.user}</a>{' '} + {comment.time_ago} ago + </div> + <div class="text" set:html={comment.content}></div> + <Show when={comment.comments.length}> + <Toggle open> + <For each={comment.comments}>{(comment: IComment) => <Astro.self comment={comment} />}</For> + </Toggle> + </Show> +</li> + +<style> + li { + border-top: 1px solid #eee; + position: relative; + } + + .by, + .text { + font-size: 0.9em; + margin: 1em 0; + } + + .by { + color: rgb(51 65 85); + } + + .by a { + color: rgb(51 65 85); + text-decoration: underline; + } + + .text { + overflow-wrap: break-word; + } + + .text :global(a:hover) { + color: #335d92; + } + + .text :global(pre) { + white-space: pre-wrap; + } +</style> diff --git a/examples/hackernews/src/components/For.astro b/examples/hackernews/src/components/For.astro new file mode 100644 index 000000000..b784f8f8a --- /dev/null +++ b/examples/hackernews/src/components/For.astro @@ -0,0 +1,21 @@ +--- +import Show from './Show.astro'; + +export interface Props<T> { + each: Iterable<T>; +} + +const { each } = Astro.props; +--- + +{(async function* () { + for await (const value of each) { + let html = await Astro.slots.render('default', [value]); + yield <Fragment set:html={html} />; + yield '\n'; + } +})()} + +<Show when={!each.length}> + <slot name="fallback" /> +</Show> diff --git a/examples/hackernews/src/components/Nav.astro b/examples/hackernews/src/components/Nav.astro new file mode 100644 index 000000000..10bf0f899 --- /dev/null +++ b/examples/hackernews/src/components/Nav.astro @@ -0,0 +1,97 @@ +--- +interface Link { + href: string; + text: string; +} + +const links: Link[] = [ + { href: '/', text: 'HN' }, + { href: '/new', text: 'New' }, + { href: '/show', text: 'Show' }, + { href: '/ask', text: 'Ask' }, + { href: '/job', text: 'Jobs' }, +]; +--- + +<header> + <nav aria-label="Main menu"> + {links.map(({ href, text }) => ( + <a href={href} aria-current={href === Astro.url.pathname ? 'page' : undefined}> + <strong>{text}</strong> + </a> + ))} + <a class="github" href="http://github.com/withastro/astro" target="_blank" rel="noreferrer"> + Built with Astro + </a> + </nav> +</header> + +<style> + header { + background-color: rgb(107 33 168); + position: fixed; + z-index: 999; + height: 55px; + top: 0; + left: 0; + right: 0; + } + + nav { + max-width: 800px; + box-sizing: border-box; + margin: 0 auto; + padding: 15px 5px; + } + + nav a { + color: rgba(248, 250, 252, 0.8); + line-height: 24px; + transition: color 0.15s ease; + display: inline-block; + vertical-align: middle; + font-weight: 300; + letter-spacing: 0.075em; + margin-right: 1.8em; + } + + nav a:hover { + color: rgb(248 250 252); + } + + nav [aria-current='page'] { + color: rgb(248 250 252); + font-weight: 400; + } + + nav a:last-of-type { + margin-right: 0; + } + + .github { + color: rgb(248 250 252); + font-size: 0.9em; + margin: 0; + float: right; + } + + @media (max-width: 860px) { + nav { + padding: 15px 30px; + } + } + + @media (max-width: 600px) { + nav { + padding: 15px; + } + + a { + margin-right: 1em; + } + + .github { + display: none; + } + } +</style> diff --git a/examples/hackernews/src/components/Show.astro b/examples/hackernews/src/components/Show.astro new file mode 100644 index 000000000..7e0887784 --- /dev/null +++ b/examples/hackernews/src/components/Show.astro @@ -0,0 +1,9 @@ +--- +export interface Props<T> { + when: T | number | boolean | undefined | null; +} + +const { when } = Astro.props; +--- + +{!!when ? <slot /> : <slot name="fallback" />} diff --git a/examples/hackernews/src/components/Story.astro b/examples/hackernews/src/components/Story.astro new file mode 100644 index 000000000..ee43bab17 --- /dev/null +++ b/examples/hackernews/src/components/Story.astro @@ -0,0 +1,77 @@ +--- +import Show from './Show.astro'; +import type { IStory } from '../types.js'; + +export interface Props { + story: IStory; +} + +const { story } = Astro.props; +--- + +<li> + <span class="score">{story.points}</span> + <span class="title"> + <Show when={story.url}> + <a href={story.url} target="_blank" rel="noreferrer"> + {story.title} + </a> + <span class="host"> ({story.domain})</span> + <a slot="fallback" href={`/item/${story.id}`}>{story.title}</a> + </Show> + </span> + <br /> + <span class="meta"> + <Show when={story.type !== 'job'}> + by <a href={`/users/${story.user}`}>{story.user}</a>{' '} + {story.time_ago}{' '}|{' '} + <a href={`/stories/${story.id}`}> + {story.comments_count ? `${story.comments_count} comments` : 'discuss'} + </a> + <a slot="fallback" href={`/stories/${story.id}`}>{story.time_ago}</a> + </Show> + </span> + <Show when={story.type !== 'link'}> + + <span class="label">{story.type}</span> + </Show> +</li> + +<style> + li { + background-color: rgb(248 250 252); + padding: 20px 30px 20px 80px; + border-bottom: 1px solid #eee; + position: relative; + line-height: 20px; + } + + .score { + color: rgb(88 28 135); + font-size: 1.1em; + font-weight: 700; + position: absolute; + top: 50%; + left: 0; + width: 80px; + text-align: center; + margin-top: -10px; + } + + .host, + .meta { + font-size: 0.85em; + color: rgb(51 65 85); + } + + .host a, + .meta a { + color: rgb(51 65 85); + text-decoration: underline; + } + + .host a:hover, + .meta a:hover { + color: #335d92; + } +</style> diff --git a/examples/hackernews/src/components/Toggle.astro b/examples/hackernews/src/components/Toggle.astro new file mode 100644 index 000000000..87b686981 --- /dev/null +++ b/examples/hackernews/src/components/Toggle.astro @@ -0,0 +1,78 @@ +--- +export interface Props { + open?: boolean; +} + +const { open = false } = Astro.props; +--- + +<hn-toggle open={open ? '' : undefined}> + <div class="toggle"> + <a>{open ? '[-]' : '[+] comments collapsed'}</a> + </div> + <ul class="comment-children"> + <slot /> + </ul> +</hn-toggle> + +<style> + hn-toggle[open] > .toggle { + padding: 0; + background-color: transparent; + margin-bottom: -0.5em; + } + + hn-toggle:not([open]) > .toggle { + background-color: rgb(255 247 237); + } + hn-toggle:not([open]) ul { + display: none; + } + + .toggle { + font-size: 0.9em; + margin: 1em 0; + padding: 0.3em 0.5em; + border-radius: 4px; + } + + a { + color: rgb(51 65 85); + cursor: pointer; + } +</style> + +<script> + class HnToggle extends HTMLElement { + #btn = this.querySelector<HTMLAnchorElement>('a')!; + #toggleOpen = this.toggleOpen.bind(this); + + connectedCallback() { + this.#btn.addEventListener('click', this.#toggleOpen, false); + } + + disconnectedCallback() { + this.#btn.addEventListener('click', this.#toggleOpen); + } + + get open() { + return this.hasAttribute('open'); + } + + set open(value: boolean) { + if (value) { + this.setAttribute('open', ''); + this.#btn.textContent = '[-]'; + } else { + this.removeAttribute('open'); + this.#btn.textContent = '[+] comments collapsed'; + } + } + + toggleOpen() { + this.open = !this.open; + } + } + + customElements.define('hn-toggle', HnToggle); +</script> diff --git a/examples/hackernews/src/env.d.ts b/examples/hackernews/src/env.d.ts new file mode 100644 index 000000000..f964fe0cf --- /dev/null +++ b/examples/hackernews/src/env.d.ts @@ -0,0 +1 @@ +/// <reference types="astro/client" /> diff --git a/examples/hackernews/src/layouts/Layout.astro b/examples/hackernews/src/layouts/Layout.astro new file mode 100644 index 000000000..b1630da8a --- /dev/null +++ b/examples/hackernews/src/layouts/Layout.astro @@ -0,0 +1,35 @@ +--- +import Nav from '../components/Nav.astro'; +--- + +<html lang="en"> + <head> + <meta charset="utf-8" /> + <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <meta name="generator" content={Astro.generator} /> + <title>Astro - Hacker News</title> + <meta name="description" content="Hacker News Clone built with Astro" /> + </head> + <body> + <Nav /> + <slot /> + <style is:global> + body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, + Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + font-size: 15px; + background-color: rgb(226 232 240); + margin: 0; + padding-top: 55px; + color: rgb(15 23 42); + overflow-y: scroll; + } + + a { + color: rgb(15 23 42); + text-decoration: none; + } + </style> + </body> +</html> diff --git a/examples/hackernews/src/lib/api.ts b/examples/hackernews/src/lib/api.ts new file mode 100644 index 000000000..61fc2f9ab --- /dev/null +++ b/examples/hackernews/src/lib/api.ts @@ -0,0 +1,24 @@ +const story = (path: string) => `https://node-hnapi.herokuapp.com/${path}`; +const user = (path: string) => `https://hacker-news.firebaseio.com/v0/${path}.json`; + +export default async function fetchAPI(path: string) { + const url = path.startsWith('user') ? user(path) : story(path); + const headers = { 'User-Agent': 'chrome' }; + + try { + let response = await fetch(url, { headers }); + let text = await response.text(); + try { + if (text === null) { + return { error: 'Not found' }; + } + return JSON.parse(text); + } catch (e) { + console.error(`Recevied from API: ${text}`); + console.error(e); + return { error: e }; + } + } catch (error) { + return { error }; + } +} diff --git a/examples/hackernews/src/pages/[...stories].astro b/examples/hackernews/src/pages/[...stories].astro new file mode 100644 index 000000000..fa227e0c1 --- /dev/null +++ b/examples/hackernews/src/pages/[...stories].astro @@ -0,0 +1,105 @@ +--- +import For from '../components/For.astro'; +import Show from '../components/Show.astro'; +import Story from '../components/Story.astro'; +import Layout from '../layouts/Layout.astro'; +import fetchAPI from '../lib/api'; +import type { IStory } from '../types.js'; + +const mapStories = { + top: 'news', + new: 'newest', + show: 'show', + ask: 'ask', + job: 'jobs', +}; + +function safeParseInt(value: any, fallback: number) { + try { + return parseInt(value) || fallback; + } catch { + return fallback; + } +} + +const page = safeParseInt(Astro.url.searchParams.get('page'), 1); +const type = + Astro.params.stories && Astro.params.stories in mapStories + ? (Astro.params.stories.toString() as keyof typeof mapStories) + : 'top'; + +const stories = (await fetchAPI(`${mapStories[type]}?page=${page}`)) as IStory[]; +--- + +<Layout> + <section> + <nav aria-labelledby="current-page"> + <Show when={page > 1}> + <a href={`/${type}?page=${page - 1}`} aria-label="Previous Page"> < prev</a> + <span slot="fallback" aria-disabled="true"> < prev</span> + </Show> + <span id="current-page">page {page}</span> + <Show when={stories?.length >= 29}> + <a href={`/${type}?page=${page + 1}`} aria-label="Next Page">more ></a> + <span slot="fallback" aria-disabled="true"> more ></span> + </Show> + </nav> + <main> + <Show when={stories}> + <ul> + <For each={stories}>{(story: IStory) => <Story story={story} />}</For> + </ul> + </Show> + </main> + </section> +</Layout> + +<style> + section { + padding-top: 45px; + } + + nav, + main { + background-color: rgb(248 250 252); + border-radius: 2px; + } + + nav { + padding: 15px 30px; + position: fixed; + text-align: center; + top: 55px; + left: 0; + right: 0; + z-index: 998; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + } + + nav a { + margin: 0 1em; + } + + [aria-disabled='true'] { + color: rgb(71 85 105); + margin: 0 1em; + } + + main { + position: absolute; + margin: 30px 0; + width: 100%; + } + + ul { + list-style-type: none; + padding: 0; + margin: 0; + } + + @media (max-width: 600px) { + main { + margin: 10px 0; + } + } +</style> diff --git a/examples/hackernews/src/pages/stories/[id].astro b/examples/hackernews/src/pages/stories/[id].astro new file mode 100644 index 000000000..6cd17ea45 --- /dev/null +++ b/examples/hackernews/src/pages/stories/[id].astro @@ -0,0 +1,96 @@ +--- +import Comment from '../../components/Comment.astro'; +import For from '../../components/For.astro'; +import Show from '../../components/Show.astro'; +import Layout from '../../layouts/Layout.astro'; +import fetchAPI from '../../lib/api'; +import type { IComment, IStory } from '../../types.js'; + +const { id } = Astro.params as { id: string }; + +const story = (await fetchAPI(`item/${id}`)) as IStory; +--- + +<Layout> + <div> + <header> + <a href={story.url} target="_blank"> + <h1>{story.title}</h1> + </a> + <Show when={story.domain}> + <span class="host">({story.domain})</span> + </Show> + <p class="meta"> + {story.points} points | by + <a href={`/users/${story.user}`}> + {story.user} + </a> + {story.time_ago} ago + </p> + </header> + <main> + <p> + {story.comments_count ? story.comments_count + ' comments' : 'No comments yet.'} + </p> + <ul class="comment-children"> + <For each={story.comments}> + {(comment: IComment) => <Comment comment={comment} />} + </For> + </ul> + </main> + </div> +</Layout> + +<style> + header { + background-color: rgb(248 250 252); + padding: 1.8em 2em 1em; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + } + + h1 { + display: inline; + font-size: 1.5em; + margin: 0; + margin-right: 0.5em; + } + + .host, + .meta, + .host a { + color: rgb(51 65 85); + } + + .meta a { + text-decoration: underline; + } + + main { + background-color: rgb(248 250 252); + margin-top: 10px; + padding: 0 2em 0.5em; + } + + main p { + margin: 0; + font-size: 1.1em; + padding: 1em 0; + position: relative; + } + + main :global(ul) { + list-style-type: none; + padding: 0; + margin: 0; + } + + @media (max-width: 600px) { + h1 { + font-size: 1.25em; + } + } + + ul :global(ul) { + margin-left: 1.5em; + } +</style> diff --git a/examples/hackernews/src/pages/users/[id].astro b/examples/hackernews/src/pages/users/[id].astro new file mode 100644 index 000000000..9b43c6958 --- /dev/null +++ b/examples/hackernews/src/pages/users/[id].astro @@ -0,0 +1,69 @@ +--- +import Show from '../../components/Show.astro'; +import Layout from '../../layouts/Layout.astro'; +import fetchAPI from '../../lib/api'; +import type { IUser } from '../../types.js'; + +const { id } = Astro.params as { id: string }; + +const user = (await fetchAPI(`user/${id}`)) as IUser; +--- + +<Layout> + <main> + <Show when={user}> + <Show when={!user.error}> + <h1 slot="fallback">User not found.</h1> + <h1>User : {user.id}</h1> + <ul class="meta"> + <li> + <span class="label">Created:</span> + {user.created} + </li> + <li> + <span class="label">Karma:</span> + {user.karma} + </li> + <Show when={user.about}> + <li set:html={user.about} class="about"></li>{' '} + </Show> + </ul> + <p> + <a href={`https://news.ycombinator.com/submitted?id=${user.id}`}>submissions</a> |{' '} + <a href={`https://news.ycombinator.com/threads?id=${user.id}`}>comments</a> + </p> + </Show> + </Show> + </main> +</Layout> + +<style> + main { + background-color: rgb(248 250 252); + box-sizing: border-box; + padding: 2em 3em; + } + + h1 { + margin: 0; + font-size: 1.5em; + } + + .meta { + list-style-type: none; + padding: 0; + } + + .label { + display: inline-block; + min-width: 4em; + } + + .about { + margin: 1em 0; + } + + p a { + text-decoration: underline; + } +</style> diff --git a/examples/hackernews/src/types.ts b/examples/hackernews/src/types.ts new file mode 100644 index 000000000..e27ee85e4 --- /dev/null +++ b/examples/hackernews/src/types.ts @@ -0,0 +1,27 @@ +export interface IComment { + user: string; + time_ago: string; + content: string; + comments: IComment[]; +} + +export interface IStory { + id: string; + points: string; + url: string; + title: string; + domain: string; + type: string; + time_ago: string; + user: string; + comments_count: number; + comments: IComment[]; +} + +export interface IUser { + error: string; + id: string; + created: string; + karma: number; + about: string; +} diff --git a/examples/hackernews/tsconfig.json b/examples/hackernews/tsconfig.json new file mode 100644 index 000000000..d78f81ec4 --- /dev/null +++ b/examples/hackernews/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "astro/tsconfigs/base" +} |