-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from yoshiya0503/development
🎉v1.0 Release
- Loading branch information
Showing
72 changed files
with
2,209 additions
and
433 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,37 @@ | ||
# rain | ||
bluesky client | ||
# ☔Rain | ||
|
||
![Vercel](https://vercelbadge.vercel.app/api/yoshiya0503/rain) | ||
![React](https://badges.aleen42.com/src/react.svg) | ||
![Typescript](https://github.com/aleen42/badges/raw/master/src/typescript.svg) | ||
|
||
**_Simple and beautiful bluesky client for web._** | ||
|
||
<img width="1388" alt="スクリーンショット 2023-10-09 15 33 54" src="https://github.com/yoshiya0503/rain/assets/5334715/0963573d-d586-42fa-86ec-867e62851bfe"> | ||
|
||
# 🖥 Development | ||
|
||
you only try follow. | ||
|
||
``` | ||
yarn | ||
yarn dev | ||
``` | ||
|
||
# 🔖 Deployment | ||
|
||
Now we use vercel to deploy. (hosting service for SPA) | ||
|
||
# 🔨 Architecture | ||
|
||
- _only to use react and material-UI._ | ||
- _we use <Suspense /> (react new feature) at all of api call._ | ||
- _response data managed by zustand._ | ||
- _we use typescript and reference types of atproto lexicons._ | ||
|
||
# ✨ Directory | ||
|
||
- pages -> call by react-router-dom. | ||
- stores -> zustand state management. | ||
- templates -> layout component and skeletons UI in loading. | ||
- components -> UI components by using MUI. | ||
- hooks -> separated localize data manage, and logic from components. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
{ | ||
"name": "skyline", | ||
"name": "rain", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import _ from "lodash"; | ||
import { useCallback } from "react"; | ||
import { useStore } from "@/stores"; | ||
import Stack from "@mui/material/Stack"; | ||
import Button from "@mui/material/Button"; | ||
import Divider from "@mui/material/Divider"; | ||
import Switch from "@mui/material/Switch"; | ||
import ToggleButton from "@mui/material/ToggleButton"; | ||
import ToggleButtonGroup from "@mui/material/ToggleButtonGroup"; | ||
import Dialog from "@mui/material/Dialog"; | ||
import DialogActions from "@mui/material/DialogActions"; | ||
import DialogContent from "@mui/material/DialogContent"; | ||
import DialogContentText from "@mui/material/DialogContentText"; | ||
import DialogTitle from "@mui/material/DialogTitle"; | ||
import List from "@mui/material/List"; | ||
import ListItem from "@mui/material/ListItem"; | ||
import ListItemText from "@mui/material/ListItemText"; | ||
import Typography from "@mui/material/Typography"; | ||
import { AppBskyActorDefs } from "@atproto/api"; | ||
|
||
type Props = { | ||
open: boolean; | ||
preferences: AppBskyActorDefs.Preferences; | ||
onClose: () => void; | ||
}; | ||
|
||
export const DialogContentFilter = (props: Props) => { | ||
const updatePreferences = useStore((state) => state.updatePreferences); | ||
const adultPref = _.find(props.preferences, (p) => AppBskyActorDefs.isAdultContentPref(p)); | ||
const contentLabelPref = _.filter(props.preferences, (p) => AppBskyActorDefs.isContentLabelPref(p)); | ||
|
||
const label = { | ||
impersonation: { | ||
title: "Impersonation", | ||
description: "Accounts falsely claiming to be people or orgs", | ||
}, | ||
nsfw: { | ||
title: "Explicit Sexual Images", | ||
description: "i.e. pornography", | ||
}, | ||
gore: { | ||
title: "Violent / Bloody", | ||
description: "Gore, self-harm, torture", | ||
}, | ||
suggestive: { | ||
title: "Sexually Suggestive", | ||
description: "Does not include nudity", | ||
}, | ||
hate: { | ||
title: "Hate Group Iconography", | ||
description: "Images of terror groups, articles covering events, etc.", | ||
}, | ||
nudity: { | ||
title: "Other Nudity", | ||
description: "Including non-sexual and artistic", | ||
}, | ||
spam: { | ||
title: "Spam", | ||
description: "Excessive unwanted interactions", | ||
}, | ||
}; | ||
|
||
const onToggleAdult = useCallback(() => { | ||
const preferences = _.map(props.preferences, (pref) => { | ||
if (AppBskyActorDefs.isAdultContentPref(pref)) return { ...pref, enabled: !pref.enabled }; | ||
return pref; | ||
}); | ||
updatePreferences(preferences); | ||
}, [props, updatePreferences]); | ||
|
||
const onChangeFilter = useCallback( | ||
(label: string) => (__: React.MouseEvent<HTMLElement>, visibility: string) => { | ||
const preferences = _.map(props.preferences, (pref) => { | ||
if (label === pref.label) return { ...pref, visibility }; | ||
return pref; | ||
}); | ||
updatePreferences(preferences); | ||
}, | ||
[props, updatePreferences] | ||
); | ||
|
||
return ( | ||
<Dialog open={props.open} fullWidth maxWidth="sm" PaperProps={{ sx: { borderRadius: 3 } }} onClose={props.onClose}> | ||
<DialogTitle>Content Filter</DialogTitle> | ||
<DialogContent> | ||
<DialogContentText component="div"> | ||
<Stack direction="row" spacing={2} alignItems="center"> | ||
<Switch checked={!!adultPref?.enabled} onChange={onToggleAdult} /> | ||
Enable Sexual Content | ||
</Stack> | ||
</DialogContentText> | ||
<List> | ||
{_.map(contentLabelPref, (pref: AppBskyActorDefs.ContentLabelPref) => ( | ||
<ListItem | ||
key={pref.label} | ||
divider | ||
secondaryAction={ | ||
<ToggleButtonGroup | ||
color="primary" | ||
size="small" | ||
exclusive | ||
value={pref.visibility} | ||
onChange={onChangeFilter(pref.label)} | ||
> | ||
<ToggleButton value="hide"> | ||
<Typography sx={{ fontWeight: 600, textTransform: "none" }} variant="caption"> | ||
Hide | ||
</Typography> | ||
</ToggleButton> | ||
<ToggleButton value="warn"> | ||
<Typography sx={{ fontWeight: 600, textTransform: "none" }} variant="caption"> | ||
Warn | ||
</Typography> | ||
</ToggleButton> | ||
<ToggleButton value="show"> | ||
<Typography sx={{ fontWeight: 600, textTransform: "none" }} variant="caption"> | ||
Show | ||
</Typography> | ||
</ToggleButton> | ||
</ToggleButtonGroup> | ||
} | ||
> | ||
<ListItemText primary={_.get(label, pref.label).title} secondary={_.get(label, pref.label).description} /> | ||
</ListItem> | ||
))} | ||
</List> | ||
</DialogContent> | ||
<Divider /> | ||
<DialogActions sx={{ display: "flex", alignItems: "center", justifyContent: "center" }}> | ||
<Button sx={{ width: "50%", borderRadius: 5, fontWeight: 600 }} variant="contained" onClick={props.onClose}> | ||
DONE | ||
</Button> | ||
</DialogActions> | ||
</Dialog> | ||
); | ||
}; | ||
|
||
export default DialogContentFilter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import _ from "lodash"; | ||
import { useCallback } from "react"; | ||
import { useStore } from "@/stores"; | ||
import Stack from "@mui/material/Stack"; | ||
import IconButton from "@mui/material/IconButton"; | ||
import Button from "@mui/material/Button"; | ||
import Dialog from "@mui/material/Dialog"; | ||
import Divider from "@mui/material/Divider"; | ||
import Avatar from "@mui/material/Avatar"; | ||
import List from "@mui/material/List"; | ||
import ListItem from "@mui/material/ListItem"; | ||
import ListItemAvatar from "@mui/material/ListItemAvatar"; | ||
import ListItemText from "@mui/material/ListItemText"; | ||
import DialogContent from "@mui/material/DialogContent"; | ||
import DialogActions from "@mui/material/DialogActions"; | ||
import DialogTitle from "@mui/material/DialogTitle"; | ||
import PushPinRoundedIcon from "@mui/icons-material/PushPinRounded"; | ||
import DeleteForeverRoundedIcon from "@mui/icons-material/DeleteForeverRounded"; | ||
import useFeedGenerator from "@/hooks/useFeedGenerator"; | ||
import { AppBskyFeedDefs, AppBskyActorDefs } from "@atproto/api"; | ||
|
||
type Props = { | ||
feeds: AppBskyFeedDefs.GeneratorView[]; | ||
preferences: AppBskyActorDefs.Preferences; | ||
open: boolean; | ||
onClose: () => void; | ||
onSend?: () => void; | ||
}; | ||
|
||
export const DialogFeed = (props: Props) => { | ||
const updateSavedFeedViewer = useStore((state) => state.updateSavedFeedViewer); | ||
const { isPinned, onToggleSave, onTogglePin } = useFeedGenerator(); | ||
|
||
const onDelete = useCallback( | ||
(feed: AppBskyFeedDefs.GeneratorView) => async () => { | ||
onToggleSave(feed, props.preferences); | ||
updateSavedFeedViewer(feed) | ||
}, | ||
[props, onToggleSave, updateSavedFeedViewer] | ||
); | ||
|
||
return ( | ||
<Dialog open={props.open} fullWidth maxWidth="sm" PaperProps={{ sx: { borderRadius: 3 } }} onClose={props.onClose}> | ||
<DialogTitle>Saved Feed</DialogTitle> | ||
<DialogContent> | ||
<List> | ||
{_.map(props.feeds, (feed) => ( | ||
<ListItem | ||
key={feed.uri} | ||
divider | ||
secondaryAction={ | ||
<Stack direction="row" spacing={1}> | ||
<IconButton | ||
size="small" | ||
color="primary" | ||
onClick={(e) => { | ||
e.stopPropagation(); | ||
onTogglePin(feed, props.preferences); | ||
}} | ||
> | ||
{isPinned(feed, props.preferences) ? ( | ||
<PushPinRoundedIcon /> | ||
) : ( | ||
<PushPinRoundedIcon color="disabled" /> | ||
)} | ||
</IconButton> | ||
<IconButton onClick={onDelete(feed)} color="error"> | ||
<DeleteForeverRoundedIcon /> | ||
</IconButton> | ||
</Stack> | ||
} | ||
> | ||
<ListItemAvatar> | ||
<Avatar alt={feed.avatar} src={feed.avatar} variant="rounded" /> | ||
</ListItemAvatar> | ||
<ListItemText primary={feed.displayName} secondary={`by @${feed.creator.handle}`} /> | ||
</ListItem> | ||
))} | ||
</List> | ||
</DialogContent> | ||
<Divider /> | ||
<DialogActions sx={{ display: "flex", alignItems: "center", justifyContent: "center" }}> | ||
<Button sx={{ width: "50%", borderRadius: 5, fontWeight: 600 }} variant="contained" onClick={props.onClose}> | ||
DONE | ||
</Button> | ||
</DialogActions> | ||
</Dialog> | ||
); | ||
}; | ||
|
||
export default DialogFeed; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.