✨ Major Features Added: - Complete magical theming and rebranding from LifeRPG to The Wizard's Grimoire - Production-grade React frontend with Tailwind CSS v4 and magical aesthetics - Comprehensive analytics dashboard with Recharts integration (ScryingPortal) - Push notifications system with PWA service worker support - Drag & drop functionality using @dnd-kit for habit reordering - Social features with friends system and leaderboards - Performance optimization tools and monitoring - Mobile app enhancement with PWA installation support 🏗️ Technical Infrastructure: - Advanced service worker with offline support and background sync - Zustand state management for scalable application state - Production-ready UI component system with enhanced Button, Card, Input - Progressive Web App (PWA) with manifest and app installation - FastAPI backend with comprehensive API endpoints - Docker containerization and CI/CD pipeline setup 📱 Progressive Web App Features: - Offline functionality with intelligent caching - Push notification support for habit reminders - App installation on mobile and desktop platforms - Background sync for offline data management - Performance monitoring and optimization tools 🎨 User Experience: - Magical wizard/grimoire theming throughout application - Responsive design optimized for all device sizes - Drag & drop habit management with smooth animations - Interactive analytics with multiple chart types - Social connectivity with friends and competitive features - Comprehensive notification and performance settings 🔧 Developer Experience: - Modern development stack with Vite and React - Comprehensive testing setup and CI/CD pipelines - Code quality tools with pre-commit hooks - Docker development environment - Detailed documentation and implementation guides This represents a complete transformation from prototype to production-ready application with enterprise-grade features and magical user experience.
72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import type { ExpoConfig } from 'expo/config';
|
|
|
|
const OIDC_ISSUER = process.env.EXPO_PUBLIC_OIDC_ISSUER || 'https://example-idp.com/realms/liferpg';
|
|
const OIDC_CLIENT_ID = process.env.EXPO_PUBLIC_OIDC_CLIENT_ID || 'liferpg-mobile';
|
|
const OIDC_REDIRECT = process.env.EXPO_PUBLIC_OIDC_REDIRECT || 'liferpg:/oauthredirect';
|
|
const OIDC_SCOPES = (process.env.EXPO_PUBLIC_OIDC_SCOPES || 'openid profile email offline_access').split(' ');
|
|
const API_BASE = process.env.EXPO_PUBLIC_API_BASE_URL || 'https://api.example.com';
|
|
|
|
function toUrl(maybe: string): URL | null {
|
|
try {
|
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(maybe)) return new URL(maybe);
|
|
if (/^[a-z][a-z0-9+.-]*:\/[^/]/i.test(maybe)) return new URL(maybe.replace(':/', '://'));
|
|
return null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
const parsedRedirect = toUrl(OIDC_REDIRECT);
|
|
|
|
const config: ExpoConfig = {
|
|
name: 'LifeRPG Mobile',
|
|
slug: 'liferpg-mobile',
|
|
scheme: 'liferpg',
|
|
version: '0.0.1',
|
|
orientation: 'portrait',
|
|
platforms: ['android', 'ios'],
|
|
// Use repo image as icon until dedicated asset exists
|
|
icon: '../../Res/128px-Role-playing_video_game_icon.svg.png',
|
|
userInterfaceStyle: 'automatic',
|
|
updates: { enabled: true },
|
|
extra: {
|
|
oidc: {
|
|
issuer: OIDC_ISSUER,
|
|
clientId: OIDC_CLIENT_ID,
|
|
redirectUrl: OIDC_REDIRECT,
|
|
scopes: OIDC_SCOPES,
|
|
},
|
|
apiBaseUrl: API_BASE,
|
|
},
|
|
ios: {
|
|
bundleIdentifier: 'com.liferpg.mobile',
|
|
associatedDomains: [],
|
|
},
|
|
android: {
|
|
package: 'com.liferpg.mobile',
|
|
intentFilters: [
|
|
{
|
|
action: 'VIEW',
|
|
autoVerify: false,
|
|
category: ['BROWSABLE', 'DEFAULT'],
|
|
data: [
|
|
parsedRedirect
|
|
? ((() => {
|
|
const base: any = { scheme: parsedRedirect.protocol.replace(':', '') };
|
|
if (parsedRedirect.host) base.host = parsedRedirect.host;
|
|
const path = parsedRedirect.pathname;
|
|
if (path && path !== '/') base.path = path;
|
|
return base;
|
|
})())
|
|
: { scheme: 'liferpg', host: 'oauthredirect' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
experiments: {
|
|
// Keep default
|
|
},
|
|
};
|
|
|
|
export default config;
|