Compare commits

...

3 Commits

16 changed files with 705 additions and 289 deletions

View File

@ -1,3 +1,13 @@
# support_uwuzu_net
ゆずねっとのサポートページです!
簡易的なものなので今後アプデしていきます。
# ゆずねっとサポート
本家https://github.com/Daichimarukana/support_uwuzu_net
## 変更点
- ダークモード対応
- 記事をMarkdownファイルで記述に
- jQueryからVanilla JSへ移管
- フッター+クレジットを追加
- CSS短縮
- コード整形
- モバイル表示のサイズを最小限に変更
- 記事画面で検索ボックスを削除

View File

@ -0,0 +1,8 @@
バルス祭りについてですが...
現在ゆずねっとはユーザ数が100人程度のためおそらくゆずねっと上でバルス祭りを行ってもサーバーはダウンしないものと考えております。
是非バルスしちゃってください。
なお、TLを埋め尽くすほどのユーズはお控えください。
ゆずねっと以外にも簡単にバルスできるボタンを作りましたので是非ご活用ください!
<br>
<a href='https://share.uwuzu.net/?text=バルス!!!' class='link_btn'>バルスる</a>

View File

@ -0,0 +1 @@
残念ながらuwuzuの仕様上ユーザーIDの変更はできません。

View File

@ -0,0 +1,18 @@
パスワードを忘れた場合、ゆずねっとでは二通りの方法でパスワードの復元が行えます。
**なお、パスワードの復元にはメールアドレスの設定が必要です。**
**メールアドレスの設定をされたいない方はパスワードの復元はできません。**
## 1. ユーザーIDとメールアドレスの入力
ゆずねっとの未ログイン時トップページより、ログインボタンを押し、下部にあるパスワード復元ボタンを押してください。
パスワードの復元ページに進みますと、ユーザーIDとメールアドレスの入力ができるので設定したユーザーIDとメールアドレスを入力して次へ進んでください。
## 2. パスワードの再設定
二段階認証を設定しているアカウントでしたら、二段階認証コードと新しいパスワードを入力して次へ進んでください。
もし二段階認証を設定していないアカウントでしたら、メールで認証するボタンを押してください。
これによりメールで二段階認証ができるようになります。
メールの送信には少々時間がかかりますのでページの読み込みが終るまでお待ち下さい。
メールを受信できたら、メールに記載されている二段階認証コードと新しいパスワードを入力して次へ進んでください。
## 3. ログイン
これでパスワードの復元(パスワードリセット)は完了です!
通常のログインページより新しいパスワードでログインをしてください。

View File

@ -0,0 +1,4 @@
ご飯の画像が多すぎることに関してですが、これはこれで私(daichimarukana)は良いと思っていますので大丈夫でしょう
もし深夜時間帯に閲覧してしまい猛烈な食欲に駆り立てられてしまったのであれば申し訳ございません。
ご飯の画像が多すぎることを解消するにはユーザー数を増やすことや様々なトピックのユーズをすることが重要だと考えていますので、是非新規さんを連れてきたりじゃんじゃんユーズしてみてください🤗(利用規約の範囲内でね!)

View File

@ -0,0 +1,8 @@
ゆずねっとのサポートサイトを開設しました!
是非このサポートサイトをご活用ください!
## 使い方
サイトを開くとトップページに記事一覧が表示されます。
お求めの記事をタップすると記事が表示されます!
また、サイト上部の検索欄より検索も可能です!

41
articles/safety_policy.md Normal file
View File

