openuispec 0.2.10 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/cli/index.ts +4 -2
- package/cli/init.ts +23 -8
- package/docs/cli.md +13 -8
- package/drift/index.ts +41 -15
- package/mcp-server/index.ts +155 -116
- package/mcp-server/screenshot.ts +19 -4
- package/package.json +5 -2
- package/prepare/index.ts +16 -0
- package/scripts/take-all-screenshots.ts +507 -0
- package/status/index.ts +2 -2
- package/examples/social-app/.mcp.json +0 -10
- package/examples/social-app/AGENTS.md +0 -124
- package/examples/social-app/CLAUDE.md +0 -124
- package/examples/social-app/backend/.gitkeep +0 -1
- package/examples/social-app/generated/android/social-app/app/.paparazzi-hashes.json +0 -3
- package/examples/social-app/generated/android/social-app/app/build.gradle.kts +0 -94
- package/examples/social-app/generated/android/social-app/app/src/main/AndroidManifest.xml +0 -26
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/AppContainer.kt +0 -20
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/MainActivity.kt +0 -35
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/SocialAppApplication.kt +0 -13
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/MockData.kt +0 -98
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/AppPreferences.kt +0 -19
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/DataStorePreferencesRepository.kt +0 -68
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/PreferencesRepository.kt +0 -15
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/model/Models.kt +0 -34
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/MainShell.kt +0 -390
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/components/Components.kt +0 -234
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/components/ContractPrimitives.kt +0 -641
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/navigation/RootComponent.kt +0 -113
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/ChatDetailScreen.kt +0 -212
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/CreatePostScreen.kt +0 -113
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/DiscoverScreen.kt +0 -137
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/EditProfileScreen.kt +0 -180
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/HomeFeedScreen.kt +0 -169
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/MessagesInboxScreen.kt +0 -85
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/NotificationsScreen.kt +0 -74
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/PostDetailScreen.kt +0 -293
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/ProfileSelfScreen.kt +0 -116
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SearchResultsScreen.kt +0 -161
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SettingsScreen.kt +0 -164
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SettingsStore.kt +0 -95
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/UserProfileScreen.kt +0 -123
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Color.kt +0 -33
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Shape.kt +0 -41
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Spacing.kt +0 -20
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Theme.kt +0 -82
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Type.kt +0 -60
- package/examples/social-app/generated/android/social-app/app/src/main/res/drawable/ic_launcher_foreground.xml +0 -9
- package/examples/social-app/generated/android/social-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +0 -5
- package/examples/social-app/generated/android/social-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +0 -5
- package/examples/social-app/generated/android/social-app/app/src/main/res/values/strings.xml +0 -91
- package/examples/social-app/generated/android/social-app/app/src/main/res/values/themes.xml +0 -10
- package/examples/social-app/generated/android/social-app/app/src/main/res/values-ru/strings.xml +0 -79
- package/examples/social-app/generated/android/social-app/app/src/main/res/values-uz/strings.xml +0 -79
- package/examples/social-app/generated/android/social-app/app/src/main/xml/AndroidManifest.xml +0 -23
- package/examples/social-app/generated/android/social-app/app/src/test/kotlin/com/social/app/screenshots/HomeFeedScreenshotTest.kt +0 -34
- package/examples/social-app/generated/android/social-app/build.gradle.kts +0 -7
- package/examples/social-app/generated/android/social-app/gradle/libs.versions.toml +0 -50
- package/examples/social-app/generated/android/social-app/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/examples/social-app/generated/android/social-app/gradle/wrapper/gradle-wrapper.properties +0 -8
- package/examples/social-app/generated/android/social-app/gradle.properties +0 -11
- package/examples/social-app/generated/android/social-app/gradlew +0 -248
- package/examples/social-app/generated/android/social-app/settings.gradle.kts +0 -27
- package/examples/social-app/generated/web/social-app/index.html +0 -12
- package/examples/social-app/generated/web/social-app/package-lock.json +0 -2517
- package/examples/social-app/generated/web/social-app/package.json +0 -27
- package/examples/social-app/generated/web/social-app/src/app/App.tsx +0 -58
- package/examples/social-app/generated/web/social-app/src/components/Shell.tsx +0 -259
- package/examples/social-app/generated/web/social-app/src/components/cards.tsx +0 -317
- package/examples/social-app/generated/web/social-app/src/components/ui.tsx +0 -340
- package/examples/social-app/generated/web/social-app/src/flows/CreatePostFlow.tsx +0 -86
- package/examples/social-app/generated/web/social-app/src/i18n.tsx +0 -59
- package/examples/social-app/generated/web/social-app/src/lib/icons.tsx +0 -85
- package/examples/social-app/generated/web/social-app/src/lib/tokens.ts +0 -70
- package/examples/social-app/generated/web/social-app/src/lib/utils.ts +0 -97
- package/examples/social-app/generated/web/social-app/src/locales/en.json +0 -67
- package/examples/social-app/generated/web/social-app/src/locales/ru.json +0 -67
- package/examples/social-app/generated/web/social-app/src/locales/uz.json +0 -67
- package/examples/social-app/generated/web/social-app/src/main.tsx +0 -16
- package/examples/social-app/generated/web/social-app/src/screens/ChatDetailScreen.tsx +0 -90
- package/examples/social-app/generated/web/social-app/src/screens/DiscoverScreen.tsx +0 -86
- package/examples/social-app/generated/web/social-app/src/screens/EditProfileScreen.tsx +0 -57
- package/examples/social-app/generated/web/social-app/src/screens/HomeFeedScreen.tsx +0 -103
- package/examples/social-app/generated/web/social-app/src/screens/MessagesInboxScreen.tsx +0 -52
- package/examples/social-app/generated/web/social-app/src/screens/NotificationsScreen.tsx +0 -41
- package/examples/social-app/generated/web/social-app/src/screens/PostDetailScreen.tsx +0 -115
- package/examples/social-app/generated/web/social-app/src/screens/ProfileSelfScreen.tsx +0 -57
- package/examples/social-app/generated/web/social-app/src/screens/ProfileUserScreen.tsx +0 -76
- package/examples/social-app/generated/web/social-app/src/screens/SearchResultsScreen.tsx +0 -96
- package/examples/social-app/generated/web/social-app/src/screens/SettingsScreen.tsx +0 -79
- package/examples/social-app/generated/web/social-app/src/state/store.ts +0 -592
- package/examples/social-app/generated/web/social-app/src/styles.css +0 -125
- package/examples/social-app/generated/web/social-app/src/vite-env.d.ts +0 -1
- package/examples/social-app/generated/web/social-app/tsconfig.json +0 -22
- package/examples/social-app/generated/web/social-app/tsconfig.node.json +0 -13
- package/examples/social-app/generated/web/social-app/tsconfig.node.tsbuildinfo +0 -1
- package/examples/social-app/generated/web/social-app/tsconfig.tsbuildinfo +0 -1
- package/examples/social-app/generated/web/social-app/vite.config.d.ts +0 -2
- package/examples/social-app/generated/web/social-app/vite.config.js +0 -6
- package/examples/social-app/generated/web/social-app/vite.config.ts +0 -7
- package/examples/social-app/package.json +0 -13
- package/examples/social-app/take-web-screenshots.ts +0 -97
- package/examples/taskflow/.codex/config.toml +0 -4
- package/examples/taskflow/.mcp.json +0 -10
- package/examples/taskflow/AGENTS.md +0 -124
- package/examples/taskflow/CLAUDE.md +0 -124
- package/examples/taskflow/backend/.gitkeep +0 -1
- package/examples/taskflow/generated/android/TaskFlow/README.md +0 -43
- package/examples/taskflow/generated/android/TaskFlow/app/build.gradle.kts +0 -76
- package/examples/taskflow/generated/android/TaskFlow/app/proguard-rules.pro +0 -1
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/AndroidManifest.xml +0 -21
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/MainActivity.kt +0 -19
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/TaskFlowApp.kt +0 -283
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/model/DomainModels.kt +0 -106
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/model/SampleData.kt +0 -57
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/components/Common.kt +0 -109
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/HomeScreen.kt +0 -112
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/ProjectsScreen.kt +0 -61
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/SettingsScreen.kt +0 -82
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/TaskDetailScreen.kt +0 -111
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/sheets/Sheets.kt +0 -77
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Color.kt +0 -30
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Theme.kt +0 -86
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Type.kt +0 -57
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/res/values/strings.xml +0 -155
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/res/values/themes.xml +0 -4
- package/examples/taskflow/generated/android/TaskFlow/build.gradle.kts +0 -5
- package/examples/taskflow/generated/android/TaskFlow/gradle/gradle-daemon-jvm.properties +0 -12
- package/examples/taskflow/generated/android/TaskFlow/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/examples/taskflow/generated/android/TaskFlow/gradle.properties +0 -4
- package/examples/taskflow/generated/android/TaskFlow/gradlew +0 -18
- package/examples/taskflow/generated/android/TaskFlow/gradlew.bat +0 -12
- package/examples/taskflow/generated/android/TaskFlow/settings.gradle.kts +0 -18
- package/examples/taskflow/generated/ios/TaskFlow/README.md +0 -21
- package/examples/taskflow/generated/ios/TaskFlow/Resources/en.lproj/Localizable.strings +0 -115
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/App/TaskFlowApp.swift +0 -24
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Components/AppChrome.swift +0 -150
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Flows/TaskEditorSheet.swift +0 -220
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Models/DomainModels.swift +0 -122
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/CalendarView.swift +0 -21
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/HomeView.swift +0 -201
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProfileEditView.swift +0 -48
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProjectDetailView.swift +0 -59
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProjectsView.swift +0 -63
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/SettingsView.swift +0 -85
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/TaskDetailView.swift +0 -219
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Support/AppModel.swift +0 -320
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Support/AppSupport.swift +0 -41
- package/examples/taskflow/generated/ios/TaskFlow/project.yml +0 -31
- package/examples/taskflow/generated/web/TaskFlow/README.md +0 -19
- package/examples/taskflow/generated/web/TaskFlow/index.html +0 -12
- package/examples/taskflow/generated/web/TaskFlow/package-lock.json +0 -1908
- package/examples/taskflow/generated/web/TaskFlow/package.json +0 -24
- package/examples/taskflow/generated/web/TaskFlow/src/App.tsx +0 -58
- package/examples/taskflow/generated/web/TaskFlow/src/AppShell.tsx +0 -55
- package/examples/taskflow/generated/web/TaskFlow/src/components/Common.tsx +0 -82
- package/examples/taskflow/generated/web/TaskFlow/src/components/Modals.tsx +0 -191
- package/examples/taskflow/generated/web/TaskFlow/src/components/Nav.tsx +0 -41
- package/examples/taskflow/generated/web/TaskFlow/src/generated/messages.ts +0 -131
- package/examples/taskflow/generated/web/TaskFlow/src/hooks.ts +0 -25
- package/examples/taskflow/generated/web/TaskFlow/src/i18n.ts +0 -39
- package/examples/taskflow/generated/web/TaskFlow/src/locales.en.json +0 -111
- package/examples/taskflow/generated/web/TaskFlow/src/main.tsx +0 -13
- package/examples/taskflow/generated/web/TaskFlow/src/screens/HomeScreen.tsx +0 -111
- package/examples/taskflow/generated/web/TaskFlow/src/screens/ProjectsScreen.tsx +0 -82
- package/examples/taskflow/generated/web/TaskFlow/src/screens/SettingsScreens.tsx +0 -132
- package/examples/taskflow/generated/web/TaskFlow/src/screens/TaskDetail.tsx +0 -105
- package/examples/taskflow/generated/web/TaskFlow/src/store.ts +0 -216
- package/examples/taskflow/generated/web/TaskFlow/src/styles.css +0 -617
- package/examples/taskflow/generated/web/TaskFlow/src/types.ts +0 -64
- package/examples/taskflow/generated/web/TaskFlow/src/utils.ts +0 -78
- package/examples/taskflow/generated/web/TaskFlow/tsconfig.json +0 -21
- package/examples/taskflow/generated/web/TaskFlow/vite.config.ts +0 -6
- package/examples/todo-orbit/.codex/config.toml +0 -4
- package/examples/todo-orbit/.mcp.json +0 -10
- package/examples/todo-orbit/AGENTS.md +0 -124
- package/examples/todo-orbit/CLAUDE.md +0 -124
- package/examples/todo-orbit/backend/.gitkeep +0 -1
- package/examples/todo-orbit/generated/android/Todo Orbit/README.md +0 -14
- package/examples/todo-orbit/generated/android/Todo Orbit/app/build.gradle.kts +0 -58
- package/examples/todo-orbit/generated/android/Todo Orbit/app/proguard-rules.pro +0 -1
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/AndroidManifest.xml +0 -20
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/MainActivity.kt +0 -14
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/TodoOrbitApp.kt +0 -345
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/support/AppLogic.kt +0 -231
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/support/Models.kt +0 -169
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/support/Strings.kt +0 -8
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/components/CommonComponents.kt +0 -236
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/screens/AnalyticsScreen.kt +0 -193
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/screens/SettingsScreen.kt +0 -102
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/screens/TasksScreen.kt +0 -347
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/sheets/EditorSheets.kt +0 -347
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/theme/TodoOrbitTheme.kt +0 -59
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/res/values/strings.xml +0 -149
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/res/values-ru/strings.xml +0 -155
- package/examples/todo-orbit/generated/android/Todo Orbit/build.gradle.kts +0 -4
- package/examples/todo-orbit/generated/android/Todo Orbit/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/examples/todo-orbit/generated/android/Todo Orbit/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/examples/todo-orbit/generated/android/Todo Orbit/gradle.properties +0 -4
- package/examples/todo-orbit/generated/android/Todo Orbit/gradlew +0 -248
- package/examples/todo-orbit/generated/android/Todo Orbit/gradlew.bat +0 -93
- package/examples/todo-orbit/generated/android/Todo Orbit/settings.gradle.kts +0 -18
- package/examples/todo-orbit/generated/ios/Todo Orbit/.screenshot-uitest/Sources/ScreenshotUITest.swift +0 -36
- package/examples/todo-orbit/generated/ios/Todo Orbit/README.md +0 -29
- package/examples/todo-orbit/generated/ios/Todo Orbit/Resources/en.lproj/Localizable.strings +0 -119
- package/examples/todo-orbit/generated/ios/Todo Orbit/Resources/ru.lproj/Localizable.strings +0 -119
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/App/TodoOrbitApp.swift +0 -50
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Components/OrbitChrome.swift +0 -204
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Components/SchedulePreviewView.swift +0 -126
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Components/TrendChartView.swift +0 -70
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Flows/RecurringRuleSheet.swift +0 -126
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Flows/TaskEditorSheet.swift +0 -61
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Models/DomainModels.swift +0 -238
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Screens/AnalyticsView.swift +0 -94
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Screens/SettingsView.swift +0 -76
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Screens/TasksHomeView.swift +0 -364
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Support/AppModel.swift +0 -324
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/project.pbxproj +0 -439
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/xcshareddata/xcschemes/TodoOrbit.xcscheme +0 -89
- package/examples/todo-orbit/generated/ios/Todo Orbit/project.yml +0 -32
- package/examples/todo-orbit/generated/web/Todo Orbit/index.html +0 -16
- package/examples/todo-orbit/generated/web/Todo Orbit/package-lock.json +0 -1087
- package/examples/todo-orbit/generated/web/Todo Orbit/package.json +0 -24
- package/examples/todo-orbit/generated/web/Todo Orbit/src/App.tsx +0 -2167
- package/examples/todo-orbit/generated/web/Todo Orbit/src/main.tsx +0 -13
- package/examples/todo-orbit/generated/web/Todo Orbit/src/styles.css +0 -926
- package/examples/todo-orbit/generated/web/Todo Orbit/tsconfig.json +0 -19
- package/examples/todo-orbit/generated/web/Todo Orbit/vite.config.ts +0 -6
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { useDeferredValue, useState } from "react";
|
|
2
|
-
import { useNavigate } from "react-router";
|
|
3
|
-
import { useI18n } from "../i18n";
|
|
4
|
-
import { ConversationCard } from "../components/cards";
|
|
5
|
-
import { EmptyState, ErrorState, ScreenScaffold, SkeletonList, TextField } from "../components/ui";
|
|
6
|
-
import { selectConversations, useAppStore } from "../state/store";
|
|
7
|
-
import { useSimulatedLoading, useUiScenario } from "../lib/utils";
|
|
8
|
-
|
|
9
|
-
export function MessagesInboxScreen() {
|
|
10
|
-
const { t } = useI18n();
|
|
11
|
-
const navigate = useNavigate();
|
|
12
|
-
const scenario = useUiScenario();
|
|
13
|
-
const [searchQuery, setSearchQuery] = useState("");
|
|
14
|
-
const deferred = useDeferredValue(searchQuery);
|
|
15
|
-
const loading = useSimulatedLoading(`messages-${deferred}`, scenario);
|
|
16
|
-
const state = useAppStore();
|
|
17
|
-
const items = scenario === "empty" ? [] : selectConversations(state, deferred);
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<ScreenScaffold title="Messages" subtitle="Conversation search, unread indicators, and direct routes into chat threads.">
|
|
21
|
-
<TextField
|
|
22
|
-
label={t("messages.search_placeholder")}
|
|
23
|
-
value={searchQuery}
|
|
24
|
-
onValueChange={setSearchQuery}
|
|
25
|
-
placeholder={t("messages.search_placeholder")}
|
|
26
|
-
/>
|
|
27
|
-
|
|
28
|
-
{scenario === "error" ? (
|
|
29
|
-
<ErrorState title="Inbox unavailable" description="The inbox query is in an error state. Remove `?ui=error` to restore it." />
|
|
30
|
-
) : loading ? (
|
|
31
|
-
<SkeletonList count={5} />
|
|
32
|
-
) : items.length === 0 ? (
|
|
33
|
-
<EmptyState title="No conversations" description={t("messages.empty_inbox")} />
|
|
34
|
-
) : (
|
|
35
|
-
<div className="space-y-3">
|
|
36
|
-
{items.map((item) =>
|
|
37
|
-
item.participant ? (
|
|
38
|
-
<ConversationCard
|
|
39
|
-
key={item.conversation.id}
|
|
40
|
-
user={item.participant}
|
|
41
|
-
excerpt={item.lastMessage?.body ?? "No messages yet"}
|
|
42
|
-
unreadCount={item.unreadCount}
|
|
43
|
-
timestamp={item.lastMessage?.createdAt}
|
|
44
|
-
onOpen={() => navigate(`/chat/${item.conversation.id}`)}
|
|
45
|
-
/>
|
|
46
|
-
) : null,
|
|
47
|
-
)}
|
|
48
|
-
</div>
|
|
49
|
-
)}
|
|
50
|
-
</ScreenScaffold>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { useNavigate } from "react-router";
|
|
2
|
-
import { useI18n } from "../i18n";
|
|
3
|
-
import { NotificationCard } from "../components/cards";
|
|
4
|
-
import { EmptyState, ErrorState, ScreenScaffold, SkeletonList } from "../components/ui";
|
|
5
|
-
import { selectNotifications, useAppStore } from "../state/store";
|
|
6
|
-
import { useSimulatedLoading, useUiScenario } from "../lib/utils";
|
|
7
|
-
|
|
8
|
-
export function NotificationsScreen() {
|
|
9
|
-
const { t } = useI18n();
|
|
10
|
-
const navigate = useNavigate();
|
|
11
|
-
const scenario = useUiScenario();
|
|
12
|
-
const loading = useSimulatedLoading("notifications", scenario);
|
|
13
|
-
const state = useAppStore();
|
|
14
|
-
const notifications = scenario === "empty" ? [] : selectNotifications(state);
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<ScreenScaffold title={t("nav.notifications")} subtitle="Mark-as-read interactions wired to the local mock state.">
|
|
18
|
-
{scenario === "error" ? (
|
|
19
|
-
<ErrorState title="Notifications unavailable" description="The notifications request failed. Remove `?ui=error` to recover." />
|
|
20
|
-
) : loading ? (
|
|
21
|
-
<SkeletonList count={6} />
|
|
22
|
-
) : notifications.length === 0 ? (
|
|
23
|
-
<EmptyState title="Nothing new" description={t("notifications.empty")} />
|
|
24
|
-
) : (
|
|
25
|
-
<div className="space-y-3">
|
|
26
|
-
{notifications.map((item) => (
|
|
27
|
-
<NotificationCard
|
|
28
|
-
key={item.id}
|
|
29
|
-
item={item}
|
|
30
|
-
actor={item.actor}
|
|
31
|
-
onOpen={() => {
|
|
32
|
-
state.markNotificationRead(item.id);
|
|
33
|
-
navigate(item.postId ? `/posts/${item.postId}` : "/profile");
|
|
34
|
-
}}
|
|
35
|
-
/>
|
|
36
|
-
))}
|
|
37
|
-
</div>
|
|
38
|
-
)}
|
|
39
|
-
</ScreenScaffold>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
import { useNavigate, useParams } from "react-router";
|
|
3
|
-
import { useI18n } from "../i18n";
|
|
4
|
-
import { CommentCard, PostCard } from "../components/cards";
|
|
5
|
-
import { ActionButton, EmptyState, ErrorState, ScreenScaffold, SectionTitle, SkeletonList, TextField } from "../components/ui";
|
|
6
|
-
import { useSimulatedLoading, useUiScenario } from "../lib/utils";
|
|
7
|
-
import { selectCommentsByPost, selectPostById, selectUserById, useAppStore } from "../state/store";
|
|
8
|
-
|
|
9
|
-
export function PostDetailScreen() {
|
|
10
|
-
const { t } = useI18n();
|
|
11
|
-
const navigate = useNavigate();
|
|
12
|
-
const { postId = "" } = useParams();
|
|
13
|
-
const scenario = useUiScenario();
|
|
14
|
-
const loading = useSimulatedLoading(`post-${postId}`, scenario);
|
|
15
|
-
const state = useAppStore();
|
|
16
|
-
const [commentText, setCommentText] = useState("");
|
|
17
|
-
const post = scenario === "empty" ? undefined : selectPostById(state, postId);
|
|
18
|
-
const comments = scenario === "empty" ? [] : selectCommentsByPost(state, postId);
|
|
19
|
-
|
|
20
|
-
if (scenario === "error") {
|
|
21
|
-
return (
|
|
22
|
-
<ScreenScaffold title="Post Detail">
|
|
23
|
-
<ErrorState title="Post unavailable" description="The detail request failed. Remove `?ui=error` to return to the normal state." />
|
|
24
|
-
</ScreenScaffold>
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (loading) {
|
|
29
|
-
return (
|
|
30
|
-
<ScreenScaffold title="Post Detail">
|
|
31
|
-
<SkeletonList count={1} tall />
|
|
32
|
-
</ScreenScaffold>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!post) {
|
|
37
|
-
return (
|
|
38
|
-
<ScreenScaffold title="Post Detail">
|
|
39
|
-
<EmptyState title="Missing post" description="This post could not be found in the local mock data." />
|
|
40
|
-
</ScreenScaffold>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const author = selectUserById(state, post.authorId);
|
|
45
|
-
if (!author) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<ScreenScaffold title="Post Detail" subtitle={`Published ${new Date(post.publishedAt).toLocaleDateString()}`}>
|
|
51
|
-
<PostCard
|
|
52
|
-
post={post}
|
|
53
|
-
author={author}
|
|
54
|
-
hero
|
|
55
|
-
onAuthor={() => navigate(`/u/${author.id}`)}
|
|
56
|
-
onLike={() => state.toggleLike(post.id)}
|
|
57
|
-
onSave={() => state.toggleSave(post.id)}
|
|
58
|
-
/>
|
|
59
|
-
|
|
60
|
-
<section className="space-y-4">
|
|
61
|
-
<ActionButton variant="secondary" icon={post.liked ? "like_fill" : "like"} onClick={() => state.toggleLike(post.id)}>
|
|
62
|
-
{t("post.like_action")}
|
|
63
|
-
</ActionButton>
|
|
64
|
-
</section>
|
|
65
|
-
|
|
66
|
-
<section className="space-y-4">
|
|
67
|
-
<SectionTitle>{t("post.comments_header")}</SectionTitle>
|
|
68
|
-
{comments.length === 0 ? (
|
|
69
|
-
<EmptyState title="No comments yet" description={t("post.no_comments")} />
|
|
70
|
-
) : (
|
|
71
|
-
<div className="space-y-3">
|
|
72
|
-
{comments.map((comment) => {
|
|
73
|
-
const commentAuthor = selectUserById(state, comment.authorId);
|
|
74
|
-
if (!commentAuthor) {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
return (
|
|
78
|
-
<CommentCard
|
|
79
|
-
key={comment.id}
|
|
80
|
-
comment={comment}
|
|
81
|
-
author={commentAuthor}
|
|
82
|
-
onAuthor={() => navigate(`/u/${commentAuthor.id}`)}
|
|
83
|
-
/>
|
|
84
|
-
);
|
|
85
|
-
})}
|
|
86
|
-
</div>
|
|
87
|
-
)}
|
|
88
|
-
</section>
|
|
89
|
-
|
|
90
|
-
<TextField
|
|
91
|
-
label={t("post.comment_placeholder")}
|
|
92
|
-
value={commentText}
|
|
93
|
-
multiline
|
|
94
|
-
onValueChange={setCommentText}
|
|
95
|
-
placeholder={t("post.comment_placeholder")}
|
|
96
|
-
trailingAction={
|
|
97
|
-
<ActionButton
|
|
98
|
-
variant="primary"
|
|
99
|
-
icon="send"
|
|
100
|
-
onClick={() => {
|
|
101
|
-
if (!commentText.trim()) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
state.addComment(post.id, commentText.trim());
|
|
105
|
-
setCommentText("");
|
|
106
|
-
state.showToast(t("post.comment_sent"));
|
|
107
|
-
}}
|
|
108
|
-
>
|
|
109
|
-
Send
|
|
110
|
-
</ActionButton>
|
|
111
|
-
}
|
|
112
|
-
/>
|
|
113
|
-
</ScreenScaffold>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { useNavigate } from "react-router";
|
|
2
|
-
import { useI18n } from "../i18n";
|
|
3
|
-
import { PostCard, ProfileHero } from "../components/cards";
|
|
4
|
-
import { ActionButton, EmptyState, ScreenScaffold, SectionTitle, SkeletonList } from "../components/ui";
|
|
5
|
-
import { selectCurrentUser, selectProfilePosts, selectUserById, useAppStore } from "../state/store";
|
|
6
|
-
import { useSimulatedLoading, useUiScenario } from "../lib/utils";
|
|
7
|
-
|
|
8
|
-
export function ProfileSelfScreen() {
|
|
9
|
-
const { t } = useI18n();
|
|
10
|
-
const navigate = useNavigate();
|
|
11
|
-
const scenario = useUiScenario();
|
|
12
|
-
const loading = useSimulatedLoading("profile-self", scenario);
|
|
13
|
-
const state = useAppStore();
|
|
14
|
-
const user = selectCurrentUser(state);
|
|
15
|
-
const posts = scenario === "empty" ? [] : selectProfilePosts(state, user.id);
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<ScreenScaffold title={t("nav.profile")} subtitle="Your own profile with edit action and authored posts.">
|
|
19
|
-
{loading ? (
|
|
20
|
-
<SkeletonList count={2} tall />
|
|
21
|
-
) : (
|
|
22
|
-
<ProfileHero
|
|
23
|
-
user={user}
|
|
24
|
-
action={
|
|
25
|
-
<ActionButton variant="secondary" icon="edit" onClick={() => navigate("/profile/edit")}>
|
|
26
|
-
{t("profile.edit_button")}
|
|
27
|
-
</ActionButton>
|
|
28
|
-
}
|
|
29
|
-
/>
|
|
30
|
-
)}
|
|
31
|
-
|
|
32
|
-
<section className="space-y-4">
|
|
33
|
-
<SectionTitle>{t("profile.posts_header")}</SectionTitle>
|
|
34
|
-
{loading ? (
|
|
35
|
-
<SkeletonList count={3} />
|
|
36
|
-
) : posts.length === 0 ? (
|
|
37
|
-
<EmptyState title="No posts yet" description={t("profile.no_posts_self")} />
|
|
38
|
-
) : (
|
|
39
|
-
<div className="space-y-4">
|
|
40
|
-
{posts.map((post) => (
|
|
41
|
-
<div key={post.id} className="rounded-card border border-[var(--color-border-default)] bg-[var(--color-surface-secondary)] p-4 shadow-sm">
|
|
42
|
-
<PostCard
|
|
43
|
-
post={post}
|
|
44
|
-
author={selectUserById(state, post.authorId) ?? user}
|
|
45
|
-
onOpen={() => navigate(`/posts/${post.id}`)}
|
|
46
|
-
onAuthor={() => navigate(`/u/${user.id}`)}
|
|
47
|
-
onLike={() => state.toggleLike(post.id)}
|
|
48
|
-
onSave={() => state.toggleSave(post.id)}
|
|
49
|
-
/>
|
|
50
|
-
</div>
|
|
51
|
-
))}
|
|
52
|
-
</div>
|
|
53
|
-
)}
|
|
54
|
-
</section>
|
|
55
|
-
</ScreenScaffold>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { useNavigate, useParams } from "react-router";
|
|
2
|
-
import { useI18n } from "../i18n";
|
|
3
|
-
import { PostCard, ProfileHero } from "../components/cards";
|
|
4
|
-
import { ActionButton, EmptyState, ErrorState, ScreenScaffold, SectionTitle, SkeletonList } from "../components/ui";
|
|
5
|
-
import { selectProfilePosts, selectUserById, useAppStore } from "../state/store";
|
|
6
|
-
import { useSimulatedLoading, useUiScenario } from "../lib/utils";
|
|
7
|
-
|
|
8
|
-
export function ProfileUserScreen() {
|
|
9
|
-
const { t } = useI18n();
|
|
10
|
-
const navigate = useNavigate();
|
|
11
|
-
const { userId = "" } = useParams();
|
|
12
|
-
const scenario = useUiScenario();
|
|
13
|
-
const loading = useSimulatedLoading(`profile-${userId}`, scenario);
|
|
14
|
-
const state = useAppStore();
|
|
15
|
-
const user = scenario === "empty" ? undefined : selectUserById(state, userId);
|
|
16
|
-
const posts = scenario === "empty" ? [] : selectProfilePosts(state, userId);
|
|
17
|
-
|
|
18
|
-
if (scenario === "error") {
|
|
19
|
-
return (
|
|
20
|
-
<ScreenScaffold title="Profile">
|
|
21
|
-
<ErrorState title="Profile unavailable" description="The profile request failed. Remove `?ui=error` to restore it." />
|
|
22
|
-
</ScreenScaffold>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (loading) {
|
|
27
|
-
return (
|
|
28
|
-
<ScreenScaffold title="Profile">
|
|
29
|
-
<SkeletonList count={3} tall />
|
|
30
|
-
</ScreenScaffold>
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (!user) {
|
|
35
|
-
return (
|
|
36
|
-
<ScreenScaffold title="Profile">
|
|
37
|
-
<EmptyState title="Profile missing" description="The requested user does not exist in the local dataset." />
|
|
38
|
-
</ScreenScaffold>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<ScreenScaffold title={user.displayName} subtitle={`@${user.handle}`}>
|
|
44
|
-
<ProfileHero
|
|
45
|
-
user={user}
|
|
46
|
-
action={
|
|
47
|
-
<ActionButton variant="primary" onClick={() => state.followUser(user.id)}>
|
|
48
|
-
{t("profile.follow_button")}
|
|
49
|
-
</ActionButton>
|
|
50
|
-
}
|
|
51
|
-
/>
|
|
52
|
-
|
|
53
|
-
<section className="space-y-4">
|
|
54
|
-
<SectionTitle>{t("profile.posts_header")}</SectionTitle>
|
|
55
|
-
{posts.length === 0 ? (
|
|
56
|
-
<EmptyState title="No posts yet" description={t("profile.no_posts_user")} />
|
|
57
|
-
) : (
|
|
58
|
-
<div className="space-y-4">
|
|
59
|
-
{posts.map((post) => (
|
|
60
|
-
<div key={post.id} className="rounded-card border border-[var(--color-border-default)] bg-[var(--color-surface-secondary)] p-4 shadow-sm">
|
|
61
|
-
<PostCard
|
|
62
|
-
post={post}
|
|
63
|
-
author={user}
|
|
64
|
-
onOpen={() => navigate(`/posts/${post.id}`)}
|
|
65
|
-
onAuthor={() => navigate(`/u/${user.id}`)}
|
|
66
|
-
onLike={() => state.toggleLike(post.id)}
|
|
67
|
-
onSave={() => state.toggleSave(post.id)}
|
|
68
|
-
/>
|
|
69
|
-
</div>
|
|
70
|
-
))}
|
|
71
|
-
</div>
|
|
72
|
-
)}
|
|
73
|
-
</section>
|
|
74
|
-
</ScreenScaffold>
|
|
75
|
-
);
|
|
76
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, startTransition } from "react";
|
|
2
|
-
import { useNavigate, useSearchParams } from "react-router";
|
|
3
|
-
import { useI18n } from "../i18n";
|
|
4
|
-
import { ActionButton, EmptyState, ErrorState, ScreenScaffold, SkeletonList, TextField } from "../components/ui";
|
|
5
|
-
import { selectSearchResults, useAppStore } from "../state/store";
|
|
6
|
-
import { useSimulatedLoading, useUiScenario } from "../lib/utils";
|
|
7
|
-
|
|
8
|
-
export function SearchResultsScreen() {
|
|
9
|
-
const { t } = useI18n();
|
|
10
|
-
const navigate = useNavigate();
|
|
11
|
-
const scenario = useUiScenario();
|
|
12
|
-
const [searchParams, setSearchParams] = useSearchParams();
|
|
13
|
-
const [query, setQuery] = useState(searchParams.get("query") ?? "");
|
|
14
|
-
const [activeTab, setActiveTab] = useState<"posts" | "people" | "tags">(
|
|
15
|
-
(searchParams.get("tab") as "posts" | "people" | "tags") ?? "posts",
|
|
16
|
-
);
|
|
17
|
-
const loading = useSimulatedLoading(`search-${query}-${activeTab}`, scenario);
|
|
18
|
-
const state = useAppStore();
|
|
19
|
-
const results = selectSearchResults(state, query, activeTab);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
setQuery(searchParams.get("query") ?? "");
|
|
23
|
-
setActiveTab(((searchParams.get("tab") as "posts" | "people" | "tags") ?? "posts"));
|
|
24
|
-
}, [searchParams]);
|
|
25
|
-
|
|
26
|
-
const visibleResults = scenario === "empty" ? [] : results;
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<ScreenScaffold title="Search Results" subtitle={`Querying "${query}" across ${activeTab}.`}>
|
|
30
|
-
<TextField
|
|
31
|
-
label={t("search.placeholder")}
|
|
32
|
-
value={query}
|
|
33
|
-
onValueChange={setQuery}
|
|
34
|
-
placeholder={t("search.placeholder")}
|
|
35
|
-
trailingAction={
|
|
36
|
-
<ActionButton
|
|
37
|
-
variant="primary"
|
|
38
|
-
icon="search"
|
|
39
|
-
onClick={() => setSearchParams({ query, tab: activeTab })}
|
|
40
|
-
>
|
|
41
|
-
Search
|
|
42
|
-
</ActionButton>
|
|
43
|
-
}
|
|
44
|
-
/>
|
|
45
|
-
|
|
46
|
-
<div className="no-scrollbar flex gap-2 overflow-x-auto pb-1">
|
|
47
|
-
{[
|
|
48
|
-
{ value: "posts" as const, label: t("search.tab_posts") },
|
|
49
|
-
{ value: "people" as const, label: t("search.tab_people") },
|
|
50
|
-
{ value: "tags" as const, label: t("search.tab_tags") },
|
|
51
|
-
].map((tab) => (
|
|
52
|
-
<ActionButton
|
|
53
|
-
key={tab.value}
|
|
54
|
-
variant="chip"
|
|
55
|
-
selected={activeTab === tab.value}
|
|
56
|
-
onClick={() => {
|
|
57
|
-
startTransition(() => setActiveTab(tab.value));
|
|
58
|
-
setSearchParams({ query, tab: tab.value });
|
|
59
|
-
}}
|
|
60
|
-
>
|
|
61
|
-
{tab.label}
|
|
62
|
-
</ActionButton>
|
|
63
|
-
))}
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
{scenario === "error" ? (
|
|
67
|
-
<ErrorState title="Search failed" description="The search request is in an error state. Remove `?ui=error` to see results." />
|
|
68
|
-
) : loading ? (
|
|
69
|
-
<SkeletonList count={5} />
|
|
70
|
-
) : visibleResults.length === 0 ? (
|
|
71
|
-
<EmptyState title="No results" description={t("search.no_results")} />
|
|
72
|
-
) : (
|
|
73
|
-
<div className="space-y-3">
|
|
74
|
-
{visibleResults.map((result) => (
|
|
75
|
-
<button
|
|
76
|
-
key={`${result.kind}-${result.id}`}
|
|
77
|
-
type="button"
|
|
78
|
-
onClick={() => {
|
|
79
|
-
if (result.kind === "people") {
|
|
80
|
-
navigate(`/u/${result.id}`);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
navigate(`/posts/${result.id}`);
|
|
84
|
-
}}
|
|
85
|
-
className="w-full rounded-card border border-[var(--color-border-default)] bg-[var(--color-surface-secondary)] p-4 text-left shadow-sm transition hover:-translate-y-0.5"
|
|
86
|
-
>
|
|
87
|
-
<p className="font-semibold text-[var(--color-text-primary)]">{result.title}</p>
|
|
88
|
-
<p className="mt-1 text-sm text-[var(--color-text-secondary)]">{result.subtitle}</p>
|
|
89
|
-
<p className="mt-3 line-clamp-2 text-sm leading-6 text-[var(--color-text-secondary)]">{result.body}</p>
|
|
90
|
-
</button>
|
|
91
|
-
))}
|
|
92
|
-
</div>
|
|
93
|
-
)}
|
|
94
|
-
</ScreenScaffold>
|
|
95
|
-
);
|
|
96
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { useNavigate } from "react-router";
|
|
2
|
-
import { useI18n } from "../i18n";
|
|
3
|
-
import { ActionButton, ActionGroup, ScreenScaffold, SectionTitle, SelectField, ToggleField } from "../components/ui";
|
|
4
|
-
import { useAppStore } from "../state/store";
|
|
5
|
-
|
|
6
|
-
export function SettingsScreen() {
|
|
7
|
-
const { t } = useI18n();
|
|
8
|
-
const navigate = useNavigate();
|
|
9
|
-
const state = useAppStore();
|
|
10
|
-
|
|
11
|
-
return (
|
|
12
|
-
<ScreenScaffold title="Settings" subtitle="Theme select, toggles, and a confirmation dialog for logout.">
|
|
13
|
-
<section className="space-y-4">
|
|
14
|
-
<SectionTitle>{t("settings.appearance")}</SectionTitle>
|
|
15
|
-
<SelectField
|
|
16
|
-
label={t("settings.theme")}
|
|
17
|
-
value={state.preferences.theme}
|
|
18
|
-
options={[
|
|
19
|
-
{ value: "system", label: t("settings.theme_system") },
|
|
20
|
-
{ value: "light", label: t("settings.theme_light") },
|
|
21
|
-
{ value: "dark", label: t("settings.theme_dark") },
|
|
22
|
-
]}
|
|
23
|
-
onValueChange={(value) => state.updatePreference("theme", value as "system" | "light" | "dark")}
|
|
24
|
-
/>
|
|
25
|
-
</section>
|
|
26
|
-
|
|
27
|
-
<section className="space-y-4">
|
|
28
|
-
<SectionTitle>{t("settings.notifications")}</SectionTitle>
|
|
29
|
-
<ToggleField
|
|
30
|
-
label={t("settings.push_notifications")}
|
|
31
|
-
checked={state.preferences.pushNotifications}
|
|
32
|
-
onChange={(value) => state.updatePreference("pushNotifications", value)}
|
|
33
|
-
/>
|
|
34
|
-
<ToggleField
|
|
35
|
-
label={t("settings.message_previews")}
|
|
36
|
-
checked={state.preferences.messagePreviews}
|
|
37
|
-
onChange={(value) => state.updatePreference("messagePreviews", value)}
|
|
38
|
-
/>
|
|
39
|
-
</section>
|
|
40
|
-
|
|
41
|
-
<section className="space-y-4">
|
|
42
|
-
<SectionTitle>{t("settings.language")}</SectionTitle>
|
|
43
|
-
<ToggleField
|
|
44
|
-
label={t("settings.auto_translate")}
|
|
45
|
-
checked={state.preferences.autoTranslate}
|
|
46
|
-
onChange={(value) => state.updatePreference("autoTranslate", value)}
|
|
47
|
-
/>
|
|
48
|
-
</section>
|
|
49
|
-
|
|
50
|
-
<section className="space-y-4">
|
|
51
|
-
<SectionTitle>{t("settings.account")}</SectionTitle>
|
|
52
|
-
<ActionGroup className="gap-2">
|
|
53
|
-
<ActionButton variant="secondary" icon="edit" onClick={() => navigate("/profile/edit")}>
|
|
54
|
-
{t("settings.edit_profile")}
|
|
55
|
-
</ActionButton>
|
|
56
|
-
<ActionButton
|
|
57
|
-
variant="destructive"
|
|
58
|
-
onClick={() =>
|
|
59
|
-
state.openDialog({
|
|
60
|
-
title: t("settings.logout"),
|
|
61
|
-
message: t("settings.logout_confirm"),
|
|
62
|
-
actions: [
|
|
63
|
-
{ label: t("common.cancel"), variant: "secondary", onPress: () => undefined },
|
|
64
|
-
{
|
|
65
|
-
label: t("settings.logout"),
|
|
66
|
-
variant: "destructive",
|
|
67
|
-
onPress: () => state.logout(),
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
>
|
|
73
|
-
{t("settings.logout")}
|
|
74
|
-
</ActionButton>
|
|
75
|
-
</ActionGroup>
|
|
76
|
-
</section>
|
|
77
|
-
</ScreenScaffold>
|
|
78
|
-
);
|
|
79
|
-
}
|