Add default metadata & make replaceFile function
Before Width: | Height: | Size: 23 KiB |
BIN
public/icons/android/icon-144x144.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
public/icons/android/icon-192x192.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
public/icons/android/icon-36x36.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
public/icons/android/icon-48x48.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
public/icons/android/icon-72x72.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
public/icons/android/icon-96x96.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
public/icons/apple/icon-114x114.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
public/icons/apple/icon-120x120.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
public/icons/apple/icon-144x144.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
public/icons/apple/icon-152x152.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
public/icons/apple/icon-180x180.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
public/icons/apple/icon-57x57.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
public/icons/apple/icon-60x60.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
public/icons/apple/icon-72x72.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
public/icons/apple/icon-76x76.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
public/icons/apple/icon-precomposed.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
public/icons/apple/icon.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
public/icons/favicon-16x16.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
public/icons/favicon-32x32.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
public/icons/favicon-96x96.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
public/icons/favicon.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
public/icons/microsoft/icon-144x144.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
public/icons/microsoft/icon-150x150.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
public/icons/microsoft/icon-310x310.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
public/icons/microsoft/icon-70x70.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
@ -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 />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
@ -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({
|
||||
|
@ -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'>
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|