Skip to content

Commit

Permalink
deno fmtの実行、Deno.KVの削除
Browse files Browse the repository at this point in the history
  • Loading branch information
masataka committed Jul 14, 2024
1 parent d9e9137 commit 97def5b
Show file tree
Hide file tree
Showing 33 changed files with 2,420 additions and 1,329 deletions.
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ SSGとDevOps/CDを利用して、リポジトリにコンテンツをプッシ
serveではserve.tsを用いないため、以下を実行する。

```sh
% deno run -A --unstable-kv serve.ts
% deno run -A serve.ts
```

### /src

サイトのコンテンツが格納されている。テンプレートにはReactを.tsxで利用している。

- お知らせのメンテナンス
- /src/information/_data/information.yml を編集する
- /src/information/_data/information.yml を編集する
- 代表社員経歴のメンテナンス
- /src/leadership/_data/careers.yml を編集する
- /src/leadership/_data/careers.yml を編集する

### /contact

Expand All @@ -56,15 +56,19 @@ APIドキュメントを提供するSPA。
- ローカル環境にプルした後、apiフォルダに移動して、npm installを実行
- npm run build を実行すると、/src/product/api/js にSPAを出力する
- 画面上のReDoc Reactコンポーネントでドキュメントを生成する。
- APIドキュメントの元となるJSONは、/api/docs.json をserve.ts経由でapi.ewware.comより取得する

- APIドキュメントの元となるJSONは、/api/docs.json
をserve.ts経由でapi.ewware.comより取得する

### /.github/workflows

GitHub Actionで、リポジトリへのプッシュがあったときにDeno Deployへ自動配置するようにしている。
GitHub Actionで、リポジトリへのプッシュがあったときにDeno
Deployへ自動配置するようにしている。

- GitHub Action の Dockerコンテナ上に、ソースコードをクローンする。
- Node.js 環境を自動構築して /contact のお問い合わせReactアプリをコンパイルする。
- Node.js 環境を自動構築して /contact
のお問い合わせReactアプリをコンパイルする。
- Node.js 環境を自動構築して /api のAPIドキュメントReactアプリをコンパイルする。
- Dockerコンテナ上で Lume を自動実行する。このタイミングでWEBサイト構成物が生成される。
- denoland/deployctl プラグインを利用して、すべてのWEBサイト構成物をDeno Deployにアップロードする。
- Dockerコンテナ上で Lume
を自動実行する。このタイミングでWEBサイト構成物が生成される。
- denoland/deployctl プラグインを利用して、すべてのWEBサイト構成物をDeno
Deployにアップロードする。
2 changes: 1 addition & 1 deletion api/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -14978,4 +14978,4 @@
"in": "header"
}
}
}
}
2 changes: 1 addition & 1 deletion api/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import { RedocStandalone } from "redoc";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<RedocStandalone specUrl="/api/docs.json"/>
<RedocStandalone specUrl="/api/docs.json" />
</React.StrictMode>,
);
2 changes: 1 addition & 1 deletion api/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default defineConfig({
rollupOptions: {
output: {
entryFileNames: `redoc.js`,
}
},
},
},
});
131 changes: 97 additions & 34 deletions contact/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import ReactDOM from "react-dom/client";
import React, { useState } from "react";
import { useForm } from "react-hook-form";

const EMAIL_REG = /^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$/;
const EMAIL_REG =
/^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$/;

