Skip to content

Commit 8d2d357

Browse files
committed
Merge remote-tracking branch 'origin/main' into sentry
2 parents f2f9a04 + 1785270 commit 8d2d357

12 files changed

Lines changed: 537 additions & 109 deletions

File tree

app/about/ai/content.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# AI質問機能について
2+
3+
my.code(); では、学習をサポートするための AI アシスタント機能を提供しています。
4+
ご利用前に以下の事項をご確認ください。
5+
6+
## AIの回答の正確性について
7+
8+
**AIの回答は誤りを含む場合があります。**
9+
10+
AIは非常に自信を持って誤った情報を回答することがあります。
11+
AIの回答を鵜呑みにせず、必ず自分自身で内容を確認するようにしてください。
12+
13+
## 免責事項
14+
15+
AI質問機能の利用によって生じたいかなる損害についても、ut.code(); は責任を負いません。
16+
17+
## 使用しているAIモデルについて
18+
19+
AIモデルへのアクセスには [OpenRouter](https://openrouter.ai/) を使用しています。
20+
使用するモデルは ut.code(); が選択しており、ユーザーが変更することはできません。
21+
また、使用するモデルは予告なく変更される場合があります。
22+
23+
## データの取り扱いについて
24+
25+
**入力データの利用について**
26+
27+
- AIへの質問内容やこのサイトで実行したコードのデータは、AIモデルのプロバイダーによって学習データとして利用される可能性があります。
28+
- また、サービス品質の向上等を目的として、ut.code(); のメンバーが閲覧可能な形でサイトに保存されます。
29+
- **個人情報や機密情報は入力しないようにしてください。**

app/about/ai/page.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Metadata } from "next";
2+
import { StyledMarkdown } from "@/markdown/markdown";
3+
import content from "./content.md?raw";
4+
5+
export const metadata: Metadata = {
6+
title: "AI質問機能について",
7+
description: "my.code(); のAI質問機能の詳細と利用上の注意事項について説明します。",
8+
};
9+
10+
export default function AiPage() {
11+
return (
12+
<div className="p-4 pb-16 w-full max-w-docs mx-auto">
13+
<StyledMarkdown content={content} />
14+
</div>
15+
);
16+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
"use client";
2+
3+
import { StyledSyntaxHighlighter } from "@/markdown/styledSyntaxHighlighter";
4+
import { langConstants } from "@my-code/runtime/languages";
5+
import { useState } from "react";
6+
7+
export interface LicenseEntry {
8+
name: string;
9+
version: string;
10+
author?: string;
11+
repository?: string;
12+
source?: string;
13+
license: string;
14+
licenseText?: string;
15+
}
16+
17+
export function ThirdPartyLicenses({ licenses }: { licenses: LicenseEntry[] }) {
18+
const [expanded, setExpanded] = useState<string | null>(null);
19+
20+
return (
21+
<div className="flex flex-col gap-2">
22+
{licenses.map((pkg) => {
23+
const key = `${pkg.name}@${pkg.version}`;
24+
const isOpen = expanded === key;
25+
let repositoryURL: string | undefined = undefined;
26+
if (pkg.repository?.startsWith("http")) {
27+
repositoryURL = pkg.repository;
28+
} else if (pkg.repository?.startsWith("git+http")) {
29+
repositoryURL = pkg.repository?.slice(4);
30+
} else if (pkg.repository?.startsWith("git@")) {
31+
repositoryURL =
32+
"https://" +
33+
pkg.repository
34+
.slice(4)
35+
.replace(":", "/")
36+
.replace(/\.git$/, "");
37+
} else if (
38+
pkg.repository &&
39+
/github:[\w-]+\/[\w-]+/.test(pkg.repository)
40+
) {
41+
repositoryURL = `https://github.com/${pkg.repository.slice(7)}`;
42+
} else if (pkg.repository && /[\w-]+\/[\w-]+/.test(pkg.repository)) {
43+
// assume github username/repository
44+
repositoryURL = `https://github.com/${pkg.repository}`;
45+
} else {
46+
// fallback to source url
47+
// repositoryURL = pkg.source ?? "";
48+
}
49+
return (
50+
<div key={key} className="collapse collapse-arrow bg-base-200">
51+
<input
52+
type="checkbox"
53+
checked={isOpen}
54+
onChange={() => setExpanded(isOpen ? null : key)}
55+
/>
56+
<div className="collapse-title font-mono">
57+
<span className="font-bold">{pkg.name}</span>
58+
<span className="opacity-60 ml-2">v{pkg.version}</span>
59+
<span className="badge badge-primary badge-soft badge-sm ml-3">
60+
{pkg.license}
61+
</span>
62+
</div>
63+
<div className="collapse-content">
64+
{pkg.author && (
65+
<p className="mb-1">
66+
<span className="opacity-60">Author: </span>
67+
{pkg.author}
68+
</p>
69+
)}
70+
{repositoryURL && (
71+
<p className="mb-1">
72+
<span className="opacity-60">Repository: </span>
73+
<a
74+
className="link link-info break-all"
75+
href={repositoryURL}
76+
target="_blank"
77+
>
78+
{repositoryURL}
79+
</a>
80+
</p>
81+
)}
82+
{pkg.licenseText && (
83+
<StyledSyntaxHighlighter
84+
className="text-sm"
85+
language={langConstants(undefined)}
86+
>
87+
{pkg.licenseText}
88+
</StyledSyntaxHighlighter>
89+
)}
90+
</div>
91+
</div>
92+
);
93+
})}
94+
</div>
95+
);
96+
}

app/about/license/page.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Metadata } from "next";
2+
import licenseText from "@/../LICENSE?raw";
3+
import { LicenseEntry, ThirdPartyLicenses } from "./ThirdPartyLicenses";
4+
import { isCloudflare } from "@/lib/detectCloudflare";
5+
import { getCloudflareContext } from "@opennextjs/cloudflare";
6+
import { readFile } from "node:fs/promises";
7+
import { join } from "node:path";
8+
import { StyledMarkdown } from "@/markdown/markdown";
9+
10+
export const metadata: Metadata = {
11+
title: "ライセンス",
12+
description:
13+
"my.code(); のライセンスおよび使用しているサードパーティライブラリのライセンス情報です。",
14+
};
15+
16+
const content = `
17+
# ライセンス
18+
19+
## my.code(); のライセンス
20+
21+
my.code(); のソースコードは MIT ライセンスのもとで公開されています。
22+
23+
\`\`\`
24+
${licenseText}
25+
\`\`\`
26+
27+
## サードパーティライブラリのライセンス
28+
29+
my.code(); は以下のオープンソースライブラリを使用しています。
30+
`;
31+
32+
export default async function LicensePage() {
33+
let licenses: LicenseEntry[];
34+
if (isCloudflare()) {
35+
const cfAssets = getCloudflareContext().env.ASSETS;
36+
const res = await cfAssets!.fetch(
37+
`https://assets.local/_next/static/oss-licenses.json`
38+
);
39+
licenses = await res.json();
40+
} else {
41+
licenses = JSON.parse(
42+
await readFile(
43+
join(
44+
process.cwd(),
45+
process.env.NODE_ENV === "development"
46+
? ".next/dev/static/oss-licenses.json"
47+
: ".next/static/oss-licenses.json"
48+
),
49+
"utf-8"
50+
)
51+
);
52+
}
53+
54+
return (
55+
<div className="p-4 pb-16 w-full max-w-docs mx-auto">
56+
<StyledMarkdown content={content} />
57+
<ThirdPartyLicenses licenses={licenses} />
58+
</div>
59+
);
60+
}

