diff --git a/components/Button.tsx b/components/Button.tsx new file mode 100644 index 0000000..f1b80a0 --- /dev/null +++ b/components/Button.tsx @@ -0,0 +1,12 @@ +import { JSX } from "preact"; +import { IS_BROWSER } from "$fresh/runtime.ts"; + +export function Button(props: JSX.HTMLAttributes) { + return ( + +

{props.count}

+ + + ); +} diff --git a/islands/StockList.tsx b/islands/StockList.tsx new file mode 100644 index 0000000..f7f53ed --- /dev/null +++ b/islands/StockList.tsx @@ -0,0 +1,126 @@ +import { Button } from "../components/Button.tsx"; +import { useEffect } from "preact/hooks"; +import { ComponentChildren } from "preact"; +import { Signal, useSignal } from "@preact/signals"; + +interface StockProps { + pageName: string; +} + +interface ToggleButtonProps { + children?: ComponentChildren; +} + +function ToggleButton(props: ToggleButtonProps) { + return ( + + ); +} + +type QueryStatus = { + type: "loading"; +} | { + type: "complete"; + data: T; +} | { + type: "error"; + err: Error; +}; + +const cacheMap = new Map(); +function useQuery(url: string): Signal> { + const state = useSignal({ + type: "loading", + } as QueryStatus); + useEffect(() => { + if (!cacheMap.has(url)) { + (async () => { + try { + const res = await fetch(url); + const data = await res.json(); + cacheMap.set(url, data); + state.value = { + type: "complete", + data: data, + }; + } catch (err) { + state.value = { + type: "error", + err: err, + }; + } + })(); + } else { + state.value = { + type: "complete", + data: cacheMap.get(url) as T, + }; + } + },[]); + return state; +} + +interface Coperation { + Name: string; + Code: string; + Sector: string; + Product: string; + ListingDay: string; + ClosingMonth: string; + Representative: string; + Homepage: string; + AddressArea: string; + LastUpdate: string; +} + +interface PageCorpsInfo { + name: string; + description: string; + corpListByDate: Record; +} + +function StockList({data}: {data: PageCorpsInfo}){ + console.log("data") + const keys = Object.keys(data.corpListByDate).sort().reverse().slice(0,5).reverse(); + //const rows = data.corpListbyDate; + + return
+ {keys.map((x,i)=>{ + const rows = data.corpListByDate[x]; + return
+ {rows.map(row=>{ + return
+ {row.Name} +
+ })} +
+ })} +
+} + +export default function StockListUI(props: StockProps) { + const sig = useQuery("/api/pages/" + props.pageName); + return ( +
+
+ Kospi + Kosdaq + Otherwise +
+
+ {sig.value.type == "loading" + ? (new Array(20).fill(0).map((_) => ( +
+ ))) + :
+ { + sig.value.type == "error" ? (
+

File Loading Failed

+
) : + } +
} +
+
+ ); +} diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..984b0ae --- /dev/null +++ b/main.ts @@ -0,0 +1,15 @@ +/// +/// +/// +/// +/// + +import "$std/dotenv/load.ts"; + +import { start } from "$fresh/server.ts"; +import manifest from "./fresh.gen.ts"; + +import twindPlugin from "$fresh/plugins/twind.ts"; +import twindConfig from "./twind.config.ts"; + +await start(manifest, { plugins: [twindPlugin(twindConfig)] }); diff --git a/pages.ts b/pages.ts new file mode 100644 index 0000000..f374d6d --- /dev/null +++ b/pages.ts @@ -0,0 +1,46 @@ +import { parse } from "https://deno.land/std@0.195.0/yaml/mod.ts"; +import { join, fromFileUrl } from "https://deno.land/std@0.193.0/path/mod.ts"; + +export const PAGES_PATH = join(fromFileUrl(import.meta.url), "../pages.yaml"); + +export interface PageDescription { + name: string; + description: string; +} + +async function readPagesDescription() { + const pagesText = await Deno.readTextFile(PAGES_PATH); + const pages = parse(pagesText) as PageDescription[]; + return pages; +} + +function watchFile( + path: string, + callback: () => void | Promise, +) { + const watcherRef = Deno.watchFs(path); + (async () => { + for await (const event of watcherRef) { + if (event.kind == "modify") { + await callback(); + } + } + })(); + Deno.addSignalListener("SIGINT", () => { + watcherRef.close(); + }); +} + +let pages_meta: PageDescription[] = []; +let mtime = 0; +export async function get_pages_meta(): Promise<[PageDescription[],number]>{ + if (pages_meta) { + pages_meta = await readPagesDescription(); + mtime = Date.now(); + watchFile(PAGES_PATH, async () => { + pages_meta = await readPagesDescription(); + mtime = Date.now(); + }); + } + return [pages_meta, mtime]; +} diff --git a/pages.yaml b/pages.yaml index 1f74479..27249f7 100644 --- a/pages.yaml +++ b/pages.yaml @@ -58,6 +58,6 @@ - name: 240일 증가 description: 240일선이 증가하는 것. - name: 볼린저 밴드 25 - description: '볼린저 밴드(25일선 ,표준편차 2배)의 위 밴드 값을 넘었을 때 표시. 시장 상황이 않 좋으면 평균 59개' + description: '볼린저 밴드(25일선 ,표준편차 2배)의 위 밴드 값을 넘었을 때 표시.' - name: 양봉사이20일선 description: Open과 Close 사이 20일 선 diff --git a/routes/_404.tsx b/routes/_404.tsx new file mode 100644 index 0000000..c8228ab --- /dev/null +++ b/routes/_404.tsx @@ -0,0 +1,28 @@ + +import { Head } from "$fresh/runtime.ts"; + +export default function Error404() { + return ( + <> + + 404 - Page not found + +
+
+ the fresh logo: a sliced lemon dripping with juice +