type ContactForm = {
name: string;
Expand All @@ -12,7 +13,8 @@ type ContactForm = {
};

const App = () => {
const { register, handleSubmit, formState: { dirtyFields, errors } } = useForm<ContactForm>();
const { register, handleSubmit, formState: { dirtyFields, errors } } =
useForm<ContactForm>();
const [formData, setFormData] = useState<ContactForm | null>(null);
const [stage, setStage] = useState<"input" | "submitted" | "posted">("input");
const [focusID, setFocusID] = useState<string | null>(null);
Expand All @@ -21,9 +23,11 @@ const App = () => {
return (
<div className="column_contents contact_contents">
<h2>送信完了</h2>
<p>この度はお問い合わせいただきまして誠にありがとうございます。<br />
内容を確認次第、担当者より折返しご連絡させていただきます。<br className="viewpc" />今しばらくお待ちください。</p>
</div>
<p>
この度はお問い合わせいただきまして誠にありがとうございます。<br />
内容を確認次第、担当者より折返しご連絡させていただきます。<br className="viewpc" />今しばらくお待ちください。
</p>
</div>
);
}

Expand All @@ -38,7 +42,8 @@ const App = () => {
"Content-Type": "application/json",
},
body: JSON.stringify({
text: `お問い合わせ\nお名前: ${name}\nメール: ${email}\nご用件: ${business}\n内容: ${content}`,
text:
`お問い合わせ\nお名前: ${name}\nメール: ${email}\nご用件: ${business}\n内容: ${content}`,
}),
});
setStage("posted");
Expand All @@ -52,26 +57,38 @@ const App = () => {
return (
<div className="column_contents contact_contents">
<h2>内容確認</h2>
<p>ご入力いただいた内容をご確認いただき、よろしければ「送信」ボタンをクリックしてください。</p>
<p>
ご入力いただいた内容をご確認いただき、よろしければ「送信」ボタンをクリックしてください。
</p>
<div className="contact_form">
<div className="input_box">
<div className="input_title">お名前<span className="ness">必須</span></div>
<div className="input_title">
お名前<span className="ness">必須</span>
</div>
<div className="confirm_text">{formData?.name}</div>
</div>
<div className="input_box">
<div className="input_title">メールアドレス<span className="ness">必須</span></div>
<div className="input_title">
メールアドレス<span className="ness">必須</span>
</div>
<div className="confirm_text">{formData?.email}</div>
</div>
<div className="radio_box">
<div className="input_title">ご用件<span className="ness">必須</span></div>
<div className="input_title">
ご用件<span className="ness">必須</span>
</div>
<div className="confirm_text">{formData?.business}</div>
</div>
<div className="input_box">
<div className="input_title">お問い合わせ内容<span className="ness">必須</span></div>
<div className="input_title">
お問い合わせ内容<span className="ness">必須</span>
</div>
<div className="confirm_text">{formData?.content}</div>
</div>
<div className="btn_area">
<button onClick={() => setStage("input")} className="back_button">戻る</button>
<button onClick={() => setStage("input")} className="back_button">
戻る
</button>
<button onClick={postForm} className="submit_button">送信</button>
</div>
</div>
Expand All @@ -85,19 +102,28 @@ const App = () => {
});
const emailBinder = register("email", {
required: { value: true, message: "メールアドレスを入力してください" },
pattern: { value: EMAIL_REG, message: "有効なメールアドレスではありません" },
maxLength: { value: 254, message: "メールアドレスは254文字以内で入力してください" },
pattern: {
value: EMAIL_REG,
message: "有効なメールアドレスではありません",
},
maxLength: {
value: 254,
message: "メールアドレスは254文字以内で入力してください",
},
});
const businessBinder = register("business", {
required: { value: true, message: "ご用件を選択してください" },
});
const contentBinder = register("content", {
required: { value: true, message: "お問い合わせ内容を入力してください" },
maxLength: { value: 300, message: "お問い合わせ内容は300文字以内で入力してください" },
maxLength: {
value: 300,
message: "お問い合わせ内容は300文字以内で入力してください",
},
});

const inputClass = (id: keyof ContactForm) => {
const list = [(id === "content" ? "input_textarea" : "input_text")];
const list = [id === "content" ? "input_textarea" : "input_text"];
if (errors[id]) {
list.push("input_error");
}
Expand All @@ -113,7 +139,7 @@ const App = () => {
list.push("label_error");
}
return list.join(" ");
}
};

