diff --git a/package-lock.json b/package-lock.json index 13bf015..61bfdcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,16 @@ { "name": "my-profile", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "my-profile", + "version": "1.0.1", + "license": "MIT", "dependencies": { - "hono": "^4.3.6" + "hono": "^4.3.6", + "microcms-js-sdk": "^3.1.2" }, "devDependencies": { "@biomejs/biome": "1.7.3", @@ -788,6 +793,14 @@ "printable-characters": "^1.0.42" } }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dependencies": { + "retry": "0.13.1" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -1422,6 +1435,17 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/microcms-js-sdk": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/microcms-js-sdk/-/microcms-js-sdk-3.1.2.tgz", + "integrity": "sha512-uPR9OpldgXxyvtdUuYKdctn+FBCvALnW4SGL7qvfq+mQfqI1Wq+QQax9zxtxOEb/wWWTh82cED0ZeZjl5TP0jA==", + "dependencies": { + "async-retry": "^1.3.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/micromatch": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", @@ -1725,6 +1749,14 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", diff --git a/package.json b/package.json index 1da1fd3..1840752 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "prepare": "husky" }, "dependencies": { - "hono": "^4.3.6" + "hono": "^4.3.6", + "microcms-js-sdk": "^3.1.2" }, "devDependencies": { "@biomejs/biome": "1.7.3", diff --git a/src/api/apiClient.ts b/src/api/apiClient.ts new file mode 100644 index 0000000..df6f1ec --- /dev/null +++ b/src/api/apiClient.ts @@ -0,0 +1,18 @@ +import { Context } from "hono"; +import { env } from "hono/adapter"; +import { createClient } from "microcms-js-sdk"; + +const getApiClient = (c: Context) => { + const { MICRO_CMS_SERVICE_DOMAIN, MICRO_CMS_API_KEY } = env<{ + MICRO_CMS_SERVICE_DOMAIN: string; + MICRO_CMS_API_KEY: string; + }>(c); + const apiClient = createClient({ + serviceDomain: MICRO_CMS_SERVICE_DOMAIN, + apiKey: MICRO_CMS_API_KEY, + }); + + return apiClient; +}; + +export { getApiClient }; diff --git a/src/api/photos/fetch.ts b/src/api/photos/fetch.ts new file mode 100644 index 0000000..2d5734f --- /dev/null +++ b/src/api/photos/fetch.ts @@ -0,0 +1,26 @@ +import { Context } from "hono"; +import { getApiClient } from "../apiClient"; + +type Response = { + contents: { + id: string; + image: { + url: string; + height: number; + width: number; + }; + title: string; + }[]; + totalCount: number; + offset: number; + limit: number; +}; + +const fetchPhotos = async (c: Context) => { + const res = await getApiClient(c).get({ endpoint: "photos" }); + return res.contents.map((content) => { + return { title: content.title, ...content.image }; + }); +}; + +export { fetchPhotos }; diff --git a/src/api/photos/index.ts b/src/api/photos/index.ts new file mode 100644 index 0000000..11a3610 --- /dev/null +++ b/src/api/photos/index.ts @@ -0,0 +1,2 @@ +export * from "./fetch"; +export * from "./model"; diff --git a/src/api/photos/model.ts b/src/api/photos/model.ts new file mode 100644 index 0000000..1ca28be --- /dev/null +++ b/src/api/photos/model.ts @@ -0,0 +1,8 @@ +type Photo = { + title: string; + url: string; + height: number; + width: number; +}; + +export type { Photo }; diff --git a/src/components/profile/ProfilePhotos.css.ts b/src/components/profile/ProfilePhotos.css.ts new file mode 100644 index 0000000..849a8dc --- /dev/null +++ b/src/components/profile/ProfilePhotos.css.ts @@ -0,0 +1,16 @@ +import { css } from "hono/css"; + +const Photo_Container = css` + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr 1fr; + gap: 16px; + margin-top: 16px; +`; + +const Photo_Image = css` + max-width: 100%; + border-radius: 8px; +`; + +export { Photo_Container, Photo_Image }; diff --git a/src/components/profile/ProfilePhotos.tsx b/src/components/profile/ProfilePhotos.tsx new file mode 100644 index 0000000..d280b91 --- /dev/null +++ b/src/components/profile/ProfilePhotos.tsx @@ -0,0 +1,25 @@ +import { FC } from "hono/jsx"; +import { Photo } from "../../api/photos"; +import { Header, Layout } from "./common.css"; +import { Photo_Container, Photo_Image } from "./ProfilePhotos.css"; + +type Props = { + photos: Photo[]; +}; + +const ProfilePhotos: FC = (props) => { + return ( +
+

Favorites

+
    + {props.photos.map((image) => ( +
  • + {image.title} +
  • + ))} +
+
+ ); +}; + +export { ProfilePhotos }; diff --git a/src/components/profile/ProfilePresenter.tsx b/src/components/profile/ProfilePresenter.tsx index 0431b4c..e3a72cc 100644 --- a/src/components/profile/ProfilePresenter.tsx +++ b/src/components/profile/ProfilePresenter.tsx @@ -1,10 +1,18 @@ +import { FC } from "hono/jsx"; import { ProfileLinks } from "./ProfileLinks"; import { ProfileMain } from "./ProfileMain"; +import { Photo } from "../../api/photos/model"; +import { ProfilePhotos } from "./ProfilePhotos"; -const ProfilePresenter = () => ( +type Props = { + photos: Photo[]; +}; + +const ProfilePresenter: FC = (props) => ( <> + ); diff --git a/src/index.tsx b/src/index.tsx index 241f290..6256702 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,6 +3,7 @@ import { ProfilePresenter } from "./components/profile/ProfilePresenter"; import { Style, css } from "hono/css"; import { jsxRenderer } from "hono/jsx-renderer"; import { Footer } from "./components/Footer"; +import { fetchPhotos } from "./api/photos"; type Bindings = { [key in keyof CloudflareBindings]: CloudflareBindings[key]; @@ -53,7 +54,8 @@ app.use( ); app.get("/", async (c) => { - return await c.render(); + const photos = await fetchPhotos(c); + return await c.render(); }); export default app;