Initial commit from Create Next App

This commit is contained in:
shinya
2025-06-17 13:15:54 +08:00
commit 2e989e5e9b
77 changed files with 13025 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
import { openGraph } from '@/lib/og';
describe('Open Graph function should work correctly', () => {
it('should not return templateTitle when not specified', () => {
const result = openGraph({
description: 'Test description',
siteName: 'Test site name',
});
expect(result).not.toContain('&templateTitle=');
});
it('should return templateTitle when specified', () => {
const result = openGraph({
templateTitle: 'Test Template Title',
description: 'Test description',
siteName: 'Test site name',
});
expect(result).toContain('&templateTitle=Test%20Template%20Title');
});
});

20
src/lib/env.ts Normal file
View File

@@ -0,0 +1,20 @@
/* eslint-disable @typescript-eslint/no-namespace */
/**
* Configuration for type-safe environment variables.
* Imported through src/app/page.tsx
* @see https://x.com/mattpocockuk/status/1760991147793449396
*/
import { z } from 'zod';
const envVariables = z.object({
NEXT_PUBLIC_SHOW_LOGGER: z.enum(['true', 'false']).optional(),
});
envVariables.parse(process.env);
declare global {
namespace NodeJS {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface ProcessEnv extends z.infer<typeof envVariables> {}
}
}

13
src/lib/helper.ts Normal file
View File

@@ -0,0 +1,13 @@
export function getFromLocalStorage(key: string): string | null {
if (typeof window !== 'undefined') {
return window.localStorage.getItem(key);
}
return null;
}
export function getFromSessionStorage(key: string): string | null {
if (typeof sessionStorage !== 'undefined') {
return sessionStorage.getItem(key);
}
return null;
}

19
src/lib/logger.ts Normal file
View File

@@ -0,0 +1,19 @@
/* eslint-disable no-console */
import { showLogger } from '@/constant/env';
/**
* A logger function that will only logs on development
* @param object - The object to log
* @param comment - Autogenerated with `lg` snippet
*/
export default function logger(object: unknown, comment?: string): void {
if (!showLogger) return;
console.log(
'%c ============== INFO LOG \n',
'color: #22D3EE',
`${typeof window !== 'undefined' && window?.location.pathname}\n`,
`=== ${comment ?? ''}\n`,
object
);
}

27
src/lib/og.ts Normal file
View File

@@ -0,0 +1,27 @@
type OpenGraphType = {
siteName: string;
description: string;
templateTitle?: string;
logo?: string;
};
// !STARTERCONF This OG is generated from https://github.com/theodorusclarence/og
// Please clone them and self-host if your site is going to be visited by many people.
// Then change the url and the default logo.
export function openGraph({
siteName,
templateTitle,
description,
// !STARTERCONF Or, you can use my server with your own logo.
logo = 'https://og.<your-domain>/images/logo.jpg',
}: OpenGraphType): string {
const ogLogo = encodeURIComponent(logo);
const ogSiteName = encodeURIComponent(siteName.trim());
const ogTemplateTitle = templateTitle
? encodeURIComponent(templateTitle.trim())
: undefined;
const ogDesc = encodeURIComponent(description.trim());
return `https://og.<your-domain>/api/general?siteName=${ogSiteName}&description=${ogDesc}&logo=${ogLogo}${
ogTemplateTitle ? `&templateTitle=${ogTemplateTitle}` : ''
}`;
}

7
src/lib/utils.ts Normal file
View File

@@ -0,0 +1,7 @@
import clsx, { ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
/** Merge classes with tailwind-merge with clsx full feature */
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}