404 - Page not found

+

+ The page you were looking for doesn't exist. +

+ Go back home +
+
+ + ); +} diff --git a/routes/_app.tsx b/routes/_app.tsx new file mode 100644 index 0000000..60f7898 --- /dev/null +++ b/routes/_app.tsx @@ -0,0 +1,9 @@ +import { AppProps } from "$fresh/server.ts"; + +export default function App({ Component }: AppProps) { + return ( + <> + + + ); +} diff --git a/routes/api/joke.ts b/routes/api/joke.ts new file mode 100644 index 0000000..a3f4243 --- /dev/null +++ b/routes/api/joke.ts @@ -0,0 +1,21 @@ +import { HandlerContext } from "$fresh/server.ts"; + +// Jokes courtesy of https://punsandoneliners.com/randomness/programmer-jokes/ +const JOKES = [ + "Why do Java developers often wear glasses? They can't C#.", + "A SQL query walks into a bar, goes up to two tables and says “can I join you?”", + "Wasn't hard to crack Forrest Gump's password. 1forrest1.", + "I love pressing the F5 key. It's refreshing.", + "Called IT support and a chap from Australia came to fix my network connection. I asked “Do you come from a LAN down under?”", + "There are 10 types of people in the world. Those who understand binary and those who don't.", + "Why are assembly programmers often wet? They work below C level.", + "My favourite computer based band is the Black IPs.", + "What programme do you use to predict the music tastes of former US presidential candidates? An Al Gore Rhythm.", + "An SEO expert walked into a bar, pub, inn, tavern, hostelry, public house.", +]; + +export const handler = (_req: Request, _ctx: HandlerContext): Response => { + const randomIndex = Math.floor(Math.random() * JOKES.length); + const body = JOKES[randomIndex]; + return new Response(body); +}; diff --git a/routes/api/kosdaq.ts b/routes/api/kosdaq.ts new file mode 100644 index 0000000..3216a13 --- /dev/null +++ b/routes/api/kosdaq.ts @@ -0,0 +1,17 @@ +import { Handlers } from "$fresh/server.ts"; +import {DB} from "https://deno.land/x/sqlite/mod.ts"; + +export const handler: Handlers = { + async GET(req, _ctx): Promise { + const headers = new Headers({ + "content-type": "application/json" + }); + const db = new DB("stock.db"); + const conn = db.query("SELECT Code,Name FROM KOSDAQ"); + const body = conn.map(row=>({ + code: row[0], + name: row[1] + })) + return new Response(JSON.stringify(body), {headers}); + }, +} \ No newline at end of file diff --git a/routes/api/kospi.ts b/routes/api/kospi.ts new file mode 100644 index 0000000..6246e2e --- /dev/null +++ b/routes/api/kospi.ts @@ -0,0 +1,17 @@ +import { Handlers } from "$fresh/server.ts"; +import {DB} from "https://deno.land/x/sqlite/mod.ts"; + +export const handler: Handlers = { + async GET(req, _ctx): Promise { + const headers = new Headers({ + "content-type": "application/json" + }); + const db = new DB("stock.db"); + const conn = db.query("SELECT Code,Name FROM KOSPI"); + const body = conn.map(row=>({ + code: row[0], + name: row[1] + })) + return new Response(JSON.stringify(body), {headers}); + }, +} \ No newline at end of file diff --git a/routes/api/pages/[name].ts b/routes/api/pages/[name].ts new file mode 100644 index 0000000..499bf9c --- /dev/null +++ b/routes/api/pages/[name].ts @@ -0,0 +1,40 @@ +import { Handlers } from "$fresh/server.ts"; +import { Status, STATUS_TEXT } from "https://deno.land/std@0.195.0/http/mod.ts"; +import { fromFileUrl, join } from "$std/path/mod.ts"; + + +export const handler: Handlers = { + async GET(req, ctx): Promise { + const headers = new Headers({ + "content-type": "application/json" + }); + const path = join(fromFileUrl(import.meta.url), "../../../../dist", `${ctx.params.name}.json`); + console.log("path : ",path) + let stat; + try { + stat = await Deno.stat(path); + } + catch(err){ + if(err instanceof Deno.errors.NotFound){ + return await ctx.renderNotFound(); + } + else { + throw err; + } + } + const mtime = stat.mtime ?? new Date(0); + const body = await Deno.readTextFile(path); + headers.set("last-modified", mtime.toUTCString()); + + const ifModifiedSinceValue = req.headers.get("if-modified-since"); + if ( ifModifiedSinceValue && + mtime.getTime() != new Date(ifModifiedSinceValue).getTime() + ){ + return new Response(null, { + status: Status.NotModified, + statusText: STATUS_TEXT[Status.NotModified] + }) + } + return new Response(body, {headers}); + }, +}; diff --git a/routes/api/pages/index.ts b/routes/api/pages/index.ts new file mode 100644 index 0000000..273937d --- /dev/null +++ b/routes/api/pages/index.ts @@ -0,0 +1,24 @@ +import { Handlers } from "$fresh/server.ts"; +import { get_pages_meta } from "../../../pages.ts"; +import { Status, STATUS_TEXT } from "https://deno.land/std@0.195.0/http/mod.ts"; + +export const handler: Handlers = { + async GET(req, _ctx): Promise { + const headers = new Headers({ + "content-type": "application/json" + }); + const [body, mtime] = await get_pages_meta(); + headers.set("last-modified", new Date(mtime).toUTCString()); + console.log("aaa"); + const ifModifiedSinceValue = req.headers.get("if-modified-since"); + if ( ifModifiedSinceValue && + mtime != new Date(ifModifiedSinceValue).getTime() + ){ + return new Response(null, { + status: Status.NotModified, + statusText: STATUS_TEXT[Status.NotModified] + }) + } + return new Response(JSON.stringify(body), {headers}); + }, +}; diff --git a/routes/greet/[name].tsx b/routes/greet/[name].tsx new file mode 100644 index 0000000..9c06827 --- /dev/null +++ b/routes/greet/[name].tsx @@ -0,0 +1,5 @@ +import { PageProps } from "$fresh/server.ts"; + +export default function Greet(props: PageProps) { + return
Hello {props.params.name}
; +} diff --git a/routes/index.tsx b/routes/index.tsx new file mode 100644 index 0000000..0032712 --- /dev/null +++ b/routes/index.tsx @@ -0,0 +1,48 @@ +import { Head } from "$fresh/runtime.ts"; +import { useSignal } from "@preact/signals"; +import {Button} from "../components/Button.tsx"; +import { PageDescription, get_pages_meta } from "../pages.ts"; +import { Handlers, PageProps } from "$fresh/server.ts"; + +export const handler: Handlers = { + async GET(_req, ctx){ + const [pages,_] = await get_pages_meta(); + return await ctx.render(pages); + } +} + +export default function Home({data}: PageProps) { + const count = useSignal(3); + + return ( + <> + + stock-front + +
+
+ the fresh logo: a sliced lemon dripping with juice +

Stock

+
+ +
+
+
+ + ); +} diff --git a/routes/pages/[name].tsx b/routes/pages/[name].tsx new file mode 100644 index 0000000..c70d5dc --- /dev/null +++ b/routes/pages/[name].tsx @@ -0,0 +1,25 @@ +import { PageProps } from "$fresh/server.ts"; +import { Head } from "$fresh/runtime.ts"; +import StockList from "../../islands/StockList.tsx"; + + +export default function Pages(props: PageProps) { + return <> + + Stock: {props.params.name} + +
+
+ stock graph +

{props.params.name}

+ +
+
+ +} diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..1cfaaa2 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/logo.svg b/static/logo.svg new file mode 100644 index 0000000..ef2fbe4 --- /dev/null +++ b/static/logo.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/static/stockgraph.svg b/static/stockgraph.svg new file mode 100644 index 0000000..d8a3d7f --- /dev/null +++ b/static/stockgraph.svg @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..c5cca09 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,7 @@ +export default { + content: ["./**/*.{html,tsx}"], + theme:{ + extend:{}, + }, + plugins: [], +} \ No newline at end of file diff --git a/twind.config.ts b/twind.config.ts new file mode 100644 index 0000000..2a7ac27 --- /dev/null +++ b/twind.config.ts @@ -0,0 +1,5 @@ +import { Options } from "$fresh/plugins/twind.ts"; + +export default { + selfURL: import.meta.url, +} as Options;