@ -0,0 +1,41 @@
ゆずねっとでは、uwuzuの安全機能を含め、ユーザーの皆様に快適で安心してご利用いただけるよう、さまざまな対策を行っています。
このページでは、その一部をご紹介します!
## 不正アクセスへの対策
ゆずねっとでは、不正アクセスへの対策として、以下の対策を行っています!
### ログイン通知
新たなログインが確認された場合には、ユーザーへそのことを通知する機能が実装されています。
### ユーザーデータの暗号化・ハッシュ化
以下の情報は、各ユーザーごとに発行される鍵を使って暗号化し、安全に保護しています。
- メールアドレス
- 二段階認証の生成コード
- IPアドレス
また、以下のデータは、ハッシュ化(一度変換すると元に戻せない形式)した上で保存しています。
- パスワード
- 二段階認証のバックアップコード
### Captcha認証
ログイン時に、人間による正しい操作であることを確認するためのCaptcha認証を導入しています。
### Self-XSSにも強い認証方式
ユーザーが正しくログインしているかを確認するための鍵を2つ用いて認証をしています。
このうち一つが流出してももう片方の鍵を生成したりログインをすることはできません。
## "もしも"に備えたサーバー運営
ゆずねっとでは、災害やサーバー障害などの"もしも"に備えた、運営を行っております。
以下のような対策により、ユーザーのデータが決して壊れないように対策しています。
### 停電対策
万が一停電が発生しても、UPS(無停電電源装置)によりサーバーへの電力供給を継続します。
さらに、停電が発生すると25秒以内に運営へ通知が届き、5分以上復旧しない場合はデータを保護するためにサーバーを自動的に停止します。
### データ破損対策
万が一ゆずねっとのサーバーが壊れたとしても、データを復旧できるように、ゆずねっとでは定期的にバックアップを保存するようになっています。
バックアップは暗号化され、別のサーバーに最大31日間保存されるため、迅速な復旧が可能です。
### 異常事態対策
サーバーに異常が発生し、アクセスできなくなる事態を防ぐため、24時間体制で自動監視を行っています。
万が一サーバーが停止すると、即座に運営に通知され、早急に対応できる仕組みになっています。

View File

@ -0,0 +1,6 @@
ゆずねっとにサービスステータスページができました!
ゆずねっとの稼働状況やメンテナンスのお知らせなどが表示されます!
是非ご活用ください。
<a href='https://status.uwuzu.net/' class='link_btn'>ゆずねっとステータスページ</a>

27
articles/use_markdown.md Normal file
View File

@ -0,0 +1,27 @@
ユーズで使用できる装飾(一部Markdown)は以下のものです。
```
# [ここにテキスト] (h1サイズで文字を表示)
## [ここにテキスト] (h2サイズで文字を表示)
### [ここにテキスト] (h3サイズで文字を表示)
[[buruburu [ここにテキスト]]] (文字をブルブルさせて表示)
`[ここにテキスト]` (インラインコードとして表示)
***[ここにテキスト]*** (斜体と太字を適用して表示)
**[ここにテキスト]** (太字を適用して表示)
*[ここにテキスト]* (斜体を適用して表示)
~~[ここにテキスト]~~ (文字に取り消し線を入れて表示)
>>> [ここにテキスト] (引用として表示)
||[ここにテキスト]|| (カーソルをのせて文字を表示)
- [ここにテキスト] (箇条書きとして左に点を表示)
```
また、以下の場合に自動的にユーズに装飾が加わることがあります
```
@[userid] (ユーザー名のリンクで表示)
:[emojiname]: (カスタム絵文字で表示)
#[hashtag] (ハッシュタグで表示)
https://youtube.com/watch?v=XXXXXXXXXXX (YouTubeの動画埋め込み(youtu.beなども対応))
https://nicovideo.jp/watch/smXXXXXXX (ニコニコ動画の埋め込み(nico.msなども対応))
その他URL (URLとして装飾)
```
これらの装飾を組み合わせて是非面白いユーズを作ってみてください!

View File

