Add default metadata & make replaceFile function

This commit is contained in:
Gabriel Brown 2025-06-01 16:36:29 -05:00
parent dc7cec8539
commit f49488123b
33 changed files with 194 additions and 51 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
public/icons/apple/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/icons/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -2,7 +2,6 @@ import Link from 'next/link';
import { forgotPassword } from '@/lib/actions';
import { FormMessage, type Message, SubmitButton } from '@/components/default';
import { Input, Label } from '@/components/ui';
import { SmtpMessage } from '@/app/(auth-pages)/smtp-message';
const ForgotPassword = async (props: { searchParams: Promise<Message> }) => {
const searchParams = await props.searchParams;
@ -30,7 +29,6 @@ const ForgotPassword = async (props: { searchParams: Promise<Message> }) => {
<FormMessage message={searchParams} />
</div>
</form>
<SmtpMessage />
</>
);
};

View File

@ -1,25 +0,0 @@
import { ArrowUpRight, InfoIcon } from 'lucide-react';
import Link from 'next/link';
export const SmtpMessage = () => {
return (
<div className='bg-muted/50 px-5 py-3 border rounded-md flex gap-4'>
<InfoIcon size={16} className='mt-0.5' />
<div className='flex flex-col gap-1'>
<small className='text-sm text-secondary-foreground'>
<strong> Note:</strong> Emails are rate limited. Enable Custom SMTP to
increase the rate limit.
</small>
<div>
<Link
href='https://supabase.com/docs/guides/auth/auth-smtp'
target='_blank'
className='text-primary/50 hover:text-primary flex items-center text-sm gap-1'
>
Learn more <ArrowUpRight size={14} />
</Link>
</div>
</div>
</div>
);
};

View File

