mirror of
https://github.com/uetchy/namae.git
synced 2025-03-16 20:20:38 +09:00
feat: new card "Product Hunt"
This commit is contained in:
parent
2e7de6072a
commit
eaa0442842
@ -50,7 +50,8 @@
|
|||||||
"firefoxAddons": "Firefox Add-ons",
|
"firefoxAddons": "Firefox Add-ons",
|
||||||
"youtube": "YouTube",
|
"youtube": "YouTube",
|
||||||
"hexpm": "Hex",
|
"hexpm": "Hex",
|
||||||
"fly": "Fly.io"
|
"fly": "Fly.io",
|
||||||
|
"productHunt": "Product Hunt"
|
||||||
},
|
},
|
||||||
"showMore": "show more",
|
"showMore": "show more",
|
||||||
"try": "How about this?",
|
"try": "How about this?",
|
||||||
|
@ -33,6 +33,7 @@ import TwitterCard from './providers/Twitter';
|
|||||||
import VercelCard from './providers/Vercel';
|
import VercelCard from './providers/Vercel';
|
||||||
import YouTubeCard from './providers/YouTube';
|
import YouTubeCard from './providers/YouTube';
|
||||||
import FlyIoCard from './providers/FlyIo';
|
import FlyIoCard from './providers/FlyIo';
|
||||||
|
import ProductHuntCard from './providers/ProductHunt';
|
||||||
|
|
||||||
const Index: React.FC<{ query: string }> = ({ query }) => {
|
const Index: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const {
|
const {
|
||||||
@ -69,6 +70,7 @@ const Index: React.FC<{ query: string }> = ({ query }) => {
|
|||||||
<FirebaseCard query={query} />
|
<FirebaseCard query={query} />
|
||||||
</Cards>
|
</Cards>
|
||||||
<Cards>
|
<Cards>
|
||||||
|
<ProductHuntCard query={query} />
|
||||||
<GithubSearchCard query={query} />
|
<GithubSearchCard query={query} />
|
||||||
<AppStoreCard query={query} />
|
<AppStoreCard query={query} />
|
||||||
<PlayStoreCard query={query} />
|
<PlayStoreCard query={query} />
|
||||||
|
192
src/components/cards/providers/ProductHunt.tsx
Normal file
192
src/components/cards/providers/ProductHunt.tsx
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import useFetch from 'fetch-suspense';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaProductHunt } from 'react-icons/fa';
|
||||||
|
import { Card, Result } from '../core';
|
||||||
|
|
||||||
|
const Search: React.FC<{ query: string }> = ({ query }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const response = useFetch(
|
||||||
|
`https://0h4smabbsg-dsn.algolia.net/1/indexes/Post_production?query=${encodeURIComponent(
|
||||||
|
query
|
||||||
|
)}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'X-Algolia-API-Key': '9670d2d619b9d07859448d7628eea5f3',
|
||||||
|
'X-Algolia-Application-Id': '0H4SMABBSG',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
) as Response;
|
||||||
|
|
||||||
|
const hits = response.hits;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{hits.length > 0 ? (
|
||||||
|
hits
|
||||||
|
.slice(0, 10)
|
||||||
|
.map((hit) => (
|
||||||
|
<Result
|
||||||
|
title={hit.name}
|
||||||
|
message={`${hit.tagline} (⬆️ ${hit.vote_count})`}
|
||||||
|
link={hit.url}
|
||||||
|
icon={<FaProductHunt />}
|
||||||
|
key={hit.id}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Result
|
||||||
|
title={t('noResult')}
|
||||||
|
message={t('noResult')}
|
||||||
|
icon={<FaProductHunt />}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProductHuntCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card title={t('providers.productHunt')}>
|
||||||
|
<Search query={query} />
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductHuntCard;
|
||||||
|
|
||||||
|
interface Response {
|
||||||
|
hits: Hit[];
|
||||||
|
nbHits: number;
|
||||||
|
page: number;
|
||||||
|
nbPages: number;
|
||||||
|
hitsPerPage: number;
|
||||||
|
exhaustiveNbHits: boolean;
|
||||||
|
exhaustiveTypo: boolean;
|
||||||
|
query: Query;
|
||||||
|
params: string;
|
||||||
|
processingTimeMS: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Hit {
|
||||||
|
comments_count: number;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
tagline: string;
|
||||||
|
topics: Topic[];
|
||||||
|
id: number;
|
||||||
|
user_id: number;
|
||||||
|
thumbnail_image_uuid?: string;
|
||||||
|
created_at: string;
|
||||||
|
featured_at: null | string;
|
||||||
|
exclusive: null;
|
||||||
|
is_featured: boolean;
|
||||||
|
media: Media[];
|
||||||
|
posted_date: number;
|
||||||
|
product_links: ProductLink[];
|
||||||
|
product_state: ProductState;
|
||||||
|
shortened_url: string;
|
||||||
|
text_content: any[];
|
||||||
|
url: string;
|
||||||
|
user: User;
|
||||||
|
vote_count: number;
|
||||||
|
objectID: string;
|
||||||
|
_highlightResult: HighlightResult;
|
||||||
|
thumbnail?: Thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HighlightResult {
|
||||||
|
name: Name;
|
||||||
|
tagline: Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Name {
|
||||||
|
value: string;
|
||||||
|
matchLevel: MatchLevel;
|
||||||
|
fullyHighlighted?: boolean;
|
||||||
|
matchedWords: Query[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum MatchLevel {
|
||||||
|
Full = 'full',
|
||||||
|
None = 'none',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Query {
|
||||||
|
Namae = 'namae',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Media {
|
||||||
|
id: number;
|
||||||
|
metadata: MediaMetadata;
|
||||||
|
original_height: number;
|
||||||
|
original_width: number;
|
||||||
|
image_url: string;
|
||||||
|
image_uuid: string;
|
||||||
|
media_type: MediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum MediaType {
|
||||||
|
Image = 'image',
|
||||||
|
Video = 'video',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MediaMetadata {
|
||||||
|
video_id?: null | string;
|
||||||
|
url?: null | string;
|
||||||
|
kindle_asin?: null;
|
||||||
|
platform?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProductLink {
|
||||||
|
store_name: StoreName;
|
||||||
|
id: number;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StoreName {
|
||||||
|
AppStore = 'App Store',
|
||||||
|
Chrome = 'Chrome',
|
||||||
|
PlayStore = 'Play Store',
|
||||||
|
Website = 'Website',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ProductState {
|
||||||
|
Default = 'default',
|
||||||
|
NoLongerOnline = 'no_longer_online',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Thumbnail {
|
||||||
|
image_uuid: string;
|
||||||
|
media_type: MediaType;
|
||||||
|
metadata: ThumbnailMetadata;
|
||||||
|
original_height: number;
|
||||||
|
id: number;
|
||||||
|
original_width: number;
|
||||||
|
image_url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ThumbnailMetadata {}
|
||||||
|
|
||||||
|
interface Topic {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
slug: string;
|
||||||
|
followers_count: number;
|
||||||
|
image_uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface User {
|
||||||
|
username: string;
|
||||||
|
id: number;
|
||||||
|
twitter_username: null | string;
|
||||||
|
name: string;
|
||||||
|
headline: null | string;
|
||||||
|
image_urls: { [key: string]: string };
|
||||||
|
link: string;
|
||||||
|
avatar_url: string;
|
||||||
|
is_maker: boolean;
|
||||||
|
}
|
@ -5,7 +5,7 @@ import XHR from 'i18next-xhr-backend';
|
|||||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||||
import { initReactI18next } from 'react-i18next';
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
|
||||||
const TRANSLATION_VERSION = '17';
|
const TRANSLATION_VERSION = '18';
|
||||||
|
|
||||||
i18n
|
i18n
|
||||||
.use(Backend)
|
.use(Backend)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user