init commit,

This commit is contained in:
louiscklaw
2025-05-28 09:55:51 +08:00
commit efe70ceb69
8042 changed files with 951668 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
import { useEffect, useState } from "react";
import { useAppDispatch, useAppSelector } from "../../store";
import { resolveObject } from "../resolve/resolveSlice";
import Post from "../post/inFeed/Post";
import FeedComment from "../comment/inFeed/FeedComment";
import { styled } from "@linaria/react";
import { InFeedContext } from "../feed/Feed";
import { useDebounceValue } from "usehooks-ts";
import { CenteredSpinner } from "../shared/CenteredSpinner";
const StyledCenteredSpinner = styled(CenteredSpinner)`
margin-top: 60px;
`;
interface AutoResolvePostCommentProps {
url: string;
}
export default function AutoResolvePostComment({
url: userInputUrl,
}: AutoResolvePostCommentProps) {
const dispatch = useAppDispatch();
const [url] = useDebounceValue(userInputUrl, 500);
const object = useAppSelector((state) => state.resolve.objectByUrl[url]);
const [error, setError] = useState(false);
useEffect(() => {
(async () => {
const _url = url;
setError(false);
try {
await dispatch(resolveObject(url));
} catch (error) {
if (_url === url) setError(true);
throw error;
}
if (_url === url) setError(false);
})();
}, [url, dispatch]);
if (object === "couldnt_find_object" || error) return null;
if (!object) return <StyledCenteredSpinner />;
if (object.post)
return (
<InFeedContext.Provider value={true}>
<Post post={object.post} />
</InFeedContext.Provider>
);
if (object.comment)
return (
<InFeedContext.Provider value={true}>
<FeedComment comment={object.comment} />
</InFeedContext.Provider>
);
return null;
}

View File

@@ -0,0 +1,11 @@
import SpecialSearchMenu from "./SpecialSearchMenu";
import TrendingCommunities from "./TrendingCommunities";
export default function EmptySearch() {
return (
<>
<TrendingCommunities />
<SpecialSearchMenu />
</>
);
}

View File

@@ -0,0 +1,76 @@
import { IonIcon, IonItem, IonList } from "@ionic/react";
import { SettingLabel } from "../user/Profile";
import { useBuildGeneralBrowseLink } from "../../helpers/routes";
import {
albumsOutline,
arrowForward,
chatbubbleOutline,
personOutline,
searchOutline,
} from "ionicons/icons";
import useLemmyUrlHandler from "../shared/useLemmyUrlHandler";
import { useMemo } from "react";
import AutoResolvePostComment from "./AutoResolvePostComment";
interface SearchOptionsProps {
search: string;
}
export default function SearchOptions({ search }: SearchOptionsProps) {
const buildGeneralBrowseLink = useBuildGeneralBrowseLink();
const { determineObjectTypeFromUrl, redirectToLemmyObjectIfNeeded } =
useLemmyUrlHandler();
const searchURI = encodeURIComponent(search);
const sanitizedUser = search.replace(/|\/|#|\?|\\/g, "").replace(/^@/, "");
const type = useMemo(
() => determineObjectTypeFromUrl(search),
[determineObjectTypeFromUrl, search],
);
const autoResolveType = type === "post" || type === "comment";
return (
<>
<IonList inset color="primary">
{type && !autoResolveType && (
<IonItem
onClick={(e) => redirectToLemmyObjectIfNeeded(search, e)}
detail
button
>
<IonIcon icon={arrowForward} color="primary" />
<SettingLabel>Visit {type}</SettingLabel>
</IonItem>
)}
<IonItem routerLink={`/search/posts/${searchURI}`}>
<IonIcon icon={albumsOutline} color="primary" />
<SettingLabel className="ion-text-nowrap">
Posts with {search}
</SettingLabel>
</IonItem>
<IonItem routerLink={`/search/comments/${searchURI}`}>
<IonIcon icon={chatbubbleOutline} color="primary" />
<SettingLabel className="ion-text-nowrap">
Comments with {search}
</SettingLabel>
</IonItem>
<IonItem routerLink={`/search/communities/${searchURI}`}>
<IonIcon icon={searchOutline} color="primary" />
<SettingLabel className="ion-text-nowrap">
Communities with {search}
</SettingLabel>
</IonItem>
<IonItem routerLink={buildGeneralBrowseLink(`/u/${sanitizedUser}`)}>
<IonIcon icon={personOutline} color="primary" />
<SettingLabel className="ion-text-nowrap">
Go to User {search}
</SettingLabel>
</IonItem>
</IonList>
{autoResolveType && <AutoResolvePostComment url={search} />}
</>
);
}

View File

@@ -0,0 +1,30 @@
import { IonIcon, IonItem, IonLabel, IonList } from "@ionic/react";
import { planetOutline, shuffle } from "ionicons/icons";
import { useAppSelector } from "../../store";
export default function SpecialSearchMenu() {
const trendingCommunities = useAppSelector(
(state) => state.community.trendingCommunities,
);
const communitiesCount = useAppSelector(
(state) => state.site.response?.site_view.counts.communities,
);
// Prevent shift of content
if (trendingCommunities === undefined) return;
if (!communitiesCount) return;
return (
<IonList inset color="primary">
<IonItem routerLink="/search/random">
<IonIcon icon={shuffle} color="primary" slot="start" />
<IonLabel className="ion-text-nowrap">Random Community</IonLabel>
</IonItem>
<IonItem routerLink="/search/explore">
<IonIcon icon={planetOutline} color="primary" slot="start" />
<IonLabel className="ion-text-nowrap">Explore</IonLabel>
</IonItem>
</IonList>
);
}

View File

@@ -0,0 +1,53 @@
import {
IonIcon,
IonItem,
IonLabel,
IonList,
IonListHeader,
} from "@ionic/react";
import { useBuildGeneralBrowseLink } from "../../helpers/routes";
import { useAppDispatch, useAppSelector } from "../../store";
import { getHandle } from "../../helpers/lemmy";
import { trendingUp } from "ionicons/icons";
import { useEffect } from "react";
import { getTrendingCommunities } from "../community/communitySlice";
import { css } from "@linaria/core";
export default function TrendingCommunities() {
const dispatch = useAppDispatch();
const buildGeneralBrowseLink = useBuildGeneralBrowseLink();
const trendingCommunities = useAppSelector(
(state) => state.community.trendingCommunities,
);
useEffect(() => {
if (trendingCommunities === undefined) dispatch(getTrendingCommunities());
}, [dispatch, trendingCommunities]);
return (
<IonList inset color="primary">
<IonListHeader>
<IonLabel
className={css`
margin-top: 0;
`}
>
Trending communities
</IonLabel>
</IonListHeader>
{trendingCommunities?.map((community) => (
<IonItem
routerLink={buildGeneralBrowseLink(
`/c/${getHandle(community.community)}`,
)}
key={community.community.id}
>
<IonIcon icon={trendingUp} color="primary" slot="start" />
<IonLabel className="ion-text-nowrap">
{getHandle(community.community)}
</IonLabel>
</IonItem>
))}
</IonList>
);
}