app/about/runtime/content.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# コード実行環境について
2+
3+
my.code(); では、プログラミング言語ごとに異なる仕組みでコードを実行しています。
4+
以下にそれぞれの言語の実行環境について説明します。
5+
6+
## ブラウザ内で実行される言語
7+
8+
以下の言語は、サーバーへの通信を行わず、すべてお使いのブラウザ内で実行されます。
9+
そのため、インターネット接続が不安定な環境でも、一度ページが読み込まれれば実行可能です。
10+
11+
### Python
12+
13+
Python は [Pyodide](https://pyodide.org/) を使用して実行されます。
14+
Pyodide は CPython(Python の公式実装)を WebAssembly にコンパイルしたものです。
15+
Python コードはブラウザ内の Web Worker 上で動作するため、ページの描画をブロックせずに実行できます。
16+
17+
### Ruby
18+
19+
Ruby は [ruby.wasm](https://ruby.github.io/ruby.wasm/) を使用して実行されます。
20+
ruby.wasm は公式の CRuby を WebAssembly にコンパイルしたものです。
21+
Python と同様に Web Worker 上で動作します。
22+
23+
### JavaScript
24+
25+
JavaScript はブラウザ自身の JavaScript エンジンを利用して実行されます。
26+
コードは安全なサンドボックス環境内で評価されます。
27+
28+
### TypeScript
29+
30+
TypeScript は [@typescript/vfs](https://www.npmjs.com/package/@typescript/vfs) を使用してブラウザ内でコンパイルされ、その後 JavaScript と同じ仕組みで実行されます。
31+
32+
## 外部サービスを利用して実行される言語
33+
34+
以下の言語は、外部のコンパイル・実行サービス([Wandbox](https://wandbox.org/))の API を通じて実行されます。
35+
コードはサーバーに送信されてコンパイル・実行され、結果がブラウザに返されます。
36+
そのため、実行にはインターネット接続が必要です。
37+
また、入力したコードが Wandbox のサーバーに送信されることをご了承ください。
38+
39+
### C++
40+
41+
Wandbox の g++ (GNU C++ Compiler) を使用してコンパイル・実行されます。
42+
最新の安定版コンパイラが使用され、Boost ライブラリも利用可能です。
43+
実行時にエラーが発生した場合は、スタックトレースが表示されます。
44+
45+
### Rust
46+
47+
Wandbox の rustc (Rust コンパイラ) を使用してコンパイル・実行されます。
48+
最新版のコンパイラが使用されます。
49+
50+
---
51+
52+
外部サービスを利用して実行される言語(C++・Rust)では、入力したコードが外部サーバーに送信されます。
53+
個人情報や機密情報を含むコードは入力しないようにしてください。

app/about/runtime/page.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Metadata } from "next";
2+
import { StyledMarkdown } from "@/markdown/markdown";
3+
import content from "./content.md?raw";
4+
5+
export const metadata: Metadata = {
6+
title: "コード実行環境について",
7+
description: "my.code(); で使用しているコード実行環境の仕組みを説明します。",
8+
};
9+
10+
export default function RuntimePage() {
11+
return (
12+
<div className="p-4 pb-16 w-full max-w-docs mx-auto">
13+
<StyledMarkdown content={content} />
14+
</div>
15+
);
16+
}

app/footer.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import Link from "next/link";
2+
13
export function Footer() {
24
return (
35
<footer className="footer sm:footer-horizontal bg-neutral text-neutral-content p-10 z-30">
@@ -26,6 +28,25 @@ export function Footer() {
2628
</a>
2729
<p>Copyright © 2026 ut.code();</p>
2830
</aside>
31+
<nav>
32+
<h6 className="footer-title normal-case">my.code(); について</h6>
33+
<Link href="/about/runtime" className="link link-hover">
34+
コード実行環境について
35+
</Link>
36+
<Link href="/about/ai" className="link link-hover">
37+
AI質問機能について
38+
</Link>
39+
<Link href="/about/license" className="link link-hover">
40+
ライセンス
41+
</Link>
42+
<a
43+
className="link link-hover"
44+
href="https://docs.google.com/forms/d/e/1FAIpQLSfkM2LKhUDgCdY2fGntuv75O3jaWISwKuBIu9MW3h3UD1I3sw/viewform?usp=publish-editor"
45+
target="_blank"
46+
>
47+
お問い合わせ
48+
</a>
49+
</nav>
2950
<nav>
3051
<h6 className="footer-title normal-case">ut.code(); について</h6>
3152
<a

app/markdown/styledSyntaxHighlighter.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,32 +21,47 @@ const SyntaxHighlighter = lazy(() => {
2121

2222
export function StyledSyntaxHighlighter(props: {
2323
children: string;
24+
className?: string;
2425
language: LangConstants;
2526
}) {
2627
const theme = useChangeTheme();
2728
const codetheme = theme === "tomorrow" ? tomorrow : tomorrowNight;
2829
const isClient = useIsClient();
2930
return isClient ? (
30-
<Suspense fallback={<FallbackPre>{props.children}</FallbackPre>}>
31+
<Suspense
32+
fallback={
33+
<FallbackPre className={props.className}>{props.children}</FallbackPre>
34+
}
35+
>
3136
<SyntaxHighlighter
32-
language={props.language.rsh}
37+
language={props.language.rsh ?? "text"}
3338
PreTag="div"
34-
className="border-2 border-current/20 mx-2 my-2 rounded-box p-4! bg-base-300! text-base-content!"
39+
className={clsx(
40+
"border-2 border-current/20 mx-2 my-2 rounded-box p-4! bg-base-300! text-base-content!",
41+
props.className
42+
)}
3543
style={codetheme}
3644
>
3745
{props.children}
3846
</SyntaxHighlighter>
3947
</Suspense>
4048
) : (
41-
<FallbackPre>{props.children}</FallbackPre>
49+
<FallbackPre className={props.className}>{props.children}</FallbackPre>
4250
);
4351
}
44-
function FallbackPre({ children }: { children: string }) {
52+
function FallbackPre({
53+
children,
54+
className,
55+
}: {
56+
children: string;
57+
className?: string;
58+
}) {
4559
return (
4660
<pre
4761
className={clsx(
4862
"border-2 border-current/20 mx-2 my-2 rounded-box p-4! bg-base-300! text-base-content!",
49-
"w-full overflow-auto"
63+
"w-full overflow-auto",
64+
className
5065
)}
5166
>
5267
{children}

0 commit comments

Comments
 (0)