const submitForm = handleSubmit((data) => {
setFormData(data);
Expand All @@ -123,32 +149,59 @@ const App = () => {
return (
<div className="column_contents contact_contents">
<h2>お問い合わせフォーム</h2>
<p>土日祝を除く3営業日以内に担当者よりご連絡させていただきます。<br />
お問い合わせ内容により、ご回答までにお時間をいただく場合または、ご回答が出来ない場合がございます。</p>
<p>
土日祝を除く3営業日以内に担当者よりご連絡させていただきます。<br />
お問い合わせ内容により、ご回答までにお時間をいただく場合または、ご回答が出来ない場合がございます。
</p>
<form className="contact_form" onSubmit={submitForm}>

<div className="input_box">
<input type="text" {...nameBinder} className={inputClass("name")}
onFocus={() => setFocusID("name")} onBlur={() => setFocusID(null)}/>
<label className={labelClass("name")}>お名前<span className="ness">必須</span></label>
<input
type="text"
{...nameBinder}
className={inputClass("name")}
onFocus={() => setFocusID("name")}
onBlur={() => setFocusID(null)}
/>
<label className={labelClass("name")}>
お名前<span className="ness">必須</span>
</label>
<div className="error-message">{errors.name?.message}</div>
</div>

<div className="input_box">
<input type="text" {...emailBinder} className={inputClass("email")}
onFocus={() => setFocusID("email")} onBlur={() => setFocusID(null)}/>
<label className={labelClass("email")}>メールアドレス<span className="ness">必須</span></label>
<input
type="text"
{...emailBinder}
className={inputClass("email")}
onFocus={() => setFocusID("email")}
onBlur={() => setFocusID(null)}
/>
<label className={labelClass("email")}>
メールアドレス<span className="ness">必須</span>
</label>
<div className="error-message">{errors.email?.message}</div>
</div>

<div className="radio_box">
<label className="radio_title">ご用件<span className="ness">必須</span></label>
<label className="radio_title">
ご用件<span className="ness">必須</span>
</label>
<div className="radio_section">
<input type="radio" id="dev" value="開発案件プロデュースのご依頼・ご相談" {...businessBinder} />
<input
type="radio"
id="dev"
value="開発案件プロデュースのご依頼・ご相談"
{...businessBinder}
/>
<label htmlFor="dev">開発案件プロデュースのご依頼・ご相談</label>
</div>
<div className="radio_section">
<input type="radio" id="info" value="Essential Workwareについて" {...businessBinder} />
<input
type="radio"
id="info"
value="Essential Workwareについて"
{...businessBinder}
/>
<label htmlFor="info">Essential Workwareについて</label>
</div>
<div className="radio_section">
Expand All @@ -159,9 +212,19 @@ const App = () => {
</div>

<div className="input_box">
<textarea id="text" cols={30} rows={8} {...contentBinder} className={inputClass("content")}
onFocus={() => setFocusID("content")} onBlur={() => setFocusID(null)}></textarea>
<label className={labelClass("content")}>お問い合わせ内容<span className="ness">必須</span></label>
<textarea
id="text"
cols={30}
rows={8}
{...contentBinder}
className={inputClass("content")}
onFocus={() => setFocusID("content")}
onBlur={() => setFocusID(null)}
>
</textarea>
<label className={labelClass("content")}>
お問い合わせ内容<span className="ness">必須</span>
</label>
<div className="error-message">{errors.content?.message}</div>
</div>

Expand All @@ -171,7 +234,7 @@ const App = () => {
</form>
</div>
);
}
};

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
Expand Down
2 changes: 1 addition & 1 deletion contact/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default defineConfig({
rollupOptions: {
output: {
entryFileNames: `form.js`,
}
},
},
},
});
28 changes: 8 additions & 20 deletions serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,14 @@ const server = new Server({
root: `${Deno.cwd()}/_site`,
});

const kv = await Deno.openKv();

function isBody(test: unknown): test is string {
return test !== undefined && typeof test === "string";
}
const getPath = (request: Request) => (new URL(request.url).pathname);
const slackWebhookURL = Deno.env.get("SLACK_WEBHOOK_URL") ||
env["SLACK_WEBHOOK_URL"];

kv.listenQueue(async (body) => {
if (isBody(body)) {
const webhookURL = Deno.env.get("SLACK_WEBHOOK_URL") ||
env["SLACK_WEBHOOK_URL"];
const response = await fetch(webhookURL, {
server.use(async (request, next) => {
if (request.method == "POST" && getPath(request) === "/slack") {
const body = await request.text();
const response = await fetch(slackWebhookURL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand All @@ -28,16 +25,7 @@ kv.listenQueue(async (body) => {
if (!response.ok) {
console.error(response);
}
}
});

const getPath = (request: Request) => (new URL(request.url).pathname);

server.use(async (request, next) => {
if (request.method == "POST" && getPath(request) === "/slack") {
const body = await new Response(request.body).text();
const result = await kv.enqueue(body);
return new Response(body, { status: result.ok ? 200 : 500 });
return new Response(body, { status: response.ok ? 200 : 500 });
}
return await next(request);
});
Expand Down
11 changes: 9 additions & 2 deletions src/404/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ export const title = "404 ページが見つかりません | クリップクロ
export default () => (
<main>
<section className="main_contents">
<h2>お探しのページは<br className="viewsp" />見つかりませんでした。</h2>
<h2>
お探しのページは<br className="viewsp" />見つかりませんでした。
</h2>
<article className="inner notfound_contents">
<div className="notfound_txt">
<p>Essential Workwareに関して、<br className="viewsp" />くわしくは<a href="/product/">こちら</a>をご覧ください。</p>
<p>
Essential
Workwareに関して、<br className="viewsp" />くわしくは<a href="/product/">
こちら
</a>をご覧ください。
</p>
</div>
<div className="notfound_img">
<img src="/assets/images/img_notfound.png" alt="404 Page not found" />
Expand Down
Loading

0 comments on commit 97def5b

Please sign in to comment.