@ -1,60 +1,52 @@
{
"articles": [
{
"title": "安全への取り組み",
"id": "safety_policy",
"date": "2025-03-20",
"description": "ゆずねっとで行われている安全への取り組みについてです!",
"content": "ゆずねっとでは、uwuzuの安全機能を含め、ユーザーの皆様に快適で安心してご利用いただけるよう、さまざまな対策を行っています。 \nこのページでは、その一部をご紹介します \n## 不正アクセスへの対策 \nゆずねっとでは、不正アクセスへの対策として、以下の対策を行っています \n \n### ログイン通知 \n新たなログインが確認された場合には、ユーザーへそのことを通知する機能が実装されています。 \n \n### ユーザーデータの暗号化・ハッシュ化 \n以下の情報は、各ユーザーごとに発行される鍵を使って暗号化し、安全に保護しています。 \n- メールアドレス \n- 二段階認証の生成コード \n- IPアドレス \n \nまた、以下のデータは、ハッシュ化一度変換すると元に戻せない形式した上で保存しています。 \n- パスワード \n- 二段階認証のバックアップコード \n \n### Captcha認証 \nログイン時に、人間による正しい操作であることを確認するためのCaptcha認証を導入しています。 \n \n### Self-XSSにも強い認証方式 \nユーザーが正しくログインしているかを確認するための鍵を2つ用いて認証をしています。 \nこのうち一つが流出してももう片方の鍵を生成したりログインをすることはできません。 \n \n## \"もしも\"に備えたサーバー運営 \nゆずねっとでは、災害やサーバー障害などの\"もしも\"に備えた、運営を行っております。 \n以下のような対策により、ユーザーのデータが決して壊れないように対策しています。 \n \n### 停電対策 \n万が一停電が発生しても、UPS(無停電電源装置)によりサーバーへの電力供給を継続します。 \nさらに、停電が発生すると25秒以内に運営へ通知が届き、5分以上復旧しない場合はデータを保護するためにサーバーを自動的に停止します。 \n \n### データ破損対策 \n万が一ゆずねっとのサーバーが壊れたとしても、データを復旧できるように、ゆずねっとでは定期的にバックアップを保存するようになっています。 \nバックアップは暗号化され、別のサーバーに最大31日間保存されるため、迅速な復旧が可能です。 \n \n### 異常事態対策 \nサーバーに異常が発生し、アクセスできなくなる事態を防ぐため、24時間体制で自動監視を行っています。 \n万が一サーバーが停止すると、即座に運営に通知され、早急に対応できる仕組みになっています。 \n"
},
{
"title": "ステータスページについて",
"id": "status_uwuzu_net",
"date": "2025-02-11",
"description": "ゆずねっとにサービスステータスページができました!",
"content": "ゆずねっとにサービスステータスページができました! \nゆずねっとの稼働状況やメンテナンスのお知らせなどが表示されます \n \n是非ご活用ください。 \n<a href='https://status.uwuzu.net/' class='link_btn'>ゆずねっとステータスページ</a>"
},
{
"title": "バルス祭り",
"id": "balsu_festival",
"date": "2024-08-30",
"description": "本日考えられるバルス祭りについて書きました",
"content": "バルス祭りについてですが... \n現在ゆずねっとはユーザ数が100人程度のためおそらくゆずねっと上でバルス祭りを行ってもサーバーはダウンしないものと考えております。 \n是非バルスしちゃってください。 \nなお、TLを埋め尽くすほどのユーズはお控えください。 \n \nゆずねっと以外にも簡単にバルスできるボタンを作りましたので是非ご活用ください \n<a href='https://share.uwuzu.net/?text=バルス!!!' class='link_btn'>バルスる</a>"
},
{
"title": "ユーズで使用できる装飾について",
"id": "use_markdown",
"date": "2024-08-30",
"description": "uwuzuで使用できる装飾一覧です。",
"content": "ユーズで使用できる装飾(一部Markdown)は以下のものです。 \n``` \n# [ここにテキスト] (h1サイズで文字を表示) \n## [ここにテキスト] (h2サイズで文字を表示) \n### [ここにテキスト] (h3サイズで文字を表示) \n[[buruburu [ここにテキスト]]] (文字をブルブルさせて表示) \n`[ここにテキスト]` (インラインコードとして表示) \n***[ここにテキスト]*** (斜体と太字を適用して表示) \n**[ここにテキスト]** (太字を適用して表示) \n*[ここにテキスト]* (斜体を適用して表示) \n~~[ここにテキスト]~~ (文字に取り消し線を入れて表示) \n>>> [ここにテキスト] (引用として表示) \n||[ここにテキスト]|| (カーソルをのせて文字を表示) \n- [ここにテキスト] (箇条書きとして左に点を表示) \n``` \nまた、以下の場合に自動的にユーズに装飾が加わることがあります \n``` \n@[userid] (ユーザー名のリンクで表示) \n:[emojiname]: (カスタム絵文字で表示) \n#[hashtag] (ハッシュタグで表示) \n \nhttps://youtube.com/watch?v=XXXXXXXXXXX (YouTubeの動画埋め込み(youtu.beなども対応)) \nhttps://nicovideo.jp/watch/smXXXXXXX (ニコニコ動画の埋め込み(nico.msなども対応)) \n \nその他URL (URLとして装飾) \n``` \nこれらの装飾を組み合わせて是非面白いユーズを作ってみてください"
},
{
"title": "TLにご飯の画像が多すぎる",
"id": "meshitero_timeline",
"date": "2024-08-29",
"description": "ゆずねっとで飯テロが横行している件についてです",
"content": "ご飯の画像が多すぎることに関してですが、これはこれで私(daichimarukana)は良いと思っていますので大丈夫でしょう \nもし深夜時間帯に閲覧してしまい猛烈な食欲に駆り立てられてしまったのであれば申し訳ございません。 \n \nご飯の画像が多すぎることを解消するにはユーザー数を増やすことや様々なトピックのユーズをすることが重要だと考えていますので、是非新規さんを連れてきたりじゃんじゃんユーズしてみてください🤗(利用規約の範囲内でね!) \n"
},
{
"title": "パスワードを忘れた",
"id": "forgot_password",
"date": "2024-08-29",
"description": "パスワードの復元(変更)方法について書きました",
"content": "パスワードを忘れた場合、ゆずねっとでは二通りの方法でパスワードの復元が行えます。 \n**なお、パスワードの復元にはメールアドレスの設定が必要です。** \n**メールアドレスの設定をされたいない方はパスワードの復元はできません。** \n \n## 1. ユーザーIDとメールアドレスの入力 \nゆずねっとの未ログイン時トップページより、ログインボタンを押し、下部にあるパスワード復元ボタンを押してください。 \nパスワードの復元ページに進みますと、ユーザーIDとメールアドレスの入力ができるので設定したユーザーIDとメールアドレスを入力して次へ進んでください。 \n \n## 2. パスワードの再設定 \n二段階認証を設定しているアカウントでしたら、二段階認証コードと新しいパスワードを入力して次へ進んでください。 \nもし二段階認証を設定していないアカウントでしたら、メールで認証するボタンを押してください。 \nこれによりメールで二段階認証ができるようになります。 \nメールの送信には少々時間がかかりますのでページの読み込みが終るまでお待ち下さい。 \nメールを受信できたら、メールに記載されている二段階認証コードと新しいパスワードを入力して次へ進んでください。 \n \n## 3. ログイン \nこれでパスワードの復元(パスワードリセット)は完了です! \n通常のログインページより新しいパスワードでログインをしてください。"
},
{
"title": "ユーザーIDを変更したい",
"id": "change_userid",
"date": "2024-08-29",
"description": "結論から申し上げますとユーザーIDの変更はできません。",
"content": "残念ながらuwuzuの仕様上ユーザーIDの変更はできません。"
},
{
"title": "サポートサイトを開設しました!",
"id": "open_uwuzu_net_support",
"date": "2024-08-29",
"description": "ゆずねっとのサポートサイトを開設しました!",
"content": "ゆずねっとのサポートサイトを開設しました! \n是非このサポートサイトをご活用ください \n \n## 使い方 \nサイトを開くとトップページに記事一覧が表示されます。 \nお求めの記事をタップすると記事が表示されます \n \nまた、サイト上部の検索欄より検索も可能です"
}
]
}
"articles": [
{
"title": "安全への取り組み",
"id": "safety_policy",
"date": "2025-03-20",
"description": "ゆずねっとで行われている安全への取り組みについてです!"
},
{
"title": "ステータスページについて",
"id": "status_uwuzu_net",
"date": "2025-02-11",
"description": "ゆずねっとにサービスステータスページができました!"
},
{
"title": "バルス祭り",
"id": "balsu_festival",
"date": "2024-08-30",
"description": "本日考えられるバルス祭りについて書きました"
},
{
"title": "ユーズで使用できる装飾について",
"id": "use_markdown",
"date": "2024-08-30",
"description": "uwuzuで使用できる装飾一覧です。"
},
{
"title": "TLにご飯の画像が多すぎる",
"id": "meshitero_timeline",
"date": "2024-08-29",
"description": "ゆずねっとで飯テロが横行している件についてです"
},
{
"title": "パスワードを忘れた",
"id": "forgot_password",
"date": "2024-08-29",
"description": "パスワードの復元(変更)方法について書きました"
},
{
"title": "ユーザーIDを変更したい",
"id": "change_userid",
"date": "2024-08-29",
"description": "結論から申し上げますとユーザーIDの変更はできません。"
},
{
"title": "サポートサイトを開設しました!",
"id": "open_uwuzu_net_support",
"date": "2024-08-29",
"description": "ゆずねっとのサポートサイトを開設しました!"
}
]
}

