Skip to content

Commit

Permalink
chore: minor changes and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasgriffintn committed Aug 25, 2024
1 parent 3ede222 commit 991ac03
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 22 deletions.
82 changes: 64 additions & 18 deletions apps/web/app/components/homepage/search-result-item.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { Fragment } from 'react';

import { Button } from '../ui/button';
import { Modal } from '../modal/base';
import { RenderDate } from '../text/date';

function formatDate(dateString: string): string {
const date = new Date(dateString);
const options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'long',
day: 'numeric',
};
return date.toLocaleDateString(undefined, options);
}
import { Fragment } from 'react';

function stripHtmlTagsAndDecode(html: string): string {
// Strip HTML tags
const text = html.replace(/<\/?[^>]+(>|$)/g, '');
// Replace paragraph tags with new lines
const textWithNewLines = html.replace(/<\/?p[^>]*>/g, '\n');

// Strip remaining HTML tags
const text = textWithNewLines.replace(/<\/?[^>]+(>|$)/g, '');

// Decode HTML entities
return text
const decodedText = text
.replace(/&#(\d+);/g, (match, dec) => {
return String.fromCharCode(dec);
})
Expand All @@ -31,6 +29,49 @@ function stripHtmlTagsAndDecode(html: string): string {
};
return entities[entity] || match;
});

// Remove leading and trailing new lines and ensure no more than one consecutive new line
return decodedText.trim().replace(/\n+/g, '\n');
}

function renderTextWithNewLines(text: string, url: string): JSX.Element {
const urlRegex = /(https?:\/\/[^\s]+)/g;
const continueReadingRegex = /Continue reading\.\.\./g;

return (
<>
{text.split('\n').map((line, index) => (
<Fragment key={index}>
{line
.split(urlRegex)
.map((part, i) =>
urlRegex.test(part) ? (
<a
key={i}
href={part}
target="_blank"
rel="noopener noreferrer"
>
{part}
</a>
) : (
part
)
)
.map((part, i) =>
continueReadingRegex.test(part as string) ? (
<a key={i} href={url} target="_blank" rel="noopener noreferrer">
Continue reading...
</a>
) : (
part
)
)}
<br />
</Fragment>
))}
</>
);
}

export const SearchResultItem = ({
Expand All @@ -55,16 +96,16 @@ export const SearchResultItem = ({
</span>
)}
<img
src="https://via.placeholder.com/150"
alt="Placeholder"
src="/assets/placeholders/150x150.png"
alt=""
className="w-full h-16 object-cover rounded-t-lg"
/>
<div className="p-4">
<a
href={result.metadata.url}
target="_blank"
rel="noopener noreferrer"
className="text-lg font-bold"
className="text-lg font-bold title"
>
{result.metadata.title}
</a>
Expand All @@ -76,18 +117,23 @@ export const SearchResultItem = ({
)}
{result.metadata.published && (
<span className="text-xs text-muted-foreground">
Published: {formatDate(result.metadata.published)}
Published:{' '}
<RenderDate date={result.metadata.published} timeZone="UTC" />
</span>
)}
{result.metadata.updated && (
<span className="text-xs text-muted-foreground">
Updated: {formatDate(result.metadata.updated)}
Updated:{' '}
<RenderDate date={result.metadata.updated} timeZone="UTC" />
</span>
)}
</div>
{result.metadata.description && (
<p className="text-sm text-muted-foreground">
{stripHtmlTagsAndDecode(result.metadata.description)}
{renderTextWithNewLines(
stripHtmlTagsAndDecode(result.metadata.description),
result.metadata.url
)}
</p>
)}
<div className="flex flex-wrap justify-center gap-2 mt-4">
Expand Down
29 changes: 29 additions & 0 deletions apps/web/app/components/providers/locale.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createContext, ReactNode, useContext } from 'react';

type LocaleContext = {
locales: string[];
};

type LocaleContextProviderProps = {
locales: string[];
children: ReactNode;
};

const Context = createContext<LocaleContext | null>(null);

export const LocaleContextProvider = ({
locales,
children,
}: LocaleContextProviderProps) => {
const value = { locales };
return <Context.Provider value={value}>{children}</Context.Provider>;
};

const throwIfNoProvider = () => {
throw new Error('Please wrap your application in a LocaleContextProvider.');
};

export const useLocales = () => {
const { locales } = useContext(Context) ?? throwIfNoProvider();
return locales;
};
21 changes: 21 additions & 0 deletions apps/web/app/components/text/date.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useLocales } from '../providers/locale';

