Merge branch 'main' into static

This commit is contained in:
Sam Becker 2024-02-28 00:05:57 -06:00
commit 788708e0aa
12 changed files with 60 additions and 30 deletions

View File

@ -15,7 +15,11 @@ interface Props {
params: { tag: string }
}
export default async function PhotoPageEdit({ params: { tag } }: Props) {
export default async function PhotoPageEdit({
params: { tag: tagFromParams } }: Props
) {
const tag = decodeURIComponent(tagFromParams);
const [
count,
photos,

View File

@ -6,15 +6,17 @@ import {
getPhotosTagDataCached,
getPhotosTagDataCachedWithPagination,
} from '@/tag/data';
import { Metadata } from 'next/types';
import type { Metadata } from 'next';
interface TagProps {
params: { tag: string }
}
export async function generateMetadata({
params: { tag },
params: { tag: tagFromParams },
}: TagProps): Promise<Metadata> {
const tag = decodeURIComponent(tagFromParams);
const [
photos,
count,
@ -49,9 +51,11 @@ export async function generateMetadata({
}
export default async function TagPage({
params: { tag },
params: { tag: tagFromParams },
searchParams,
}:TagProps & PaginationParams) {
const tag = decodeURIComponent(tagFromParams);
const {
photos,
count,

View File

@ -7,15 +7,17 @@ import {
getPhotosTagDataCached,
getPhotosTagDataCachedWithPagination,
} from '@/tag/data';
import { Metadata } from 'next/types';
import type { Metadata } from 'next';
interface TagProps {
params: { tag: string }
}
export async function generateMetadata({
params: { tag },
params: { tag: tagFromParams },
}: TagProps): Promise<Metadata> {
const tag = decodeURIComponent(tagFromParams);
const [
photos,
count,
@ -50,9 +52,11 @@ export async function generateMetadata({
}
export default async function Share({
params: { tag },
params: { tag: tagFromParams },
searchParams,
}: TagProps & PaginationParams) {
const tag = decodeURIComponent(tagFromParams);
const {
photos,
count,

View File

@ -16,7 +16,7 @@ export default function CameraOverview({
camera: Camera,
photos: Photo[],
count: number,
dateRange: PhotoDateRange,
dateRange?: PhotoDateRange,
showMorePath?: string,
animateOnFirstLoadOnly?: boolean,
}) {

View File

@ -13,7 +13,7 @@ export default function CameraShareModal({
camera: Camera
photos: Photo[]
count: number
dateRange: PhotoDateRange,
dateRange?: PhotoDateRange,
}) {
return (
<ShareModal

View File

@ -17,7 +17,7 @@ export type CameraWithCount = {
export type Cameras = CameraWithCount[];
export const createCameraKey = ({ make, model }: Camera) =>
parameterize(`${make}-${model}`);
parameterize(`${make}-${model}`, true);
// Assumes no makes ('Fujifilm,' 'Apple,' 'Canon', etc.) have dashes
export const getCameraFromKey = (cameraKey: string): Camera => {

View File

@ -72,11 +72,11 @@ export default function TagInput({
onChange?.([
...selectedOptions,
option.startsWith(CREATE_LABEL)
? option.slice(CREATE_LABEL.length, -1)
? option.match(new RegExp(`^${CREATE_LABEL} "(.+)"$`))?.[1] ?? option
: option,
]
.filter(Boolean)
.map(parameterize)
.map(item => parameterize(item))
.join(','));
}
setSelectedOptionIndex(undefined);

View File

@ -22,6 +22,7 @@ import {
revalidateAdminPaths,
revalidateAllKeysAndPaths,
revalidatePhotosKey,
revalidateTagsKey,
} from '@/photo/cache';
import { PATH_ADMIN_PHOTOS, PATH_ADMIN_TAGS, PATH_ROOT } from '@/site/paths';
import { extractExifDataFromBlobPath } from './server';
@ -105,6 +106,7 @@ export async function renamePhotoTagGloballyAction(formData: FormData) {
if (tag && updatedTag && tag !== updatedTag) {
await sqlRenamePhotoTagGlobally(tag, updatedTag);
revalidatePhotosKey();
revalidateTagsKey();
redirect(PATH_ADMIN_TAGS);
}
}

View File

@ -174,8 +174,8 @@ const sqlGetPhotosTagCount = async (tag: string) => sql`
const sqlGetPhotosCameraCount = async (camera: Camera) => sql`
SELECT COUNT(*) FROM photos
WHERE
LOWER(make)=${parameterize(camera.make)} AND
LOWER(REPLACE(model, ' ', '-'))=${parameterize(camera.model)} AND
LOWER(make)=${parameterize(camera.make, true)} AND
LOWER(REPLACE(model, ' ', '-'))=${parameterize(camera.model, true)} AND
hidden IS NOT TRUE
`.then(({ rows }) => parseInt(rows[0].count, 10));
@ -191,23 +191,29 @@ const sqlGetPhotosDateRange = async () => sql`
SELECT MIN(taken_at_naive) as start, MAX(taken_at_naive) as end
FROM photos
WHERE hidden IS NOT TRUE
`.then(({ rows }) => rows[0] as PhotoDateRange);
`.then(({ rows }) => rows[0]?.start && rows[0]?.end
? rows[0] as PhotoDateRange
: undefined);
const sqlGetPhotosTagDateRange = async (tag: string) => sql`
SELECT MIN(taken_at_naive) as start, MAX(taken_at_naive) as end
FROM photos
WHERE ${tag}=ANY(tags) AND
hidden IS NOT TRUE
`.then(({ rows }) => rows[0] as PhotoDateRange);
`.then(({ rows }) => rows[0]?.start && rows[0]?.end
? rows[0] as PhotoDateRange
: undefined);
const sqlGetPhotosCameraDateRange = async (camera: Camera) => sql`
SELECT MIN(taken_at_naive) as start, MAX(taken_at_naive) as end
FROM photos
WHERE
LOWER(make)=${parameterize(camera.make)} AND
LOWER(REPLACE(model, ' ', '-'))=${parameterize(camera.model)} AND
LOWER(make)=${parameterize(camera.make, true)} AND
LOWER(REPLACE(model, ' ', '-'))=${parameterize(camera.model, true)} AND
hidden IS NOT TRUE
`.then(({ rows }) => rows[0] as PhotoDateRange);
`.then(({ rows }) => rows[0]?.start && rows[0]?.end
? rows[0] as PhotoDateRange
: undefined);
const sqlGetPhotosFilmSimulationDateRange = async (
simulation: FilmSimulation,
@ -216,7 +222,9 @@ const sqlGetPhotosFilmSimulationDateRange = async (
FROM photos
WHERE film_simulation=${simulation} AND
hidden IS NOT TRUE
`.then(({ rows }) => rows[0] as PhotoDateRange);
`.then(({ rows }) => rows[0]?.start && rows[0]?.end
? rows[0] as PhotoDateRange
: undefined);
const sqlGetUniqueTags = async () => sql`
SELECT DISTINCT unnest(tags) as tag, COUNT(*)
@ -349,8 +357,8 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
if (camera) {
wheres.push(`LOWER(make)=$${valueIndex++}`);
wheres.push(`LOWER(REPLACE(model, ' ', '-'))=$${valueIndex++}`);
values.push(parameterize(camera.make));
values.push(parameterize(camera.model));
values.push(parameterize(camera.make, true));
values.push(parameterize(camera.model, true));
}
if (simulation) {
wheres.push(`film_simulation=$${valueIndex++}`);

View File

@ -16,7 +16,7 @@ export default function FilmSimulationOverview({
simulation: FilmSimulation,
photos: Photo[],
count: number,
dateRange: PhotoDateRange,
dateRange?: PhotoDateRange,
showMorePath?: string,
animateOnFirstLoadOnly?: boolean,
}) {

View File

@ -15,7 +15,7 @@ export default function TagOverview({
tag: string,
photos: Photo[],
count: number,
dateRange: PhotoDateRange,
dateRange?: PhotoDateRange,
showMorePath?: string,
animateOnFirstLoadOnly?: boolean,
}) {

View File

@ -2,9 +2,9 @@ export const convertStringToArray = (
string?: string,
shouldParameterize = true,
) => string
? string.split(',').map(tag => shouldParameterize
? parameterize(tag)
: tag.trim())
? string.split(',').map(item => shouldParameterize
? parameterize(item)
: item.trim())
: undefined;
export const capitalize = (string: string) =>
@ -16,14 +16,22 @@ export const capitalizeWords = (string = '') =>
.map(capitalize)
.join(' ');
export const parameterize = (string: string) =>
export const parameterize = (
string: string,
shouldRemoveNonAlphanumeric?: boolean,
) =>
string
.trim()
// Replaces spaces, underscores, and dashes with dashes
.replaceAll(/[\s_—]/gi, '-')
// Removes all non-alphanumeric characters
.replaceAll(/([^a-z0-9-])/gi, '')
.toLowerCase();
.replaceAll(
shouldRemoveNonAlphanumeric
? /([^a-z0-9-])/gi
: /''/gi,
'',
)
.toLocaleLowerCase();
export const formatCount = (count: number) => `× ${count}`;