81
css/dark.css Normal file
View File

@ -0,0 +1,81 @@
@media (prefers-color-scheme: dark) {
body {
background-color: #0b0b0b;
}
.top {
background-color: #ffc832;
}
.top .left a {
color: #000000;
}
.top .right .searchbox {
border: solid 1px #000000;
background-color: #0b0b0b;
color: #ffffff;
}
main .contents .items:hover {
box-shadow: 0 0px 48px 0 rgba(0, 0, 0, 0.05);
}
main .contents .items {
background-color: #181616;
}
main h1,
main p,
main .contents .items h1,
main .contents .items p,
main .contents .items .date,
main .article .date,
main .article h1,
main .article h2,
main .article h3,
main .article p {
color: #f0f0f0;
}
main .article td,
th {
border: solid 1px #f0f0f0;
}
main .article pre,
.link_btn,
.error p {
color: #0b0b0b;
}
main .article pre {
background-color: #f0f0f0;
}
.link_btn {
background-color: #ffc832;
}
.error {
background-color: #ff4848;
box-shadow: 0 0px 48px 0 rgba(0, 0, 0, 0.15);
}
.error p {
text-shadow: 0 0 0 #0b0b0b;
}
footer {
background-color: #000000;
color: #ffffff;
}
footer a {
color: #ffffff;
}
ul, li, ol {
color: #ffffff;
}
}

