Update deps

This commit is contained in:
HugeFrog24
2026-03-26 03:35:53 +01:00
parent 1edd996336
commit c746b2c17f
68 changed files with 8504 additions and 6901 deletions
+32 -5
View File
@@ -1,14 +1,41 @@
export const appConfig = {
name: 'Shake the Frog',
description: 'A fun interactive frog that reacts to shaking!',
url: 'https://shakethefrog.vercel.app',
url: 'https://shakethefrog.com',
assets: {
favicon: '/images/frog.svg',
ogImage: {
width: 1200,
height: 630,
bgColor: '#f0fdf4',
textColor: '#374151'
bgColor: '#c9ffda',
textColor: '#000000'
}
}
} as const
},
skins: {
frog: {
id: 'frog',
name: 'Frog',
normal: '/images/frog.svg',
shaken: '/images/frog-shaken.svg',
isPremium: false
},
mandarin: {
id: 'mandarin',
name: 'Mandarin',
normal: '/images/mandarin.svg',
// TODO: Create a proper shaken version of the mandarin skin
shaken: '/images/mandarin.svg', // Using the same image for both states until a shaken version is created
isPremium: false,
variantId: 'your_mandarin_variant_id_here' // Replace with actual variant ID when created
},
beaver: {
id: 'beaver',
name: 'Beaver',
normal: '/images/beaver.svg',
shaken: '/images/beaver-shaken.svg',
isPremium: true,
variantId: '1047017'
}
},
defaultSkin: 'frog'
} as const
+14
View File
@@ -0,0 +1,14 @@
// Define our curated emoji pool
const emojiPool = [
'💫', '💝', '💘', '💖', '💕',
'💓', '💗', '💞', '✨', '🌟',
'🔥', '👼', '⭐', '💎', '💨',
'🎉', '🕸️', '🤗', '💋', '😘',
'🫂', '👫', '💟', '💌', '🥰',
'😍', '🥺', '😢', '😭'
];
// Helper function to get a random emoji
export function getRandomEmoji(): string {
return emojiPool[Math.floor(Math.random() * emojiPool.length)];
}
+20
View File
@@ -0,0 +1,20 @@
/**
* Server-side feature flag definitions.
*
* Flags are read from environment variables. The abstraction is kept thin
* so a runtime provider (Flipt, Unleash, Flags SDK adapter, etc.) can be
* swapped in later without changing any consumer code.
*
* Convention: FEATURE_<NAME>=1 → enabled
* anything else → disabled
*/
export interface FeatureFlags {
paymentsEnabled: boolean;
}
export function getFeatureFlags(): FeatureFlags {
return {
paymentsEnabled: process.env.FEATURE_PAYMENTS === '1',
};
}
+45
View File
@@ -0,0 +1,45 @@
import { lemonSqueezySetup } from '@lemonsqueezy/lemonsqueezy.js';
// Initialize Lemon Squeezy SDK
export function initializeLemonSqueezy() {
const apiKey = process.env.LEMONSQUEEZY_API_KEY;
if (!apiKey) {
throw new Error('LEMONSQUEEZY_API_KEY is required');
}
lemonSqueezySetup({
apiKey,
onError: (error) => {
throw error; // Fail fast instead of just logging
},
});
}
// Lemon Squeezy configuration with lazy validation.
// Config is only resolved on first access so the module can be safely
// imported even when payment env vars are absent (e.g. payments disabled).
let _config: { storeId: string; webhookSecret: string; baseUrl: string } | null = null;
export function getLemonSqueezyConfig() {
if (_config) return _config;
const storeId = process.env.LEMONSQUEEZY_STORE_ID;
const webhookSecret = process.env.LEMONSQUEEZY_WEBHOOK_SECRET;
const baseUrl = process.env.NEXT_PUBLIC_APP_URL;
if (!storeId) {
throw new Error('LEMONSQUEEZY_STORE_ID is required');
}
if (!webhookSecret) {
throw new Error('LEMONSQUEEZY_WEBHOOK_SECRET is required');
}
if (!baseUrl) {
throw new Error('NEXT_PUBLIC_APP_URL is required');
}
_config = { storeId, webhookSecret, baseUrl };
return _config;
}
-135
View File
@@ -1,135 +0,0 @@
export const frogMessages = [
"Again! Again! ",
"Almost got me! ",
"Can't catch your breath? ",
"Catch me if you can! ",
"Chase me! ",
"Claim me! ",
"Come closer! ",
"Do it again! ",
"Don't stop now! ",
"Faster! Faster! ",
"Give me all you've got! ",
"Higher! Higher! ",
"I can dance all day! ",
"I can't get enough! ",
"I can't resist you! ",
"I crave your touch! ",
"I feel dizzy! ",
"I like your style! ",
"I love this game! ",
"I need you! ",
"I surrender to you! ",
"I want more! ",
"I yearn for your touch! ",
"I'm a furnace for you! ",
"I'm a raging inferno! ",
"I'm addicted to you! ",
"I'm all yours! ",
"I'm burning up! ",
"I'm completely yours! ",
"I'm consumed by you! ",
"I'm floating on air! ",
"I'm getting dizzy! ",
"I'm getting excited! ",
"I'm getting hot! ",
"I'm having a blast! ",
"I'm having a blast! ",
"I'm hooked on you! ",
"I'm in a tizzy! ",
"I'm in heaven! ",
"I'm in paradise! ",
"I'm lost in you! ",
"I'm melting! ",
"I'm on fire! ",
"I'm on the edge! ",
"I'm overflowing! ",
"I'm quivering with desire! ",
"I'm seeing stars! ",
"I'm shaking with anticipation! ",
"I'm so happy! ",
"I'm trembling! ",
"I'm under your spell! ",
"I'm yours for the taking! ",
"I'm yours forever! ",
"I'm yours to command! ",
"I'm yours! ",
"I'm yours, body and soul! ",
"I'm yours, now and forever! ",
"Is that all you've got? ",
"Keep shaking! ",
"Keep the rhythm going! ",
"Let's party! ",
"Let's play more! ",
"Like a record baby! ",
"Make me yours! ",
"Make me yours, completely! ",
"Missed me! ",
"More, more, more! ",
"My heart's racing! ",
"Neither can I! ",
"One more time! ",
"Playing hard to get? ",
"Round and round we go! ",
"Shake me harder! ",
"Show me what you've got! ",
"Show me your moves! ",
"So close! ",
"Spin me right round! ",
"Stop tickling! ",
"Take me to the edge! ",
"Take me! ",
"Take me, I'm yours! ",
"That tickles! ",
"That was fun! ",
"Too slow! ",
"Unleash me! ",
"Wait till I catch you! ",
"What a rush! ",
"Wheeee! ",
"Wheeeeeee! ",
"You drive me wild! ",
"You found me! ",
"You got me! ",
"You know how to party! ",
"You know what I like! ",
"You make me feel alive! ",
"You're absolute perfection! ",
"You're amazing! ",
"You're beyond incredible! ",
"You're driving me insane! ",
"You're driving me wild! ",
"You're fun! ",
"You're getting better! ",
"You're good at this! ",
"You're incredible! ",
"You're irresistible! ",
"You're making me blush! ",
"You're making me bounce! ",
"You're making me bounce! ",
"You're making me crazy! ",
"You're making me giddy! ",
"You're making me spin! ",
"You're making me swoon! ",
"You're making me twirl! ",
"You're my addiction! ",
"You're my desire! ",
"You're my dream! ",
"You're my everything and more! ",
"You're my everything! ",
"You're my fantasy! ",
"You're my heart's desire! ",
"You're my masterpiece! ",
"You're my obsession! ",
"You're my obsession! ",
"You're my temptation! ",
"You're my ultimate fantasy! ",
"You're my weakness! ",
"You're perfect! ",
"You're so good! ",
"You're so playful! ",
"You're such a tease! ",
"You're unstoppable! ",
"You've got the magic touch! ",
"Your touch is electric! "
];
+100
View File
@@ -0,0 +1,100 @@
import { type Locale } from '../../i18n/request';
// Define grammatical cases for languages that need them
type GrammaticalCase = 'nominative' | 'accusative' | 'dative' | 'genitive' | 'instrumental' | 'prepositional';
// Define which languages need grammatical cases
const languagesWithCases: Partial<Record<Locale, boolean>> = {
ru: true,
ka: true
};
// Localized skin names for different languages with grammatical cases
const skinNames: Record<string, Record<Locale, string | Record<GrammaticalCase, string>>> = {
frog: {
en: 'Frog',
de: 'Frosch',
ru: {
nominative: 'Лягушка',
accusative: 'Лягушку',
dative: 'Лягушке',
genitive: 'Лягушки',
instrumental: 'Лягушкой',
prepositional: 'Лягушке'
},
ka: {
nominative: 'ბაყაყი',
accusative: 'ბაყაყს',
dative: 'ბაყაყს',
genitive: 'ბაყაყის',
instrumental: 'ბაყაყით',
prepositional: 'ბაყაყზე'
},
ar: 'ضفدع'
},
mandarin: {
en: 'Mandarin',
de: 'Mandarine',
ru: {
nominative: 'Мандарин',
accusative: 'Мандарин',
dative: 'Мандарину',
genitive: 'Мандарина',
instrumental: 'Мандарином',
prepositional: 'Мандарине'
},
ka: {
nominative: 'მანდარინი',
accusative: 'მანდარინს',
dative: 'მანდარინს',
genitive: 'მანდარინის',
instrumental: 'მანდარინით',
prepositional: 'მანდარინზე'
},
ar: 'ماندرين'
},
beaver: {
en: 'Beaver',
de: 'Biber',
ru: {
nominative: 'Бобр',
accusative: 'Бобра',
dative: 'Бобру',
genitive: 'Бобра',
instrumental: 'Бобром',
prepositional: 'Бобре'
},
ka: {
nominative: 'თახვი',
accusative: 'თახვს',
dative: 'თახვს',
genitive: 'თახვის',
instrumental: 'თახვით',
prepositional: 'თახვზე'
},
ar: 'قندس'
}
};
/**
* Get the localized name for a skin with the appropriate grammatical case
* @param skinId The skin ID
* @param language The language code
* @param grammaticalCase The grammatical case to use (for languages that need it)
* @returns The localized skin name
*/
export function getLocalizedSkinName(
skinId: string,
language: Locale,
grammaticalCase: GrammaticalCase = 'nominative'
): string {
const skinName = skinNames[skinId]?.[language];
// If the language doesn't use cases or we don't have cases for this skin
if (!skinName || typeof skinName === 'string' || !languagesWithCases[language]) {
return typeof skinName === 'string' ? skinName : skinNames[skinId]?.en as string || skinId;
}
// Return the appropriate case, or fallback to nominative if the case doesn't exist
return skinName[grammaticalCase] || skinName.nominative;
}