commit
c82fcd63ae
@ -2,22 +2,27 @@ import "./Avatar.css";
|
||||
import Nostrich from "../nostrich.jpg";
|
||||
import { CSSProperties } from "react";
|
||||
import type { UserMetadata } from "Nostr";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "State/Store";
|
||||
import { ApiHost } from "Const";
|
||||
|
||||
const Avatar = ({ user, ...rest }: { user?: UserMetadata, onClick?: () => void }) => {
|
||||
const useImageProxy = useSelector((s: RootState) => s.login.preferences.useImageProxy);
|
||||
|
||||
const Avatar = ({ user, ...rest }: { user?: UserMetadata, onClick?: () => void}) => {
|
||||
const avatarUrl = (user?.picture?.length ?? 0) === 0 ? Nostrich : user?.picture
|
||||
const backgroundImage = `url(${avatarUrl})`
|
||||
const domain = user?.nip05 && user.nip05.split('@')[1]
|
||||
const style = { '--img-url': backgroundImage } as CSSProperties
|
||||
return (
|
||||
<div
|
||||
{...rest}
|
||||
style={style}
|
||||
className="avatar"
|
||||
data-domain={domain?.toLowerCase()}
|
||||
>
|
||||
</div>
|
||||
)
|
||||
const avatarUrl = (user?.picture?.length ?? 0) === 0 ? Nostrich :
|
||||
(useImageProxy ? `${ApiHost}/api/v1/imgproxy/${window.btoa(user!.picture!)}` : user?.picture)
|
||||
const backgroundImage = `url(${avatarUrl})`
|
||||
const domain = user?.nip05 && user.nip05.split('@')[1]
|
||||
const style = { '--img-url': backgroundImage } as CSSProperties
|
||||
return (
|
||||
<div
|
||||
{...rest}
|
||||
style={style}
|
||||
className="avatar"
|
||||
data-domain={domain?.toLowerCase()}
|
||||
>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Avatar
|
||||
|
@ -39,7 +39,7 @@ export default function NoteReaction(props: NoteReactionProps) {
|
||||
* Some clients embed the reposted note in the content
|
||||
*/
|
||||
function extractRoot() {
|
||||
if (ev?.Kind === EventKind.Repost && ev.Content.length > 0) {
|
||||
if (ev?.Kind === EventKind.Repost && ev.Content.length > 0 && ev.Content !== "#[0]") {
|
||||
try {
|
||||
let r: RawEvent = JSON.parse(ev.Content);
|
||||
return r as TaggedRawEvent;
|
||||
|
@ -71,6 +71,15 @@ const PreferencesPage = () => {
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card flex">
|
||||
<div className="flex f-col f-grow">
|
||||
<div>Image proxy</div>
|
||||
<small>Use the caching image proxy to load avatars</small>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" checked={perf.useImageProxy} onChange={e => dispatch(setPreferences({ ...perf, useImageProxy: e.target.checked }))} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card flex">
|
||||
<div className="flex f-col f-grow">
|
||||
<div>Debug Menus</div>
|
||||
|
@ -13,10 +13,10 @@ const RelayListKey = "last-relays";
|
||||
const FollowList = "last-follows";
|
||||
|
||||
export interface NotificationRequest {
|
||||
title: string
|
||||
body: string
|
||||
icon: string
|
||||
timestamp: number
|
||||
title: string
|
||||
body: string
|
||||
icon: string
|
||||
timestamp: number
|
||||
}
|
||||
|
||||
export interface UserPreferences {
|
||||
@ -50,10 +50,15 @@ export interface UserPreferences {
|
||||
*/
|
||||
showDebugMenus: boolean,
|
||||
|
||||
/**
|
||||
* File uploading service to upload attachments to
|
||||
*/
|
||||
fileUploader: "void.cat" | "nostr.build"
|
||||
/**
|
||||
* File uploading service to upload attachments to
|
||||
*/
|
||||
fileUploader: "void.cat" | "nostr.build",
|
||||
|
||||
/**
|
||||
* Use image proxy service to compress avatars
|
||||
*/
|
||||
useImageProxy: boolean,
|
||||
}
|
||||
|
||||
export interface LoginStore {
|
||||
@ -155,7 +160,8 @@ const InitState = {
|
||||
confirmReposts: false,
|
||||
showDebugMenus: false,
|
||||
autoShowLatest: false,
|
||||
fileUploader: "void.cat"
|
||||
fileUploader: "void.cat",
|
||||
useImageProxy: true
|
||||
}
|
||||
} as LoginStore;
|
||||
|
||||
@ -279,21 +285,21 @@ const LoginSlice = createSlice({
|
||||
|
||||
window.localStorage.setItem(FollowList, JSON.stringify(state.follows));
|
||||
},
|
||||
setMuted(state, action: PayloadAction<{createdAt: number, keys: HexKey[]}>) {
|
||||
const { createdAt, keys } = action.payload
|
||||
if (createdAt >= state.latestMuted) {
|
||||
const muted = new Set([...keys])
|
||||
state.muted = Array.from(muted)
|
||||
state.latestMuted = createdAt
|
||||
}
|
||||
setMuted(state, action: PayloadAction<{ createdAt: number, keys: HexKey[] }>) {
|
||||
const { createdAt, keys } = action.payload
|
||||
if (createdAt >= state.latestMuted) {
|
||||
const muted = new Set([...keys])
|
||||
state.muted = Array.from(muted)
|
||||
state.latestMuted = createdAt
|
||||
}
|
||||
},
|
||||
setBlocked(state, action: PayloadAction<{createdAt: number, keys: HexKey[]}>) {
|
||||
const { createdAt, keys } = action.payload
|
||||
if (createdAt >= state.latestMuted) {
|
||||
const blocked = new Set([...keys])
|
||||
state.blocked = Array.from(blocked)
|
||||
state.latestMuted = createdAt
|
||||
}
|
||||
setBlocked(state, action: PayloadAction<{ createdAt: number, keys: HexKey[] }>) {
|
||||
const { createdAt, keys } = action.payload
|
||||
if (createdAt >= state.latestMuted) {
|
||||
const blocked = new Set([...keys])
|
||||
state.blocked = Array.from(blocked)
|
||||
state.latestMuted = createdAt
|
||||
}
|
||||
},
|
||||
addDirectMessage: (state, action: PayloadAction<TaggedRawEvent | Array<TaggedRawEvent>>) => {
|
||||
let n = action.payload;
|
||||
@ -352,26 +358,26 @@ export const {
|
||||
} = LoginSlice.actions;
|
||||
|
||||
export function sendNotification({ title, body, icon, timestamp }: NotificationRequest) {
|
||||
return async (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState()
|
||||
const { readNotifications } = state.login
|
||||
const hasPermission = "Notification" in window && Notification.permission === "granted"
|
||||
const shouldShowNotification = hasPermission && timestamp > readNotifications
|
||||
if (shouldShowNotification) {
|
||||
try {
|
||||
let worker = await navigator.serviceWorker.ready;
|
||||
worker.showNotification(title, {
|
||||
tag: "notification",
|
||||
vibrate: [500],
|
||||
body,
|
||||
icon,
|
||||
timestamp,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
}
|
||||
return async (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState()
|
||||
const { readNotifications } = state.login
|
||||
const hasPermission = "Notification" in window && Notification.permission === "granted"
|
||||
const shouldShowNotification = hasPermission && timestamp > readNotifications
|
||||
if (shouldShowNotification) {
|
||||
try {
|
||||
let worker = await navigator.serviceWorker.ready;
|
||||
worker.showNotification(title, {
|
||||
tag: "notification",
|
||||
vibrate: [500],
|
||||
body,
|
||||
icon,
|
||||
timestamp,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const reducer = LoginSlice.reducer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user