Refine camera/lens query handling
This commit is contained in:
parent
0ca8823dae
commit
3966a6437a
10
__tests__/lens.test.ts
Normal file
10
__tests__/lens.test.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/* eslint-disable max-len */
|
||||
import { formatLensText, Lens } from '@/lens';
|
||||
|
||||
const IPHONE_15_PRO_FRONT: Lens = { make: 'Apple', model: 'iPhone 15 Pro front TrueDepth camera 2.69mm f/1.9' };
|
||||
|
||||
describe('Lens', () => {
|
||||
it('correctly formats iPhone lenses', () => {
|
||||
expect(formatLensText(IPHONE_15_PRO_FRONT)).toBe('Front Camera');
|
||||
});
|
||||
});
|
||||
@ -7,7 +7,6 @@ import PhotoSmall from '@/photo/PhotoSmall';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { pathForAdminPhotoEdit, pathForPhoto } from '@/app/paths';
|
||||
import Link from 'next/link';
|
||||
import { AiOutlineEyeInvisible } from 'react-icons/ai';
|
||||
import PhotoDate from '@/photo/PhotoDate';
|
||||
import EditButton from './EditButton';
|
||||
import { useAppState } from '@/state/AppState';
|
||||
@ -15,6 +14,7 @@ import { RevalidatePhoto } from '@/photo/InfinitePhotoScroll';
|
||||
import PhotoSyncButton from './PhotoSyncButton';
|
||||
import DeletePhotoButton from './DeletePhotoButton';
|
||||
import { Timezone } from '@/utility/timezone';
|
||||
import IconHidden from '@/components/icons/IconHidden';
|
||||
|
||||
export default function AdminPhotosTable({
|
||||
photos,
|
||||
@ -71,7 +71,7 @@ export default function AdminPhotosTable({
|
||||
{titleForPhoto(photo)}
|
||||
{photo.hidden && <span className="whitespace-nowrap">
|
||||
{' '}
|
||||
<AiOutlineEyeInvisible
|
||||
<IconHidden
|
||||
className="inline translate-y-[-0.5px]"
|
||||
size={16}
|
||||
/>
|
||||
|
||||
@ -140,13 +140,13 @@ export const pathForTag = (tag: string) =>
|
||||
`${PREFIX_TAG}/${tag}`;
|
||||
|
||||
export const pathForCamera = ({ make, model }: Camera) =>
|
||||
`${PREFIX_CAMERA}/${parameterize(make, true)}/${parameterize(model, true)}`;
|
||||
`${PREFIX_CAMERA}/${parameterize(make)}/${parameterize(model)}`;
|
||||
|
||||
export const pathForFilmSimulation = (simulation: FilmSimulation) =>
|
||||
`${PREFIX_FILM_SIMULATION}/${simulation}`;
|
||||
|
||||
export const pathForLens = ({ make, model }: Lens) =>
|
||||
`${PREFIX_LENS}/${parameterize(make, true)}/${parameterize(model, true)}`;
|
||||
`${PREFIX_LENS}/${parameterize(make)}/${parameterize(model)}`;
|
||||
|
||||
export const pathForFocalLength = (focal: number) =>
|
||||
`${PREFIX_FOCAL_LENGTH}/${focal}mm`;
|
||||
|
||||
@ -28,7 +28,7 @@ export type Cameras = CameraWithCount[];
|
||||
|
||||
// Support keys for make-only and model-only camera queries
|
||||
export const createCameraKey = ({ make, model }: Partial<Camera>) =>
|
||||
parameterize(`${make ?? 'ANY'}-${model ?? 'ANY'}`, true);
|
||||
parameterize(`${make ?? 'ANY'}-${model ?? 'ANY'}`);
|
||||
|
||||
export const getCameraFromParams = ({
|
||||
make,
|
||||
@ -37,8 +37,8 @@ export const getCameraFromParams = ({
|
||||
make: string,
|
||||
model: string,
|
||||
}): Camera => ({
|
||||
make: parameterize(make, true),
|
||||
model: parameterize(model, true),
|
||||
make: parameterize(make),
|
||||
model: parameterize(model),
|
||||
});
|
||||
|
||||
export const sortCamerasWithCount = (
|
||||
|
||||
@ -28,7 +28,7 @@ export type Lenses = LensWithCount[];
|
||||
|
||||
// Support keys for make-only and model-only lens queries
|
||||
export const createLensKey = ({ make, model }: Partial<Lens>) =>
|
||||
parameterize(`${make ?? 'ANY'}-${model ?? 'ANY'}`, true);
|
||||
parameterize(`${make ?? 'ANY'}-${model ?? 'ANY'}`);
|
||||
|
||||
export const getLensFromParams = ({
|
||||
make,
|
||||
@ -37,8 +37,8 @@ export const getLensFromParams = ({
|
||||
make: string,
|
||||
model: string,
|
||||
}): Lens => ({
|
||||
make: parameterize(make, true),
|
||||
model: parameterize(model, true),
|
||||
make: parameterize(make),
|
||||
model: parameterize(model),
|
||||
});
|
||||
|
||||
export const lensFromPhoto = (
|
||||
@ -55,13 +55,20 @@ const isLensMakeApple = (make?: string) =>
|
||||
export const isLensApple = ({ make }: Lens) =>
|
||||
isLensMakeApple(make);
|
||||
|
||||
const formatAppleLensText = (model: string) => {
|
||||
if (model.includes('front TrueDepth camera')) {
|
||||
return 'Front Camera';
|
||||
}
|
||||
return model;
|
||||
};
|
||||
|
||||
export const formatLensText = (
|
||||
{ make, model: modelRaw }: Lens,
|
||||
length:
|
||||
'long' | // Unmodified make and model
|
||||
'medium' | // Make and model, with modifiers removed
|
||||
'short' // Model only
|
||||
= 'medium',
|
||||
= 'short',
|
||||
) => {
|
||||
// Capture simple make without modifiers like 'Corporation' or 'Company'
|
||||
const makeSimple = make.match(/^(\S+)/)?.[1];
|
||||
@ -69,7 +76,11 @@ export const formatLensText = (
|
||||
makeSimple &&
|
||||
modelRaw.toLocaleLowerCase().startsWith(makeSimple.toLocaleLowerCase())
|
||||
);
|
||||
const model = modelRaw;
|
||||
|
||||
const model = isLensMakeApple(make)
|
||||
? formatAppleLensText(modelRaw)
|
||||
: modelRaw;
|
||||
|
||||
switch (length) {
|
||||
case 'long':
|
||||
case 'medium':
|
||||
|
||||
@ -9,10 +9,11 @@ export const PHOTO_DEFAULT_LIMIT = 100;
|
||||
|
||||
// Trim whitespace
|
||||
// Make lowercase
|
||||
// Replace spaces with dashes
|
||||
// Remove periods and commas
|
||||
const parameterizeForDb = (text: string) =>
|
||||
`REPLACE(REPLACE(REPLACE(LOWER(TRIM(${text})), '.', ''), ',', ''), ' ', '-')`;
|
||||
// Remove commas
|
||||
// Replace spaces, slashes with dashes
|
||||
const parameterizeForDb = (field: string) =>
|
||||
// eslint-disable-next-line max-len
|
||||
`REPLACE(REPLACE(REPLACE(LOWER(TRIM(${field})), ',', ''), '/', '-'), ' ', '-')`;
|
||||
|
||||
export type GetPhotosOptions = {
|
||||
sortBy?: 'createdAt' | 'createdAtAsc' | 'takenAt' | 'priority'
|
||||
@ -64,6 +65,19 @@ export const getWheresFromOptions = (
|
||||
break;
|
||||
}
|
||||
|
||||
if (options.lens?.make) {
|
||||
console.log('LENS MODEL QUERY',{
|
||||
db: parameterizeForDb('lens_make'),
|
||||
args: parameterize(options.lens.make),
|
||||
});
|
||||
}
|
||||
if (options.lens?.model) {
|
||||
console.log('LENS MODEL QUERY',{
|
||||
db: parameterizeForDb('lens_model'),
|
||||
args: parameterize(options.lens.model),
|
||||
});
|
||||
}
|
||||
|
||||
if (takenBefore) {
|
||||
wheres.push(`taken_at < $${valuesIndex++}`);
|
||||
wheresValues.push(takenBefore.toISOString());
|
||||
@ -87,19 +101,19 @@ export const getWheresFromOptions = (
|
||||
}
|
||||
if (camera?.make) {
|
||||
wheres.push(`${parameterizeForDb('make')}=$${valuesIndex++}`);
|
||||
wheresValues.push(parameterize(camera.make, true));
|
||||
wheresValues.push(parameterize(camera.make));
|
||||
}
|
||||
if (camera?.model) {
|
||||
wheres.push(`${parameterizeForDb('model')}=$${valuesIndex++}`);
|
||||
wheresValues.push(parameterize(camera.model, true));
|
||||
wheresValues.push(parameterize(camera.model));
|
||||
}
|
||||
if (lens?.make) {
|
||||
wheres.push(`${parameterizeForDb('lens_make')}=$${valuesIndex++}`);
|
||||
wheresValues.push(parameterize(lens.make, true));
|
||||
wheresValues.push(parameterize(lens.make));
|
||||
}
|
||||
if (lens?.model) {
|
||||
wheres.push(`${parameterizeForDb('lens_model')}=$${valuesIndex++}`);
|
||||
wheresValues.push(parameterize(lens.model, true));
|
||||
wheresValues.push(parameterize(lens.model));
|
||||
}
|
||||
if (tag) {
|
||||
wheres.push(`$${valuesIndex++}=ANY(tags)`);
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { TAG_HIDDEN } from '.';
|
||||
import { pathForTag } from '@/app/paths';
|
||||
import IconHidden from '@/components/icons/IconHidden';
|
||||
import EntityLink, {
|
||||
EntityLinkExternalProps,
|
||||
} from '@/components/primitives/EntityLink';
|
||||
import { AiOutlineEyeInvisible } from 'react-icons/ai';
|
||||
|
||||
export default function HiddenTag({
|
||||
type,
|
||||
@ -20,14 +20,14 @@ export default function HiddenTag({
|
||||
label={badged
|
||||
? <span className="inline-flex items-center gap-1">
|
||||
{TAG_HIDDEN}
|
||||
<AiOutlineEyeInvisible
|
||||
<IconHidden
|
||||
size={13}
|
||||
className="translate-y-[-0.5px]"
|
||||
/>
|
||||
</span>
|
||||
: TAG_HIDDEN}
|
||||
href={pathForTag(TAG_HIDDEN)}
|
||||
icon={!badged && <AiOutlineEyeInvisible size={16} />}
|
||||
icon={!badged && <IconHidden size={16} />}
|
||||
type={type}
|
||||
className={className}
|
||||
hoverEntity={countOnHover}
|
||||
|
||||
@ -22,10 +22,10 @@ export const parameterize = (
|
||||
) =>
|
||||
string
|
||||
.trim()
|
||||
// Replaces spaces, underscores, and dashes with dashes
|
||||
.replaceAll(/[\s_–—]/gi, '-')
|
||||
// Replaces spaces, underscores, slashes,and dashes with dashes
|
||||
.replaceAll(/[\s_–—/]/gi, '-')
|
||||
// Removes punctuation
|
||||
.replaceAll(/['"!@#$%^&*()_+=[\]{};:/?,.<>\\|`~]/gi, '')
|
||||
.replaceAll(/['"!@#$%^&*()_+=[\]{};:/?,<>\\|`~]/gi, '')
|
||||
// Removes all non-alphanumeric characters
|
||||
.replaceAll(
|
||||
shouldRemoveNonAlphanumeric
|
||||
|
||||
Loading…
Reference in New Issue
Block a user