type IntlDateProps = {
date: string;
timeZone?: string;
};

export const RenderDate = ({ date, timeZone }: IntlDateProps) => {
const dateFromString = new Date(date);

const locales = useLocales();
const isoString = dateFromString.toISOString();
const formattedDate = new Intl.DateTimeFormat(locales, {
year: 'numeric',
month: 'short',
day: 'numeric',
timeZone,
}).format(dateFromString);

return <time dateTime={isoString}>{formattedDate}</time>;
};
10 changes: 8 additions & 2 deletions apps/web/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { RemixBrowser } from '@remix-run/react';
import { startTransition, StrictMode, useEffect } from 'react';
import { startTransition, StrictMode } from 'react';
import { hydrateRoot } from 'react-dom/client';

import { LocaleContextProvider } from './components/providers/locale';

const locales = window.navigator.languages;

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
<LocaleContextProvider locales={locales}>
<RemixBrowser />
</LocaleContextProvider>
</StrictMode>
);
});
12 changes: 11 additions & 1 deletion apps/web/app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@ import type { EntryContext } from '@remix-run/cloudflare';
import { RemixServer } from '@remix-run/react';
import { isbot } from 'isbot';
import { renderToReadableStream } from 'react-dom/server';
import { parseAcceptLanguage } from 'intl-parse-accept-language';

import { LocaleContextProvider } from './components/providers/locale';

export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const acceptLanguage = request.headers.get('accept-language');
const locales = parseAcceptLanguage(acceptLanguage, {
validate: Intl.DateTimeFormat.supportedLocalesOf,
});

const body = await renderToReadableStream(
<RemixServer context={remixContext} url={request.url} />,
<LocaleContextProvider locales={locales}>
<RemixServer context={remixContext} url={request.url} />
</LocaleContextProvider>,
{
signal: request.signal,
onError(error: unknown) {
Expand Down
23 changes: 23 additions & 0 deletions apps/web/app/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
a:not(.title) {
font-weight: 700;
-webkit-text-decoration: underline;
text-decoration: underline;
text-decoration-color: #207DE9;
text-decoration-thickness: 1px;
text-decoration-skip-ink: none;
text-underline-offset: 0.25em;
}

a:not(.title):hover {
text-decoration-color: currentcolor;
text-decoration-thickness: 2px;
color: #207DE9;
}

a.title:hover {
text-decoration-color: currentcolor;
text-decoration-thickness: 2px;
color: #207DE9;
-webkit-text-decoration: underline;
text-decoration: underline;
}
2 changes: 2 additions & 0 deletions apps/web/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
ScrollRestoration,
useRouteError,
} from '@remix-run/react';

import './tailwind.css';
import './global.css';

export function Layout({ children }: { children: React.ReactNode }) {
return (
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export default function Index() {
<div className="w-full max-w-3xl py-4 px-4 sm:px-6 lg:px-8 m-auto items-center text-center">
<div
className={`transition-all duration-500 ease-in-out ${
hasSearched ? 'mt-8' : 'mt-[15vh]'
hasSearched ? 'mt-8' : 'mt-[5vh] lg:mt-[15vh]'
}`}
>
{isIntroVisible && <IntroSection hasSearched={hasSearched} />}
Expand Down
1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@remix-run/react": "^2.11.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"intl-parse-accept-language": "^1.0.0",
"isbot": "^5.1.17",
"lucide-react": "^0.435.0",
"react": "^18.3.1",
Expand Down
Binary file added apps/web/public/assets/placeholders/150x150.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 991ac03

Please sign in to comment.