Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Improve code]: astro/src/components/Client/bsky/* 手動formatter・Linter対応 #83

Merged
merged 27 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1863c56
Merge remote-tracking branch 'upstream/develop' into feature/issue_55
ZEKE320 Apr 7, 2024
51ab570
Merge branch 'feature/issue_62' into feature/issue_55
ZEKE320 Apr 7, 2024
d8fd91a
🚨 astro/src/components/Client/bsky/にESLintの--fixオプションを適用
ZEKE320 Apr 7, 2024
40f97ec
🔒️ target="_blank"付のタグの脆弱性対策を追加
ZEKE320 Apr 7, 2024
624cf9e
🚨 readDrafts()が常にtruthyな値を返すようなので、OR演算子を削除
ZEKE320 Apr 7, 2024
82ad2cd
🏷️ atproto_apiの型定義変更に伴い、既存の実装の型情報を更新
ZEKE320 Apr 7, 2024
c8c9587
🚨 Promise<void>を返す関数にvoidキーワードを追加
ZEKE320 Apr 7, 2024
7afa8cb
🚨 バッククォートで囲われたダブルクォートのエスケープを解除
ZEKE320 Apr 7, 2024
fc6aca6
✏️ identifierの綴りを修正
ZEKE320 Apr 7, 2024
d5221f3
🚨 map()で繰り返し出力されるコンポーネントに、key属性を追加
ZEKE320 Apr 7, 2024
5dde2ec
🚨 使用されないエラー変数にアンダースコアを追加
ZEKE320 Apr 7, 2024
ac8f1d7
🏷️ atproto_apiの型定義変更に伴い、既存の実装の型情報を更新
ZEKE320 Apr 7, 2024
7c1baac
🎨 astro/src/components/Client/bskyにPrettierを適用
ZEKE320 Apr 7, 2024
3922b0a
Merge branch 'feature/issue_55' into preview/issue_55
ZEKE320 Apr 7, 2024
fa6c374
Merge branch 'preview/issue_62' into preview/issue_55
ZEKE320 Apr 7, 2024
20d4027
Merge remote-tracking branch 'upstream/preview/issue_62' into preview…
ZEKE320 Apr 7, 2024
3082156
✏️ `LoginForm`の注意文言に、環境変数の`servicename`を用いるよう変更
ZEKE320 Apr 10, 2024
c011d41
💬 エラー処理後の型アサーションを解説するコメントを追記
ZEKE320 Apr 10, 2024
6178aea
🥅 使用されていないエラー変数名をアンダースコアのみに変更
ZEKE320 Apr 10, 2024
683f27d
Merge branch 'feature/issue_55' into preview/issue_55
ZEKE320 Apr 10, 2024
420d64e
🚨 エラー型の判定を`"error" in val`形式で統一
ZEKE320 Apr 11, 2024
59ff033
♻️ 変数定義と値の代入を凝集化
ZEKE320 Apr 11, 2024
31e1ff8
🚨 エラー型の判定を`"error" in val`形式で統一
ZEKE320 Apr 11, 2024
2a21df7
🏷️ 型アサーションを用いない実装に変更
ZEKE320 Apr 11, 2024
59b4d4b
🔥 不要になったimport文を削除
ZEKE320 Apr 11, 2024
8d28cab
🎨 astro/src/components/Client/bsky/*にPrettierを適用
ZEKE320 Apr 11, 2024
703a463
Merge remote-tracking branch 'origin/feature/issue_55' into preview/i…
ZEKE320 Apr 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 61 additions & 40 deletions astro/src/components/Client/bsky/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import { useState, useEffect, useContext, Dispatch, SetStateAction } from "react"
import {
useState,
useEffect,
useContext,
Dispatch,
SetStateAction,
} from "react"
import { inputtext_base, link } from "../common/tailwindVariants"
import { Session_context, Profile_context } from "../common/contexts"
import { type msgInfo } from "../common/types"
import createSession from "@/utils/atproto_api/createSession";
import loadProfile from "./lib/loadProfile";
import createSession from "@/utils/atproto_api/createSession"
import loadProfile from "./lib/loadProfile"

import { writeJwt } from "@/utils/useLocalStorage"
import ProcButton from "../common/ProcButton"
import Tooltip from "../common/Tooltip"
import SavePasswordToggle from "./optionToggles/SavePasswordToggle"
import { readLogininfo, setLogininfo } from "@/utils/useLocalStorage"
import { writeJwt, readLogininfo, setLogininfo } from "@/utils/useLocalStorage"
import { servicename } from "@/env/vars"

export const Component = ({
setMsgInfo,
}: {
setMsgInfo: Dispatch<SetStateAction<msgInfo>>,
setMsgInfo: Dispatch<SetStateAction<msgInfo>>
}) => {
const [loading, setLoad] = useState<boolean>(false)
const [savePassword, setSavePassword] = useState<boolean>(false)
const [identifier, setIdentifer] = useState<string>("")
const [identifier, setIdentifier] = useState<string>("")
const [password, setPassword] = useState<string>("")
const { setSession } = useContext(Session_context)
const { setProfile } = useContext(Profile_context)
Expand All @@ -32,10 +38,10 @@ export const Component = ({
}
const res = await createSession({
identifier: id,
password: pw
password: pw,
})
if (typeof res.error !== "undefined") {
let e: Error = new Error(res.message)
if ("error" in res) {
const e: Error = new Error(res.message)
e.name = res.error
throw e
} else {
Expand All @@ -50,13 +56,13 @@ export const Component = ({
if (savePassword === true) {
setLogininfo({
id: identifier,
pw: password
pw: password,
})
}
// プロフィールを読み込み
await loadProfile({
session: res,
setProfile: setProfile
setProfile: setProfile,
})
}
} catch (error: unknown) {
Expand All @@ -66,7 +72,7 @@ export const Component = ({
}
setMsgInfo({
msg: msg,
isError: true
isError: true,
})
}
setLoad(false)
Expand All @@ -78,77 +84,92 @@ export const Component = ({
msg: "ブラウザに保存されたID/APWでログイン中...",
isError: false,
})
await handleLogin(
loginInfo.id,
loginInfo.pw)
await handleLogin(loginInfo.id, loginInfo.pw)
}
}
useEffect(() => {
handleOnLoad()
void handleOnLoad()
}, [])

return (
<>
<div>
<div className="mt-16">
<div className="align-middle mb-0">
<label className="w-32 inline-block my-auto">
Email or ID:
</label>
<input onChange={(event) => setIdentifer(event.target.value)}
<input
onChange={event => setIdentifier(event.target.value)}
placeholder="example.bsky.social"
disabled={loading}
className={inputtext_base({
class: "max-w-52 w-full px-2",
kind: "outbound",
disabled: loading
})} type="text" />
disabled: loading,
})}
type="text"
/>
</div>
<div className="align-middle">
<label className="w-32 inline-block my-auto">
AppPassword※:
</label>
<input onChange={(event) => setPassword(event.target.value)}
<input
onChange={event => setPassword(event.target.value)}
placeholder="this-isex-ampl-epwd"
disabled={loading}
className={inputtext_base({
class: "max-w-52 w-full px-2",
kind: "outbound",
disabled: loading
})} type="password" />
disabled: loading,
})}
type="password"
/>
</div>
<div className="my-2">
<ProcButton
handler={handleLogin}
isProcessing={loading}
context="Blueskyアカウントへログイン"
disabled={!(identifier.length > 0 && password.length > 0)}
showAnimation={true} />
disabled={
!(identifier.length > 0 && password.length > 0)
}
showAnimation={true}
/>
</div>
<div className="mx-auto w-fit">
<SavePasswordToggle
labeltext={"ID/AppPasswordをブラウザへ保存する"}
prop={savePassword}
setProp={setSavePassword} />
setProp={setSavePassword}
/>
</div>
<Tooltip tooltip={
<div className="flex flex-col sm:flex-row">
<div className="inline-block px-4 py-2 text-left">
(BskyLinXに限らず)非公式のアプリを使う際はAppPasswordの利用が推奨されています。
<a className={link()}
target="_blank"
href="https://bsky.app/settings/app-passwords">
<b>bsky.appの⚙設定</b>→<b>🔒高度な設定(新規タブが開きます)</b>
</a>から生成してください。
<Tooltip
tooltip={
<div className="flex flex-col sm:flex-row">
<div className="inline-block px-4 py-2 text-left">
{`(${servicename}に限らず)非公式のアプリを使う際はAppPasswordの利用が推奨されています。`}
<a
className={link()}
target="_blank"
href="https://bsky.app/settings/app-passwords"
rel="noopener noreferrer"
>
<b>bsky.appの⚙設定</b>→
<b>🔒高度な設定(新規タブが開きます)</b>
</a>
から生成してください。
</div>
</div>
</div>
}>
}
>
<span className="text-sky-400">
※AppPasswordとは?(タップで説明を表示)
</span>
</Tooltip>
</div>
</>
</div>
)
}

export default Component
export default Component
86 changes: 49 additions & 37 deletions astro/src/components/Client/bsky/MediaPreview/AltDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// utils
import React, { memo, useRef, useCallback, useState, useEffect } from "react";
import React, { memo, useRef, useCallback, useState, useEffect } from "react"

// component
import OverlayDialog from "../../common/OverlayDialog"
Expand All @@ -9,50 +9,54 @@ import { inputtext_base, link } from "../../common/tailwindVariants"
import { MediaData } from "../../common/types"

const Img = ({
mediaDataItem
mediaDataItem,
}: {
mediaDataItem: {
alt: string
blob: Blob
}
}) => {
return (
<img src={URL.createObjectURL(mediaDataItem.blob)} className="max-w-md w-full mx-auto" />
<img
src={URL.createObjectURL(mediaDataItem.blob)}
className="max-w-md w-full mx-auto"
/>
)
}
const MemoImg = memo(Img)

export const Component = ({
itemId,
mediaData
mediaData,
}: {
itemId: number,
itemId: number
mediaData: MediaData
}) => {
// mediaDataがimageではない場合はコンポーネントを無効に
if (mediaData === null || mediaData.type !== "images") {
return
}
let mediaDataItem = mediaData.images[itemId]
const textref = useRef<HTMLTextAreaElement | null>(null);
const textref = useRef<HTMLTextAreaElement | null>(null)
const [altBoxText, setAltBoxText] = useState<string>(mediaDataItem.alt)
const maxShowAltLength = 10

const handleOpenDialog = () => {
if (textref.current) {
textref.current.value = mediaDataItem.alt
}
};
}

const handleCloseDialog = () => {
mediaDataItem.alt = altBoxText
};
}

const handleClickInDialog = useCallback(
(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
e.stopPropagation();
}, []
);
e.stopPropagation()
},
[],
)

const handleOnChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
// メディアがimagesの場合のみ処理
Expand Down Expand Up @@ -81,43 +85,51 @@ export const Component = ({
callbackOpenDialog={handleOpenDialog}
callbackCloseDialog={handleCloseDialog}
buttonOption={{
className: [
"rounded-lg", "border-1",
"bg-opacity-70", "px-2",
"bg-black", "border-white",
"text-white", "absolute",
"left-1", "bottom-1"].join(" ") + (
altBoxText !== "" ? (" bg-blue-500") : ("")
),
className:
[
"rounded-lg",
"border-1",
"bg-opacity-70",
"px-2",
"bg-black",
"border-white",
"text-white",
"absolute",
"left-1",
"bottom-1",
].join(" ") + (altBoxText !== "" ? " bg-blue-500" : ""),
content:
altBoxText !== "" ? (
`${altBoxText.slice(0, maxShowAltLength)
}${altBoxText.length >= maxShowAltLength
? ("...") : ("")}`
) : (
"Altを設定"
)
}}>
<div onClick={handleClickInDialog} >
<MemoImg
mediaDataItem={mediaDataItem} />
<label>画像に設定するAltを入力(ダイアログを閉じると反映)</label>
<textarea onChange={handleOnChange}
altBoxText !== ""
? `${altBoxText.slice(0, maxShowAltLength)}${
altBoxText.length >= maxShowAltLength ? "..." : ""
}`
: "Altを設定",
}}
>
<div onClick={handleClickInDialog}>
<MemoImg mediaDataItem={mediaDataItem} />
<label>
画像に設定するAltを入力(ダイアログを閉じると反映)
</label>
<textarea
onChange={handleOnChange}
autoFocus={true}
ref={textref}
placeholder="上記に設定するAltを入力してください"
className={inputtext_base({
kind: "outbound",
class: "p-4 w-full md:w-lg resize-y overflow-y-auto h-32"
class: "p-4 w-full md:w-lg resize-y overflow-y-auto h-32",
})}
/>
<button
className={link({ enabled: !(altBoxText === "") })}
disabled={altBoxText === ""}
onClick={handleClick}
>内容をクリア</button>
>
内容をクリア
</button>
</div>
</OverlayDialog>
);
};
export default Component
)
}
export default Component
Loading