View File

@ -1,31 +1,37 @@
@import url('https://fonts.googleapis.com/css2?family=BIZ+UDGothic:wght@400;700&family=BIZ+UDPGothic:wght@400;700&family=Inter:wght@100..900&display=swap');
body{
@import url("https://fonts.googleapis.com/css2?family=BIZ+UDGothic:wght@400;700&family=BIZ+UDPGothic:wght@400;700&family=Inter:wght@100..900&display=swap");
body {
margin: 0px;
width: 100%;
height: fit-content;
background-color: #F7F7F7;
height: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.top{
.top {
width: 100%;
margin: 0px;
height: 64px;
display: flex;
justify-content: space-between;
background-color: #FFC832;
border-radius: 0px 0px 15px 15px;
}
.top .left{
.top .left {
margin-left: 0px;
display: flex;
}
.top .left img{
.top .left img {
width: 48px;
height: 48px;
margin: 8px;
object-fit: cover;
border-radius: 8px;
}
.top .left a{
.top .left a {
display: block;
text-decoration: none;
font-size: 32px;
@ -35,38 +41,38 @@ body{
width: fit-content;
font-family: "Inter", "BIZ UDPGothic", sans-serif;
margin: 8px 0px;
color: #FFFFFF;
}
.top .right{
.top .right {
margin-right: 0px;
display: flex;
}
.top .right .searchbox{
.top .right .searchbox {
width: 200px;
height: 28px;
margin: 16px;
border-radius: 25px;
padding-left: 8px;
border: solid 1px #FFFFFF;
outline: none;
}
main{
main {
margin: 0px auto;
width: 1080px;
}
main h1{
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: bold;
color: #252525;
main h1 {
font-size: 48px;
}
main p{
main p {
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: normal;
color: #252525;
font-size: 16px;
}
main .contents{
main .contents {
margin-top: 32px;
width: 100%;
display: flex;
@ -74,108 +80,106 @@ main .contents{
height: fit-content;
flex-wrap: wrap;
}
main .contents .items{
main .contents .items {
cursor: pointer;
width: calc(50% - 40px);
height: fit-content;
background-color: #FFFFFF;
border-radius: 10px;
padding: 16px;
margin-bottom: 16px;
transition: all 250ms ease-out;
}
main .contents .items:hover{
box-shadow: 0 0px 48px 0 rgba(0, 0, 0, .05);
}
main .contents .items h1{
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: bold;
color: #252525;
main .contents .items h1 {
font-size: 24px;
margin: 4px 0px;
}
main .contents .items p{
main .contents .items p {
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: normal;
color: #252525;
font-size: 14px;
margin: 4px 0px;
}
main .contents .items .date{
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: bold;
color: #252525;
main .contents .items .date {
font-size: 12px;
}
main .article{
main .article {
width: 100%;
height: fit-content;
}
main .article .date{
main h1
main .contents .items .date,
main .contents .items h1
main .article .date,
main .article h1,
main .article h2,
main .article h3 {
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: bold;
color: #252525;
}
main .article .date {
font-size: 16px;
}
main .article h1{
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: bold;
color: #252525;
main .article h1 {
font-size: 48px;
}
main .article h2{
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: bold;
color: #252525;
main .article h2 {
font-size: 32px;
}
main .article h3{
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: bold;
color: #252525;
main .article h3 {
font-size: 24px;
}
main .article p{
main .article p {
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: normal;
color: #252525;
font-size: 16px;
}
main .article table{
main .article table {
margin: 16px 0px;
width: calc(fit-content + 128px);
border: none;
border-collapse: collapse;
}
main .article td, th {
main .article td,
th {
padding: 4px 16px;
border: solid 1px #252525;
}
main .article pre{
main .article pre {
width: 100%;
height: fit-content;
background-color: #252525;
padding: 16px;
border-radius: 15px;
color: #F7F7F7;
font-family: "BIZ UDGothic", sans-serif;
}
.link_btn{
.link_btn {
line-height: 64px;
width: fit-content;
height: 32px;
padding: 8px 16px;
background-color: #FFC832;
color: #F7F7F7;
text-decoration: none;
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-weight: normal;
font-size: 20px;
border-radius: 25px;
}
.error {
position: absolute;
animation: slideDown 5.0s ease-in-out forwards;
animation: slideDown 5s ease-in-out forwards;
margin-top: 32px;
margin-right: auto;
margin-left: auto;
@ -184,12 +188,11 @@ main .article pre{
width: fit-content;
height: 32px;
z-index: 9999;
background-color: #FF4848;
border-radius: 20px;
box-shadow: 0 0px 48px 0 rgba(0, 0, 0, .15);
text-decoration: none;
}
.error p{
.error p {
margin-top: 4px;
margin-bottom: 4px;
margin-left: 12px;
@ -197,34 +200,50 @@ main .article pre{
line-height: 24px;
font-family: "Inter", "BIZ UDPGothic", sans-serif;
font-size: 16px;
color: #F7F7F7;
color: transparent;
text-shadow: 0 0 0 #F7F7F7;
color: transparent;
text-align: center;
}
@keyframes slideDown {
0%, 100% { transform: translateY(-40dvh); }
20%, 90% { transform: translateY(0px); }
footer {
margin: 0 auto;
text-align: center;
width: 100%;
}
@media screen and (max-width: 1080px) {
.top .left a{
@keyframes slideDown {
0%,
100% {
transform: translateY(-40dvh);
}
20%,
90% {
transform: translateY(0px);
}
}
@media screen and (max-width: 581px) {
.top .left a {
display: none;
}
main{
main {
margin: 0px auto;
width: calc(100% - 32px);
overflow-wrap: normal;
}
main .contents{
main .contents {
display: block;
height: fit-content;
}
main .contents .items{
main .contents .items {
width: calc(100% - 32px);
}
main .article pre{
main .article pre {
width: calc(100% - 32px);
overflow: scroll;
}
}
}

75
css/light.css Normal file
View File

@ -0,0 +1,75 @@
@media (prefers-color-scheme: light) {
body {
background-color: #f7f7f7;
}
.top {
background-color: #ffc832;
}
.top .left a {
color: #ffffff;
}
.top .right .searchbox {
border: solid 1px #ffffff;
}
main .contents .items:hover {
box-shadow: 0 0px 48px 0 rgba(0, 0, 0, 0.05);
}
main .contents .items {
background-color: #ffffff;
}
main h1,
main p,
main .contents .items h1,
main .contents .items p,
main .contents .items .date,
main .article .date,
main .article h1,
main .article h2,
main .article h3,
main .article p {
color: #252525;
}
main .article td,
th {
border: solid 1px #252525;
}
main .article pre,
.link_btn,
.error p {
color: #f7f7f7;
}
main .article pre {
background-color: #252525;
}
.link_btn {
background-color: #ffc832;
}
.error {
background-color: #ff4848;
box-shadow: 0 0px 48px 0 rgba(0, 0, 0, 0.15);
}
.error p {
text-shadow: 0 0 0 #f7f7f7;
}
footer {
background-color: #f0f0f0;
color: #000000;
}
footer a {
color: #000000;
}
}

View File

@ -1,159 +1,62 @@
<!DOCTYPE html>
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ゆずねっとサポート</title>
<link rel="stylesheet" href="css/style.css" type="text/css">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body>
<div id="error" class="error" style="display:none;">
<p>Error</p>
</div>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<div class="top">
<div class="left">
<img src="img/uwuzu_net_icon.png">
<a href="index.html">ゆずねっとサポート</a>
<link rel="icon" href="/img/uwuzu_net_icon.png" />
<title>ゆずねっとサポート</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="/css/layout.css" type="text/css" />
<link rel="stylesheet" href="/css/light.css" type="text/css" />
<link rel="stylesheet" href="/css/dark.css" type="text/css" />
</head>
<body>
<div id="error" class="error" style="display: none">
<p id="errorMsg">Error</p>
</div>
<div class="right">
<input class="searchbox" type="text" id="searchbox" placeholder="検索">
<div class="top">
<div class="left">
<img src="/img/uwuzu_net_icon.png" />
<a href="/">ゆずねっとサポート</a>
</div>
<div class="right">
<input
class="searchbox"
type="text"
id="searchbox"
placeholder="検索"
/>
</div>
</div>
</div>
<main>
<div id="top">
<h1>ゆずねっとサポート</h1>
<p>ゆずねっとのサポートサイトです。<br>
右上の検索欄から検索するか下から記事を選択すると閲覧ができます!</p>
<main>
<div id="top">
<h1 class="articlelist">ゆずねっとサポート</h1>
<p class="articlelist">
ゆずねっとのサポートサイトです。
<br />
右上の検索欄から検索するか下から記事を選択すると閲覧ができます!
</p>
<div id="contents" class="contents articlelist" />
</div>
<div id="contents" class="contents"></div>
</div>
<div id="docs" style="display: none;">
<div id="docs" />
</main>
</div>
</main>
</body>
<footer>
Created by
<a class="credit" href="https://daichimarukana.com">Daichimarukana</a>
<script>
function showError(text){
$("#error").children("p").text(text);
$("#error").show();
setTimeout(function(){
$("#error").hide();
}, 5000);
}
<br>
$(document).ready(function() {
// グローバル変数としてJSONデータを保持
var articlesData;
// JSONを読み込み、ページにコンテンツを追加
$.getJSON('contents.json', function(data) {
articlesData = data.articles; // JSONデータを保持
$.each(articlesData, function(index, article) {
// 記事のHTML要素を作成して追加
$('#contents').append(
`<div class="items" id="${article.id}">
<div class="date">${article.date}</div>
<h1>${article.title}</h1>
<p>${article.description}</p>
</div>`
);
});
var now_url = window.location.href;
var url = new URL(now_url);
var data = url.searchParams.get("article");
if(!(data === null)){
var article = articlesData.find(function(a) {
return a.id === data;
});
if (article) {
$('#docs').html(
`<div class="article">
<h1>${article.title}</h1>
<div class="date">${article.date}</div>
<div class="content">${marked.parse(article.content)}</div>
</div>`
).show();
$('#top').hide();
history.pushState({ articleId: data }, article.title, `?article=${data}`);
} else {
showError("記事が存在しませんでした");
}
}
$("#contents").on('click', '.items', function() {
var id = $(this).attr("id");
var article = articlesData.find(function(a) {
return a.id === id;
});
if (article) {
$('#docs').html(
`<div class="article">
<h1>${article.title}</h1>
<div class="date">${article.date}</div>
<div class="content">${marked.parse(article.content)}</div>
</div>`
).show();
$('#top').hide();
history.pushState({ articleId: id }, article.title, `?article=${id}`);
} else {
showError("記事が存在しませんでした");
}
});
window.addEventListener('popstate', function(event) {
if (event.state && event.state.articleId) {
// 特定の記事の状態
var id = event.state.articleId;
var article = articlesData.find(function(a) {
return a.id === id;
});
if (article) {
$('#docs').html(
`<div class="article">
<h1>${article.title}</h1>
<div class="date">${article.date}</div>
<div class="content">${marked.parse(article.content)}</div>
</div>`
).show();
$('#top').hide();
}
} else {
$('#docs').hide();
$('#top').show();
}
});
// 検索機能
$('#searchbox').on('input', function() {
var searchText = $(this).val().toLowerCase();
$('#contents .items').each(function() {
var title = $(this).find('h1').text().toLowerCase();
var description = $(this).find('p').text().toLowerCase();
if (title.includes(searchText) || description.includes(searchText)) {
$(this).show(); // マッチする場合は表示
} else {
$(this).hide(); // マッチしない場合は非表示
}
});
});
}).fail(function() {
showError("記事一覧を取得できませんでした!");
});
});
</script>
Edited by
<a class="credit" href="https://last2014.com">Last2014</a>
</footer>
</body>
<script src="/js/script.js"></script>
<script src="/js/credit.js"></script>
</html>

20
js/credit.js Normal file
View File

@ -0,0 +1,20 @@
const footer = document.querySelector("footer");
const startYear = 2024;
const nowYear = new Date().getFullYear();
if (startYear === nowYear) {
footer.innerHTML = `
&copy;${String(startYear)} uwuzu.net
<br>
` + footer.innerHTML;
} else {
footer.innerHTML = `
&copy;${String(startYear)}-${String(nowYear)} uwuzu.net
<br>
` + footer.innerHTML;
}

203
js/script.js Normal file
View File

@ -0,0 +1,203 @@
// エラー表示
function showError(text) {
const errorMsgElement = document.querySelector("#errorMsg");
const errorElement = document.querySelector("#error");
if (errorMsgElement) {
errorMsgElement.textContent = text;
}
if (errorElement) {
errorElement.style.display = "block";
setTimeout(() => {
errorElement.style.display = "none";
}, 5000);
}
}
document.addEventListener("DOMContentLoaded", async () => {
try {
// contents.json読み込み
const response = await fetch("/contents.json");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
const articlesData = data.articles;
if (!Array.isArray(articlesData)) {
throw new Error("記事データが不正な形式です");
}
// #contents読み込み
const contentsContainer = document.querySelector("#contents");
if (!contentsContainer) {
throw new Error("#contentsが見つかりません");
}
contentsContainer.innerHTML = "";
// 記事一覧作成
articlesData.forEach(article => {
// ID取得
const articleElement = document.createElement("div");
articleElement.className = "items";
articleElement.id = article.id;
// 日付取得
const dateElement = document.createElement("div");
dateElement.className = "date";
dateElement.textContent = String(article.date);
// タイトル取得
const titleElement = document.createElement("h1");
titleElement.textContent = String(article.title);
// 説明取得
const descriptionElement = document.createElement("p");
descriptionElement.textContent = String(article.description);
// 親要素に追加
articleElement.appendChild(dateElement);
articleElement.appendChild(titleElement);
articleElement.appendChild(descriptionElement);
contentsContainer.appendChild(articleElement);
});
// URLパラメータから記事IDを取得
const urlParams = new URLSearchParams(window.location.search);
const articleId = urlParams.get("article");
if (articleId) {
const article = articlesData.find(a => a && a.id === articleId);
if (article) {
showArticle(article);
} else {
showError("記事が存在しませんでした");
}
}
// 記事移動
contentsContainer.addEventListener("click", (e) => {
const itemElement = e.target.closest(".items");
if (itemElement && itemElement.id) {
const id = itemElement.id;
const article = articlesData.find(a => a && a.id === id);
if (article) {
showArticle(article);
try {
history.pushState({ articleId: id }, article.title, `?article=${id}`);
} catch (error) {
console.warn("History API操作に失敗しました:", error);
}
} else {
showError("記事が存在しませんでした");
}
}
});
// 検索
const searchBox = document.querySelector("#searchbox");
if (searchBox) {
searchBox.addEventListener("input", (e) => {
const searchText = (e.target.value || '').toLowerCase();
const items = document.querySelectorAll("#contents .items");
items.forEach(item => {
const titleElement = item.querySelector("h1");
const descriptionElement = item.querySelector("p");
if (titleElement && descriptionElement) {
const title = (titleElement.textContent || '').toLowerCase();
const description = (descriptionElement.textContent || '').toLowerCase();
if (title.includes(searchText) || description.includes(searchText)) {
item.style.display = "block";
} else {
item.style.display = "none";
}
}
});
});
}
// 記事表示
async function showArticle(article) {
// #docs・#top取得
const docsElement = document.querySelector("#docs");
const topElement = document.querySelector("#top");
// データ存在確認
if (docsElement && topElement && article && article.title && article.date) {
// 記事div作成
const articleDiv = document.createElement("div");
articleDiv.className = "article";
// タイトル取得
const titleElement = document.createElement("h1");
titleElement.textContent = String(article.title);
// 日付取得
const dateElement = document.createElement("div");
dateElement.className = "date";
dateElement.textContent = String(article.date);
// 内容
const contentElement = document.createElement("div");
contentElement.className = "content";
// 記事内容
try {
// mdファイル読み込み
const response = await fetch(`/articles/${article.id}.md`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.text();
// パース
const content = data || '';
if (typeof marked !== 'undefined' && typeof marked.parse === 'function') {
contentElement.innerHTML = marked.parse(content);
} else {
contentElement.textContent = content;
}
} catch (error) {
console.error("Markdownパースエラー:", error);
contentElement.textContent = response || '';
}
// 親要素に追加
articleDiv.appendChild(titleElement);
articleDiv.appendChild(dateElement);
articleDiv.appendChild(contentElement);
// 記事表示
docsElement.innerHTML = "";
docsElement.appendChild(articleDiv);
docsElement.style.display = "block";
// 記事一覧非表示
const articleList = document.querySelectorAll(".articlelist");
for (let i = 0; i < articleList.length; i++) {
articleList[i].style.display = "none";
}
// 検索ボックス削除
document.querySelector(".right").remove();
}
}
} catch (error) {
console.error("データの読み込みに失敗しました:", error);
showError("データの読み込みに失敗しました");
}
});