@ -9,24 +9,169 @@ import Footer from '@/components/default/footer';
import { Toaster } from '@/components/ui';
export const metadata: Metadata = {
title: 'T3 Template with Supabase',
description: 'Generated by create-t3-app',
icons: [
{
rel: 'icon',
url: '/images/favicon.ico',
title: {
template: '%s | T3 Template',
default: 'T3 Template with Supabase',
},
description: 'Created by Gib with T3!',
applicationName: 'T3 Template',
keywords: 'T3 Template, Next.js, Supabase, Tailwind, TypeScript, React, T3, Gib, Theo',
authors: [{name: 'Gib', url: 'https://gbrown.org'}],
creator: 'Gib Brown',
publisher: 'Gib Brown',
formatDetection: {
email: false,
address: false,
telephone: false,
},
robots: {
index: true,
follow: true,
nocache: false,
googleBot: {
index: true,
follow: true,
noimageindex: false,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
icons: {
icon: [
{ url: '/icons/favicon.ico', type: 'image/x-icon', sizes: 'any' },
{ url: '/icons/favicon-16x16.png', type: 'image/png', sizes: '16x16'},
{ url: '/icons/favicon-32x32.png', type: 'image/png', sizes: '32x32'},
{ url: '/icons/favicon-96x96.png', type: 'image/png', sizes: '96x96'},
{ url: '/icons/favicon.ico', type: 'image/x-icon', sizes: 'any', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/favicon-16x16.png', type: 'image/png', sizes: '16x16', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/favicon-32x32.png', type: 'image/png', sizes: '32x32', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/favicon-96x96.png', type: 'image/png', sizes: '96x96', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-36x36', type: 'image/png', sizes: '36x36'},
{ url: '/icons/android/icon-48x48', type: 'image/png', sizes: '48x48'},
{ url: '/icons/android/icon-72x72', type: 'image/png', sizes: '72x72'},
{ url: '/icons/android/icon-96x96', type: 'image/png', sizes: '96x96'},
{ url: '/icons/android/icon-144x144', type: 'image/png', sizes: '144x144'},
{ url: '/icons/android/icon-192x192', type: 'image/png', sizes: '192x192'},
{ url: '/icons/android/icon-36x36', type: 'image/png', sizes: '36x36', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-48x48', type: 'image/png', sizes: '48x48', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-72x72', type: 'image/png', sizes: '72x72', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-96x96', type: 'image/png', sizes: '96x96', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-144x144', type: 'image/png', sizes: '144x144', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-192x192', type: 'image/png', sizes: '192x192', media: '(prefers-color-scheme: dark)' },
],
shortcut: [
{ url: '/icons/android/icon-36x36', type: 'image/png', sizes: '36x36'},
{ url: '/icons/android/icon-48x48', type: 'image/png', sizes: '48x48'},
{ url: '/icons/android/icon-72x72', type: 'image/png', sizes: '72x72'},
{ url: '/icons/android/icon-96x96', type: 'image/png', sizes: '96x96'},
{ url: '/icons/android/icon-144x144', type: 'image/png', sizes: '144x144'},
{ url: '/icons/android/icon-192x192', type: 'image/png', sizes: '192x192'},
{ url: '/icons/android/icon-36x36', type: 'image/png', sizes: '36x36', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-48x48', type: 'image/png', sizes: '48x48', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-72x72', type: 'image/png', sizes: '72x72', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-96x96', type: 'image/png', sizes: '96x96', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-144x144', type: 'image/png', sizes: '144x144', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/android/icon-192x192', type: 'image/png', sizes: '192x192', media: '(prefers-color-scheme: dark)' },
],
apple: [
{ url: '/icons/apple/icon.png', type: 'image/png', sizes: '192x192' },
{ url: '/icons/apple/icon-57x57.png', type: 'image/png', sizes: '57x57' },
{ url: '/icons/apple/icon-60x60.png', type: 'image/png', sizes: '60x60' },
{ url: '/icons/apple/icon-72x72.png', type: 'image/png', sizes: '72x72' },
{ url: '/icons/apple/icon-76x76.png', type: 'image/png', sizes: '76x76' },
{ url: '/icons/apple/icon-114x114.png', type: 'image/png', sizes: '114x114' },
{ url: '/icons/apple/icon-120x120.png', type: 'image/png', sizes: '120x120' },
{ url: '/icons/apple/icon-144x144.png', type: 'image/png', sizes: '144x144' },
{ url: '/icons/apple/icon-152x152.png', type: 'image/png', sizes: '152x152' },
{ url: '/icons/apple/icon-180x180.png', type: 'image/png', sizes: '180x180' },
{ url: '/icons/apple/icon.png', type: 'image/png', sizes: '192x192', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-57x57.png', type: 'image/png', sizes: '57x57', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-60x60.png', type: 'image/png', sizes: '60x60', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-72x72.png', type: 'image/png', sizes: '72x72', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-76x76.png', type: 'image/png', sizes: '76x76', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-114x114.png', type: 'image/png', sizes: '114x114', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-120x120.png', type: 'image/png', sizes: '120x120', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-144x144.png', type: 'image/png', sizes: '144x144', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-152x152.png', type: 'image/png', sizes: '152x152', media: '(prefers-color-scheme: dark)' },
{ url: '/icons/apple/icon-180x180.png', type: 'image/png', sizes: '180x180', media: '(prefers-color-scheme: dark)' },
],
other: [
{
rel: 'icon',
rel: 'apple-touch-icon-precomposed',
url: '/icons/apple/icon-precomposed.png',
type: 'image/png',
sizes: '32x32',
url: '/images/favicon.png',
},
{
rel: 'apple-touch-icon',
url: '/images/appicon.png',
sizes: '180x180'
},
],
},
twitter: {
card: 'app',
title: 'T3 Template',
description: 'Created by Gib with T3!',
siteId: '',
creator: '@cs_gib',
creatorId: '',
images: {
url: 'https://git.gbrown.org/gib/T3-Template/raw/main/public/icons/apple/icon.png',
alt: 'T3 Template',
},
app: {
name: 'T3 Template',
id: {
iphone: '',
ipad: '',
googleplay: '',
},
url: {
iphone: '',
ipad: '',
googleplay: '',
},
},
},
verification: {
google: 'google',
yandex: 'yandex',
yahoo: 'yahoo',
},
itunes: {
appId: '',
appArgument: '',
},
appleWebApp: {
title: 'T3 Template',
statusBarStyle: 'black-translucent',
startupImage: [
'/icons/apple/splash-768x1004.png',
{
url: '/icons/apple/splash-1536x2008.png',
media: '(device-width: 768px) and (device-height: 1024px)',
},
],
},
appLinks: {
ios: {
url: 'https://t3-template.gbrown.org/ios',
app_store_id: 't3_template',
},
android: {
package: 'org.gbrown.android/t3-template',
app_name: 'app_t3_template',
},
web: {
url: 'https://t3-template.gbrown.org/web',
should_fallback: true,
},
},
facebook: {
appId: '',
},
pinterest: {
richPin: true,
},
category: 'technology',
};
const geist = Geist({

View File

@ -4,6 +4,7 @@ import Link from 'next/link';
import { Button } from '@/components/ui';
import NavigationAuth from './auth';
import { ThemeToggle } from '@/components/context/theme';
import Image from 'next/image';
const Navigation = () => {
return (
@ -16,7 +17,10 @@ const Navigation = () => {
items-center p-3 px-5 text-sm'
>
<div className='flex gap-5 items-center font-semibold'>
<Link href={'/'}>T3 Supabase Template</Link>
<Link className='flex flex-row my-auto gap-2' href='/'>
<Image src='/icons/favicon-96x96.png' alt='T3 Logo' width={50} height={50} />
<h1 className='my-auto text-2xl'>T3 Supabase Template</h1>
</Link>
<div className='flex items-center gap-2'>
<Button asChild>
<Link href='https://git.gbrown.org/gib/T3-Template'>

View File

@ -31,7 +31,6 @@ export type UploadStorageProps = {
export type ReplaceStorageProps = {
bucket: string;
prevPath: string;
path: string;
file: File;
options?: {
cacheControl?: string;
@ -137,21 +136,22 @@ export const uploadFile = async ({
export const replaceFile = async ({
bucket,
prevPath,
path,
file,
options = {},
}: ReplaceStorageProps): Promise<Result<string>> => {
try {
options.upsert = true;
const supabase = await createServerClient();
//const deleteFileData = await deleteFile({
//bucket,
//path: [...prevPath],
//});
const { data, error } = await supabase.storage
.from(bucket)
.update(path, file, options);
//.update(path, file, options);
.update(prevPath, file, options);
if (error) throw error;
if (!data?.path) throw new Error('No path returned from upload');
const deleteFileData = await deleteFile({
bucket,
path: [...prevPath],
});
return { success: true, data: data.path };
} catch (error) {
return {

View File

@ -1,7 +1,7 @@
'use client'
import { useState, useRef } from 'react';
import { deleteFile, uploadFile } from '@/lib/actions';
import { deleteFile, replaceFile, uploadFile } from '@/lib/actions';
import { toast } from 'sonner';
import { useAuth } from '@/components/context/auth';
import { resizeImage } from '@/lib/hooks';
@ -43,6 +43,21 @@ export const useFileUpload = () => {
console.error('Error deleting file:', deleteResult.error);
throw new Error(deleteResult.error || `Failed to delete ${prevPath}`);
} else console.log('Delete sucessful!')
console.log('Deleted file path: ', deleteResult.data)
const updateResult = await replaceFile({
bucket,
prevPath: prevPath,
file,
options: {
contentType: file.type,
},
});
if (!updateResult.success) {
console.error('Error updating file:', updateResult.error);
} else {
console.log('We used the new update function hopefully it worked!');
return { success: true, path: updateResult.data };
}
}
let fileToUpload = file;

View File

@ -58,6 +58,12 @@ create policy "Avatar images are publicly accessible." on storage.objects
create policy "Anyone can upload an avatar." on storage.objects
for insert with check (bucket_id = 'avatars');
create policy "Anyone can update an avatar." on storage.objects
for update using (bucket_id = 'avatars');
create policy "Anyone can delete an avatar." on storage.objects
for delete using (bucket_id = 'avatars');
-- -- Create a table for public statuses
-- CREATE TABLE statuses (
-- id uuid DEFAULT gen_random_uuid() PRIMARY KEY,