commit
77bed4821f
@ -62,7 +62,8 @@ Installation
|
||||
|
||||
### 6. Optional configuration
|
||||
|
||||
- `NEXT_PUBLIC_PRO_MODE = 1` enables higher quality image storage
|
||||
- `NEXT_PUBLIC_PRO_MODE = 1` enables higher quality image storage (will result in increased storage usage)
|
||||
- `NEXT_PUBLIC_BLUR_DISABLED = 1` prevents image blur data being stored and displayed (potentially useful for limiting Postgres usage)
|
||||
- `NEXT_PUBLIC_GEO_PRIVACY = 1` disables collection/display of location-based data
|
||||
- `NEXT_PUBLIC_IGNORE_PRIORITY_ORDER = 1` prevents `priority_order` field affecting photo order
|
||||
- `NEXT_PUBLIC_PUBLIC_API = 1` enables public API available at `/api`
|
||||
|
||||
22
src/components/ImageBlurFallback.tsx
Normal file
22
src/components/ImageBlurFallback.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { BLUR_ENABLED } from '@/site/config';
|
||||
import clsx from 'clsx/lite';
|
||||
import Image, { ImageProps } from 'next/image';
|
||||
|
||||
export default function ImageBlurFallback(props: ImageProps) {
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/alt-text
|
||||
<Image {...{
|
||||
...props,
|
||||
...BLUR_ENABLED && props.blurDataURL ? {
|
||||
placeholder: 'blur',
|
||||
blurDataURL: props.blurDataURL,
|
||||
}: {
|
||||
placeholder: 'empty',
|
||||
className: clsx(
|
||||
props.className,
|
||||
'bg-gray-100/50 dark:bg-gray-900/50',
|
||||
),
|
||||
},
|
||||
}} />
|
||||
);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { IMAGE_LARGE_WIDTH } from '@/site';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import ImageBlurFallback from './ImageBlurFallback';
|
||||
|
||||
export default function ImageLarge({
|
||||
className,
|
||||
@ -16,7 +16,7 @@ export default function ImageLarge({
|
||||
src: string
|
||||
alt: string
|
||||
aspectRatio: number
|
||||
blurData: string
|
||||
blurData?: string
|
||||
priority?: boolean
|
||||
}) {
|
||||
return (
|
||||
@ -24,13 +24,12 @@ export default function ImageLarge({
|
||||
href={href}
|
||||
className="active:brightness-75"
|
||||
>
|
||||
<Image {...{
|
||||
<ImageBlurFallback {...{
|
||||
className,
|
||||
src,
|
||||
alt,
|
||||
priority,
|
||||
blurDataURL: blurData,
|
||||
placeholder: 'blur',
|
||||
width: IMAGE_LARGE_WIDTH,
|
||||
height: Math.round(IMAGE_LARGE_WIDTH / aspectRatio),
|
||||
}} />
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { IMAGE_SMALL_WIDTH } from '@/site';
|
||||
import Image from 'next/image';
|
||||
import ImageBlurFallback from './ImageBlurFallback';
|
||||
|
||||
export default function ImageSmall({
|
||||
className,
|
||||
@ -12,10 +12,10 @@ export default function ImageSmall({
|
||||
src: string
|
||||
alt: string
|
||||
aspectRatio: number
|
||||
blurData: string
|
||||
blurData?: string
|
||||
}) {
|
||||
return (
|
||||
<Image {...{
|
||||
<ImageBlurFallback {...{
|
||||
className,
|
||||
src,
|
||||
alt,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { IMAGE_TINY_WIDTH } from '@/site';
|
||||
import Image from 'next/image';
|
||||
import ImageBlurFallback from './ImageBlurFallback';
|
||||
|
||||
export default function ImageTiny({
|
||||
className,
|
||||
@ -15,7 +15,7 @@ export default function ImageTiny({
|
||||
blurData?: string
|
||||
}) {
|
||||
return (
|
||||
<Image {...{
|
||||
<ImageBlurFallback {...{
|
||||
className,
|
||||
src,
|
||||
alt,
|
||||
|
||||
@ -9,7 +9,6 @@ import {
|
||||
isFormValid,
|
||||
} from './form';
|
||||
import FieldSetWithStatus from '@/components/FieldSetWithStatus';
|
||||
import NextImage from 'next/image';
|
||||
import { createPhotoAction, updatePhotoAction } from './actions';
|
||||
import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus';
|
||||
import Link from 'next/link';
|
||||
@ -22,6 +21,8 @@ import {
|
||||
} from '@/utility/date';
|
||||
import { toastSuccess, toastWarning } from '@/toast';
|
||||
import { getDimensionsFromSize } from '@/utility/size';
|
||||
import ImageBlurFallback from '@/components/ImageBlurFallback';
|
||||
import { BLUR_ENABLED } from '@/site/config';
|
||||
|
||||
const THUMBNAIL_SIZE = 300;
|
||||
|
||||
@ -97,16 +98,18 @@ export default function PhotoForm({
|
||||
const url = formData.url ?? '';
|
||||
|
||||
const updateBlurData = useCallback((blurData: string) => {
|
||||
setFormData(data => ({
|
||||
...data,
|
||||
blurData,
|
||||
}));
|
||||
if (BLUR_ENABLED) {
|
||||
setFormData(data => ({
|
||||
...data,
|
||||
blurData,
|
||||
}));
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="space-y-8 max-w-[38rem]">
|
||||
<div className="flex gap-2">
|
||||
<NextImage
|
||||
<ImageBlurFallback
|
||||
alt="Upload"
|
||||
src={url}
|
||||
className={clsx(
|
||||
|
||||
@ -13,7 +13,7 @@ import {
|
||||
MAKE_FUJIFILM,
|
||||
} from '@/vendors/fujifilm';
|
||||
import { FilmSimulation } from '@/simulation';
|
||||
import { GEO_PRIVACY_ENABLED } from '@/site/config';
|
||||
import { BLUR_ENABLED, GEO_PRIVACY_ENABLED } from '@/site/config';
|
||||
import { TAG_FAVS, doesTagsStringIncludeFavs } from '@/tag';
|
||||
|
||||
type VirtualFields = 'favorite';
|
||||
@ -28,8 +28,8 @@ type FormMeta = {
|
||||
readOnly?: boolean
|
||||
validate?: (value?: string) => string | undefined
|
||||
capitalize?: boolean
|
||||
hide?: boolean
|
||||
hideIfEmpty?: boolean
|
||||
hideTemporarily?: boolean
|
||||
hideBasedOnCamera?: (make?: string, mode?: string) => boolean
|
||||
loadingMessage?: string
|
||||
checkbox?: boolean
|
||||
@ -50,7 +50,8 @@ const FORM_METADATA: Record<keyof PhotoFormData, FormMeta> = {
|
||||
blurData: {
|
||||
label: 'blur data',
|
||||
readOnly: true,
|
||||
required: true,
|
||||
required: BLUR_ENABLED,
|
||||
hideIfEmpty: !BLUR_ENABLED,
|
||||
loadingMessage: 'Generating blur data ...',
|
||||
},
|
||||
url: { label: 'url', readOnly: true },
|
||||
@ -70,7 +71,7 @@ const FORM_METADATA: Record<keyof PhotoFormData, FormMeta> = {
|
||||
iso: { label: 'ISO' },
|
||||
exposureTime: { label: 'exposure time' },
|
||||
exposureCompensation: { label: 'exposure compensation' },
|
||||
locationName: { label: 'location name', hideTemporarily: true },
|
||||
locationName: { label: 'location name', hide: true },
|
||||
latitude: { label: 'latitude' },
|
||||
longitude: { label: 'longitude' },
|
||||
takenAt: { label: 'taken at' },
|
||||
@ -82,7 +83,7 @@ const FORM_METADATA: Record<keyof PhotoFormData, FormMeta> = {
|
||||
|
||||
export const FORM_METADATA_ENTRIES =
|
||||
(Object.entries(FORM_METADATA) as [keyof PhotoFormData, FormMeta][])
|
||||
.filter(([_, meta]) => !meta.hideTemporarily);
|
||||
.filter(([_, meta]) => !meta.hide);
|
||||
|
||||
export const convertFormKeysToLabels = (keys: (keyof PhotoFormData)[]) =>
|
||||
keys.map(key => FORM_METADATA[key].label.toUpperCase());
|
||||
|
||||
@ -44,7 +44,7 @@ export interface PhotoDbInsert extends PhotoExif {
|
||||
id: string
|
||||
url: string
|
||||
extension: string
|
||||
blurData: string
|
||||
blurData?: string
|
||||
title?: string
|
||||
tags?: string[]
|
||||
locationName?: string
|
||||
|
||||
@ -37,6 +37,7 @@ export default function SiteChecklistClient({
|
||||
showFilmSimulations,
|
||||
showExifInfo,
|
||||
isProModeEnabled,
|
||||
isBlurEnabled,
|
||||
isGeoPrivacyEnabled,
|
||||
isPriorityOrderEnabled,
|
||||
isPublicApiEnabled,
|
||||
@ -270,6 +271,16 @@ export default function SiteChecklistClient({
|
||||
higher quality image storage:
|
||||
{renderEnvVars(['NEXT_PUBLIC_PRO_MODE'])}
|
||||
</ChecklistRow>
|
||||
<ChecklistRow
|
||||
title="Image Blur"
|
||||
status={isBlurEnabled}
|
||||
isPending={isPendingPage}
|
||||
optional
|
||||
>
|
||||
Set environment variable to {'"1"'} to prevent
|
||||
image blur data being stored and displayed
|
||||
{renderEnvVars(['NEXT_PUBLIC_BLUR_DISABLED'])}
|
||||
</ChecklistRow>
|
||||
<ChecklistRow
|
||||
title="Geo Privacy"
|
||||
status={isGeoPrivacyEnabled}
|
||||
|
||||
@ -82,6 +82,7 @@ export const CURRENT_STORAGE: StorageType =
|
||||
// SETTINGS
|
||||
|
||||
export const PRO_MODE_ENABLED = process.env.NEXT_PUBLIC_PRO_MODE === '1';
|
||||
export const BLUR_ENABLED = process.env.NEXT_PUBLIC_BLUR_DISABLED !== '1';
|
||||
export const GEO_PRIVACY_ENABLED = process.env.NEXT_PUBLIC_GEO_PRIVACY === '1';
|
||||
export const PRIORITY_ORDER_ENABLED =
|
||||
process.env.NEXT_PUBLIC_IGNORE_PRIORITY_ORDER !== '1';
|
||||
@ -120,6 +121,7 @@ export const CONFIG_CHECKLIST_STATUS = {
|
||||
showFilmSimulations: SHOW_FILM_SIMULATIONS,
|
||||
showExifInfo: SHOW_EXIF_DATA,
|
||||
isProModeEnabled: PRO_MODE_ENABLED,
|
||||
isBlurEnabled: BLUR_ENABLED,
|
||||
isGeoPrivacyEnabled: GEO_PRIVACY_ENABLED,
|
||||
isPriorityOrderEnabled: PRIORITY_ORDER_ENABLED,
|
||||
isPublicApiEnabled: PUBLIC_API_ENABLED,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user