openuispec 0.1.45 → 0.1.46
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 +2 -1
- package/cli/init.ts +5 -2
- package/examples/social-app/.mcp.json +10 -0
- package/examples/social-app/AGENTS.md +105 -0
- package/examples/social-app/CLAUDE.md +105 -0
- package/examples/social-app/README.md +19 -0
- package/examples/social-app/backend/.gitkeep +1 -0
- package/examples/social-app/generated/android/social-app/app/build.gradle.kts +92 -0
- package/examples/social-app/generated/android/social-app/app/src/main/AndroidManifest.xml +26 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/AppContainer.kt +20 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/MainActivity.kt +35 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/SocialAppApplication.kt +13 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/MockData.kt +98 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/AppPreferences.kt +19 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/DataStorePreferencesRepository.kt +68 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/PreferencesRepository.kt +15 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/model/Models.kt +34 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/MainShell.kt +390 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/components/Components.kt +234 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/components/ContractPrimitives.kt +641 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/navigation/RootComponent.kt +113 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/ChatDetailScreen.kt +212 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/CreatePostScreen.kt +113 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/DiscoverScreen.kt +137 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/EditProfileScreen.kt +180 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/HomeFeedScreen.kt +157 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/MessagesInboxScreen.kt +85 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/NotificationsScreen.kt +74 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/PostDetailScreen.kt +293 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/ProfileSelfScreen.kt +116 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SearchResultsScreen.kt +161 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SettingsScreen.kt +162 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SettingsStore.kt +95 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/UserProfileScreen.kt +123 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Color.kt +33 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Shape.kt +41 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Spacing.kt +20 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Theme.kt +82 -0
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Type.kt +60 -0
- package/examples/social-app/generated/android/social-app/app/src/main/res/drawable/ic_launcher_foreground.xml +9 -0
- package/examples/social-app/generated/android/social-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- package/examples/social-app/generated/android/social-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- package/examples/social-app/generated/android/social-app/app/src/main/res/values/strings.xml +91 -0
- package/examples/social-app/generated/android/social-app/app/src/main/res/values/themes.xml +10 -0
- package/examples/social-app/generated/android/social-app/app/src/main/res/values-ru/strings.xml +79 -0
- package/examples/social-app/generated/android/social-app/app/src/main/res/values-uz/strings.xml +79 -0
- package/examples/social-app/generated/android/social-app/app/src/main/xml/AndroidManifest.xml +23 -0
- package/examples/social-app/generated/android/social-app/build.gradle.kts +6 -0
- package/examples/social-app/generated/android/social-app/gradle/libs.versions.toml +48 -0
- package/examples/social-app/generated/android/social-app/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/examples/social-app/generated/android/social-app/gradle.properties +11 -0
- package/examples/social-app/generated/android/social-app/gradlew +25 -0
- package/examples/social-app/generated/android/social-app/settings.gradle.kts +23 -0
- package/examples/social-app/generated/web/social-app/index.html +12 -0
- package/examples/social-app/generated/web/social-app/package-lock.json +2517 -0
- package/examples/social-app/generated/web/social-app/package.json +27 -0
- package/examples/social-app/generated/web/social-app/src/app/App.tsx +58 -0
- package/examples/social-app/generated/web/social-app/src/components/Shell.tsx +247 -0
- package/examples/social-app/generated/web/social-app/src/components/cards.tsx +317 -0
- package/examples/social-app/generated/web/social-app/src/components/ui.tsx +328 -0
- package/examples/social-app/generated/web/social-app/src/flows/CreatePostFlow.tsx +86 -0
- package/examples/social-app/generated/web/social-app/src/i18n.tsx +59 -0
- package/examples/social-app/generated/web/social-app/src/lib/icons.tsx +85 -0
- package/examples/social-app/generated/web/social-app/src/lib/tokens.ts +70 -0
- package/examples/social-app/generated/web/social-app/src/lib/utils.ts +97 -0
- package/examples/social-app/generated/web/social-app/src/locales/en.json +67 -0
- package/examples/social-app/generated/web/social-app/src/locales/ru.json +67 -0
- package/examples/social-app/generated/web/social-app/src/locales/uz.json +67 -0
- package/examples/social-app/generated/web/social-app/src/main.tsx +16 -0
- package/examples/social-app/generated/web/social-app/src/screens/ChatDetailScreen.tsx +90 -0
- package/examples/social-app/generated/web/social-app/src/screens/DiscoverScreen.tsx +86 -0
- package/examples/social-app/generated/web/social-app/src/screens/EditProfileScreen.tsx +57 -0
- package/examples/social-app/generated/web/social-app/src/screens/HomeFeedScreen.tsx +113 -0
- package/examples/social-app/generated/web/social-app/src/screens/MessagesInboxScreen.tsx +52 -0
- package/examples/social-app/generated/web/social-app/src/screens/NotificationsScreen.tsx +41 -0
- package/examples/social-app/generated/web/social-app/src/screens/PostDetailScreen.tsx +115 -0
- package/examples/social-app/generated/web/social-app/src/screens/ProfileSelfScreen.tsx +57 -0
- package/examples/social-app/generated/web/social-app/src/screens/ProfileUserScreen.tsx +76 -0
- package/examples/social-app/generated/web/social-app/src/screens/SearchResultsScreen.tsx +96 -0
- package/examples/social-app/generated/web/social-app/src/screens/SettingsScreen.tsx +77 -0
- package/examples/social-app/generated/web/social-app/src/state/store.ts +592 -0
- package/examples/social-app/generated/web/social-app/src/styles.css +124 -0
- package/examples/social-app/generated/web/social-app/src/vite-env.d.ts +1 -0
- package/examples/social-app/generated/web/social-app/tsconfig.json +22 -0
- package/examples/social-app/generated/web/social-app/tsconfig.node.json +13 -0
- package/examples/social-app/generated/web/social-app/tsconfig.node.tsbuildinfo +1 -0
- package/examples/social-app/generated/web/social-app/tsconfig.tsbuildinfo +1 -0
- package/examples/social-app/generated/web/social-app/vite.config.d.ts +2 -0
- package/examples/social-app/generated/web/social-app/vite.config.js +6 -0
- package/examples/social-app/generated/web/social-app/vite.config.ts +7 -0
- package/examples/social-app/openuispec/README.md +56 -0
- package/examples/social-app/openuispec/contracts/.gitkeep +0 -0
- package/examples/social-app/openuispec/contracts/action_trigger.yaml +73 -0
- package/examples/social-app/openuispec/contracts/collection.yaml +43 -0
- package/examples/social-app/openuispec/contracts/data_display.yaml +47 -0
- package/examples/social-app/openuispec/contracts/feedback.yaml +49 -0
- package/examples/social-app/openuispec/contracts/input_field.yaml +41 -0
- package/examples/social-app/openuispec/contracts/nav_container.yaml +34 -0
- package/examples/social-app/openuispec/contracts/surface.yaml +41 -0
- package/examples/social-app/openuispec/flows/.gitkeep +0 -0
- package/examples/social-app/openuispec/flows/create_post.yaml +66 -0
- package/examples/social-app/openuispec/locales/.gitkeep +0 -0
- package/examples/social-app/openuispec/locales/en.json +67 -0
- package/examples/social-app/openuispec/locales/ru.json +67 -0
- package/examples/social-app/openuispec/locales/uz.json +67 -0
- package/examples/social-app/openuispec/openuispec.yaml +214 -0
- package/examples/social-app/openuispec/platform/.gitkeep +0 -0
- package/examples/social-app/openuispec/platform/android.yaml +30 -0
- package/examples/social-app/openuispec/platform/ios.yaml +19 -0
- package/examples/social-app/openuispec/platform/web.yaml +23 -0
- package/examples/social-app/openuispec/screens/.gitkeep +0 -0
- package/examples/social-app/openuispec/screens/chat_detail.yaml +53 -0
- package/examples/social-app/openuispec/screens/discover.yaml +78 -0
- package/examples/social-app/openuispec/screens/edit_profile.yaml +78 -0
- package/examples/social-app/openuispec/screens/home_feed.yaml +123 -0
- package/examples/social-app/openuispec/screens/messages_inbox.yaml +43 -0
- package/examples/social-app/openuispec/screens/notifications.yaml +29 -0
- package/examples/social-app/openuispec/screens/post_detail.yaml +86 -0
- package/examples/social-app/openuispec/screens/profile_self.yaml +53 -0
- package/examples/social-app/openuispec/screens/profile_user.yaml +60 -0
- package/examples/social-app/openuispec/screens/search_results.yaml +62 -0
- package/examples/social-app/openuispec/screens/settings.yaml +94 -0
- package/examples/social-app/openuispec/tokens/.gitkeep +0 -0
- package/examples/social-app/openuispec/tokens/color.yaml +76 -0
- package/examples/social-app/openuispec/tokens/elevation.yaml +31 -0
- package/examples/social-app/openuispec/tokens/icons.yaml +147 -0
- package/examples/social-app/openuispec/tokens/layout.yaml +37 -0
- package/examples/social-app/openuispec/tokens/motion.yaml +28 -0
- package/examples/social-app/openuispec/tokens/spacing.yaml +19 -0
- package/examples/social-app/openuispec/tokens/themes.yaml +31 -0
- package/examples/social-app/openuispec/tokens/typography.yaml +50 -0
- package/examples/social-app/package.json +12 -0
- package/package.json +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
discover:
|
|
2
|
+
semantic: "Discover screen with search, trending topics, and suggested creators"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
data:
|
|
6
|
+
creators:
|
|
7
|
+
source: "api.discover.creators"
|
|
8
|
+
loading: { skeleton: true, count: 6 }
|
|
9
|
+
trends:
|
|
10
|
+
source: "api.discover.trends"
|
|
11
|
+
loading: { skeleton: true, count: 5 }
|
|
12
|
+
tags:
|
|
13
|
+
source: "api.discover.tags"
|
|
14
|
+
loading: { skeleton: true, count: 10 }
|
|
15
|
+
|
|
16
|
+
state:
|
|
17
|
+
search_query: { type: string, default: "" }
|
|
18
|
+
|
|
19
|
+
layout:
|
|
20
|
+
type: scroll_vertical
|
|
21
|
+
sections:
|
|
22
|
+
- id: search_bar
|
|
23
|
+
contract: input_field
|
|
24
|
+
input_type: text
|
|
25
|
+
props:
|
|
26
|
+
label: "$t:discover.search_placeholder"
|
|
27
|
+
value: "state.search_query"
|
|
28
|
+
icon: "search"
|
|
29
|
+
action:
|
|
30
|
+
type: navigate
|
|
31
|
+
destination: "screens/search_results"
|
|
32
|
+
params: { query: "state.search_query" }
|
|
33
|
+
|
|
34
|
+
- id: trending_section
|
|
35
|
+
header: "$t:discover.trending"
|
|
36
|
+
contract: collection
|
|
37
|
+
variant: list
|
|
38
|
+
props:
|
|
39
|
+
data: "trends"
|
|
40
|
+
item_contract: data_display
|
|
41
|
+
item_props_map:
|
|
42
|
+
title: "item.label"
|
|
43
|
+
subtitle: "{item.post_count | format:number}"
|
|
44
|
+
action:
|
|
45
|
+
type: navigate
|
|
46
|
+
destination: "screens/search_results"
|
|
47
|
+
params: { query: "{item.label}", tab: "posts" }
|
|
48
|
+
|
|
49
|
+
- id: tags_section
|
|
50
|
+
header: "$t:discover.popular_tags"
|
|
51
|
+
contract: collection
|
|
52
|
+
variant: chip_row
|
|
53
|
+
props:
|
|
54
|
+
data: "tags"
|
|
55
|
+
item_contract: action_trigger
|
|
56
|
+
item_props_map:
|
|
57
|
+
label: "#{item.name}"
|
|
58
|
+
action:
|
|
59
|
+
type: navigate
|
|
60
|
+
destination: "screens/search_results"
|
|
61
|
+
params: { query: "#{item.name}", tab: "posts" }
|
|
62
|
+
|
|
63
|
+
- id: creators_section
|
|
64
|
+
header: "$t:discover.suggested_creators"
|
|
65
|
+
contract: collection
|
|
66
|
+
variant: horizontal_scroll
|
|
67
|
+
props:
|
|
68
|
+
data: "creators"
|
|
69
|
+
item_contract: data_display
|
|
70
|
+
item_props_map:
|
|
71
|
+
title: "item.display_name"
|
|
72
|
+
subtitle: "@{item.handle}"
|
|
73
|
+
body: "item.bio"
|
|
74
|
+
leading: "item.avatar_url"
|
|
75
|
+
action:
|
|
76
|
+
type: navigate
|
|
77
|
+
destination: "screens/profile_user"
|
|
78
|
+
params: { user_id: "{item.id}" }
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
edit_profile:
|
|
2
|
+
semantic: "Edit current user's profile fields"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
data:
|
|
6
|
+
profile:
|
|
7
|
+
source: "api.profiles.me"
|
|
8
|
+
|
|
9
|
+
state:
|
|
10
|
+
display_name: { type: string, default: "{profile.display_name}" }
|
|
11
|
+
handle: { type: string, default: "{profile.handle}" }
|
|
12
|
+
bio: { type: string, default: "{profile.bio}" }
|
|
13
|
+
website: { type: string, default: "{profile.website}" }
|
|
14
|
+
|
|
15
|
+
layout:
|
|
16
|
+
type: scroll_vertical
|
|
17
|
+
sections:
|
|
18
|
+
- id: avatar_section
|
|
19
|
+
contract: data_display
|
|
20
|
+
variant: card
|
|
21
|
+
props:
|
|
22
|
+
title: "$t:edit_profile.avatar"
|
|
23
|
+
media: "{profile.avatar_url}"
|
|
24
|
+
|
|
25
|
+
- id: form
|
|
26
|
+
form_id: "profile_form"
|
|
27
|
+
children:
|
|
28
|
+
- contract: input_field
|
|
29
|
+
input_type: text
|
|
30
|
+
props:
|
|
31
|
+
label: "$t:edit_profile.display_name"
|
|
32
|
+
value: "state.display_name"
|
|
33
|
+
required: true
|
|
34
|
+
data_binding: "form.display_name"
|
|
35
|
+
|
|
36
|
+
- contract: input_field
|
|
37
|
+
input_type: text
|
|
38
|
+
props:
|
|
39
|
+
label: "$t:edit_profile.handle"
|
|
40
|
+
value: "state.handle"
|
|
41
|
+
required: true
|
|
42
|
+
data_binding: "form.handle"
|
|
43
|
+
|
|
44
|
+
- contract: input_field
|
|
45
|
+
input_type: text
|
|
46
|
+
props:
|
|
47
|
+
label: "$t:edit_profile.bio"
|
|
48
|
+
value: "state.bio"
|
|
49
|
+
multiline: true
|
|
50
|
+
max_length: 160
|
|
51
|
+
data_binding: "form.bio"
|
|
52
|
+
|
|
53
|
+
- contract: input_field
|
|
54
|
+
input_type: text
|
|
55
|
+
props:
|
|
56
|
+
label: "$t:edit_profile.website"
|
|
57
|
+
value: "state.website"
|
|
58
|
+
keyboard: url
|
|
59
|
+
data_binding: "form.website"
|
|
60
|
+
|
|
61
|
+
- id: save_button
|
|
62
|
+
contract: action_trigger
|
|
63
|
+
variant: primary
|
|
64
|
+
props:
|
|
65
|
+
label: "$t:edit_profile.save"
|
|
66
|
+
full_width: true
|
|
67
|
+
action:
|
|
68
|
+
type: sequence
|
|
69
|
+
actions:
|
|
70
|
+
- type: api_call
|
|
71
|
+
endpoint: "api.profiles.updateMe"
|
|
72
|
+
body:
|
|
73
|
+
display_name: "state.display_name"
|
|
74
|
+
handle: "state.handle"
|
|
75
|
+
bio: "state.bio"
|
|
76
|
+
website: "state.website"
|
|
77
|
+
- { type: feedback, variant: toast, message: "$t:edit_profile.saved" }
|
|
78
|
+
- { type: dismiss }
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
home_feed:
|
|
2
|
+
semantic: "Main feed with stories carousel, post list, and create post action"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
data:
|
|
6
|
+
feed:
|
|
7
|
+
source: "api.feed.list"
|
|
8
|
+
params:
|
|
9
|
+
filter: "state.active_filter"
|
|
10
|
+
search: "state.search_query"
|
|
11
|
+
cursor: "state.cursor"
|
|
12
|
+
loading: { skeleton: true, count: 5 }
|
|
13
|
+
empty: { message: "$t:home.empty_feed" }
|
|
14
|
+
stories:
|
|
15
|
+
source: "api.feed.stories"
|
|
16
|
+
loading: { skeleton: true, count: 8 }
|
|
17
|
+
|
|
18
|
+
state:
|
|
19
|
+
active_filter:
|
|
20
|
+
type: enum
|
|
21
|
+
values: [all, following, popular]
|
|
22
|
+
default: all
|
|
23
|
+
search_query: { type: string, default: "" }
|
|
24
|
+
cursor: { type: string, default: "" }
|
|
25
|
+
|
|
26
|
+
navigation:
|
|
27
|
+
contract: nav_container
|
|
28
|
+
props:
|
|
29
|
+
items:
|
|
30
|
+
- id: "home"
|
|
31
|
+
label: "$t:nav.home"
|
|
32
|
+
icon: "home"
|
|
33
|
+
destination: "screens/home_feed"
|
|
34
|
+
- id: "discover"
|
|
35
|
+
label: "$t:nav.discover"
|
|
36
|
+
icon: "discover"
|
|
37
|
+
destination: "screens/discover"
|
|
38
|
+
- id: "create"
|
|
39
|
+
label: "$t:nav.create"
|
|
40
|
+
icon: "create_post"
|
|
41
|
+
destination: "flows/create_post"
|
|
42
|
+
- id: "notifications"
|
|
43
|
+
label: "$t:nav.notifications"
|
|
44
|
+
icon: "notifications"
|
|
45
|
+
destination: "screens/notifications"
|
|
46
|
+
badge:
|
|
47
|
+
count: "api.notifications.unreadCount"
|
|
48
|
+
- id: "profile"
|
|
49
|
+
label: "$t:nav.profile"
|
|
50
|
+
icon: "profile"
|
|
51
|
+
destination: "screens/profile_self"
|
|
52
|
+
adaptive:
|
|
53
|
+
compact: { variant: tab_bar }
|
|
54
|
+
expanded: { variant: sidebar }
|
|
55
|
+
|
|
56
|
+
layout:
|
|
57
|
+
type: scroll_vertical
|
|
58
|
+
sections:
|
|
59
|
+
- id: stories_bar
|
|
60
|
+
contract: collection
|
|
61
|
+
variant: horizontal_scroll
|
|
62
|
+
props:
|
|
63
|
+
data: "stories"
|
|
64
|
+
item_contract: data_display
|
|
65
|
+
item_props_map:
|
|
66
|
+
title: "item.author.display_name"
|
|
67
|
+
media: "item.preview_url"
|
|
68
|
+
action:
|
|
69
|
+
type: navigate
|
|
70
|
+
destination: "screens/post_detail"
|
|
71
|
+
params: { post_id: "{item.id}" }
|
|
72
|
+
|
|
73
|
+
- id: filter_chips
|
|
74
|
+
contract: collection
|
|
75
|
+
variant: chip_row
|
|
76
|
+
props:
|
|
77
|
+
data: "state.active_filter"
|
|
78
|
+
item_contract: action_trigger
|
|
79
|
+
item_props_map:
|
|
80
|
+
label: "item.label"
|
|
81
|
+
options:
|
|
82
|
+
- { value: "all", label: "$t:home.filter_all" }
|
|
83
|
+
- { value: "following", label: "$t:home.filter_following" }
|
|
84
|
+
- { value: "popular", label: "$t:home.filter_popular" }
|
|
85
|
+
|
|
86
|
+
- id: post_list
|
|
87
|
+
contract: collection
|
|
88
|
+
variant: list
|
|
89
|
+
props:
|
|
90
|
+
data: "feed"
|
|
91
|
+
item_contract: data_display
|
|
92
|
+
item_props_map:
|
|
93
|
+
title: "item.author.display_name"
|
|
94
|
+
subtitle: "@{item.author.handle}"
|
|
95
|
+
body: "item.body"
|
|
96
|
+
media: "item.media_url"
|
|
97
|
+
leading: "item.author.avatar_url"
|
|
98
|
+
metadata:
|
|
99
|
+
like_count: "{item.like_count | format:number}"
|
|
100
|
+
comment_count: "{item.comment_count | format:number}"
|
|
101
|
+
timestamp: "{item.published_at | format:date_relative}"
|
|
102
|
+
item_actions:
|
|
103
|
+
- id: like
|
|
104
|
+
icon: "like"
|
|
105
|
+
icon_active: "like_fill"
|
|
106
|
+
action: { type: api_call, endpoint: "api.posts.toggleLike", params: { id: "{item.id}" } }
|
|
107
|
+
- id: comment
|
|
108
|
+
icon: "comment"
|
|
109
|
+
action: { type: navigate, destination: "screens/post_detail", params: { post_id: "{item.id}" } }
|
|
110
|
+
- id: share
|
|
111
|
+
icon: "share"
|
|
112
|
+
action: { type: share, content: "{item.body}" }
|
|
113
|
+
- id: save
|
|
114
|
+
icon: "bookmark"
|
|
115
|
+
icon_active: "bookmark_fill"
|
|
116
|
+
action: { type: api_call, endpoint: "api.posts.save", params: { id: "{item.id}" } }
|
|
117
|
+
action:
|
|
118
|
+
type: navigate
|
|
119
|
+
destination: "screens/post_detail"
|
|
120
|
+
params: { post_id: "{item.id}" }
|
|
121
|
+
pagination:
|
|
122
|
+
type: infinite_scroll
|
|
123
|
+
cursor_field: "cursor"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
messages_inbox:
|
|
2
|
+
semantic: "Conversations list with search and unread indicators"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
data:
|
|
6
|
+
conversations:
|
|
7
|
+
source: "api.messages.list"
|
|
8
|
+
params:
|
|
9
|
+
search: "state.search_query"
|
|
10
|
+
loading: { skeleton: true, count: 6 }
|
|
11
|
+
empty: { message: "$t:messages.empty_inbox" }
|
|
12
|
+
|
|
13
|
+
state:
|
|
14
|
+
search_query: { type: string, default: "" }
|
|
15
|
+
|
|
16
|
+
layout:
|
|
17
|
+
type: scroll_vertical
|
|
18
|
+
sections:
|
|
19
|
+
- id: search
|
|
20
|
+
contract: input_field
|
|
21
|
+
input_type: text
|
|
22
|
+
props:
|
|
23
|
+
label: "$t:messages.search_placeholder"
|
|
24
|
+
value: "state.search_query"
|
|
25
|
+
icon: "search"
|
|
26
|
+
|
|
27
|
+
- id: conversation_list
|
|
28
|
+
contract: collection
|
|
29
|
+
variant: list
|
|
30
|
+
props:
|
|
31
|
+
data: "conversations"
|
|
32
|
+
item_contract: data_display
|
|
33
|
+
item_props_map:
|
|
34
|
+
title: "item.participant.display_name"
|
|
35
|
+
subtitle: "item.last_message.body"
|
|
36
|
+
leading: "item.participant.avatar_url"
|
|
37
|
+
metadata:
|
|
38
|
+
timestamp: "{item.last_message.created_at | format:date_relative}"
|
|
39
|
+
unread_count: "{item.unread_count}"
|
|
40
|
+
action:
|
|
41
|
+
type: navigate
|
|
42
|
+
destination: "screens/chat_detail"
|
|
43
|
+
params: { conversation_id: "{item.id}" }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
notifications:
|
|
2
|
+
semantic: "Notification list with mark-as-read"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
data:
|
|
6
|
+
notifications:
|
|
7
|
+
source: "api.notifications.list"
|
|
8
|
+
loading: { skeleton: true, count: 8 }
|
|
9
|
+
empty: { message: "$t:notifications.empty" }
|
|
10
|
+
|
|
11
|
+
layout:
|
|
12
|
+
type: scroll_vertical
|
|
13
|
+
sections:
|
|
14
|
+
- id: notification_list
|
|
15
|
+
contract: collection
|
|
16
|
+
variant: list
|
|
17
|
+
props:
|
|
18
|
+
data: "notifications"
|
|
19
|
+
item_contract: data_display
|
|
20
|
+
item_props_map:
|
|
21
|
+
title: "item.actor.display_name"
|
|
22
|
+
subtitle: "item.message"
|
|
23
|
+
leading: "item.actor.avatar_url"
|
|
24
|
+
metadata:
|
|
25
|
+
timestamp: "{item.created_at | format:date_relative}"
|
|
26
|
+
action:
|
|
27
|
+
type: api_call
|
|
28
|
+
endpoint: "api.notifications.markRead"
|
|
29
|
+
params: { id: "{item.id}" }
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
post_detail:
|
|
2
|
+
semantic: "Full post view with comments thread and interaction actions"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
params:
|
|
6
|
+
post_id: { type: string, required: true }
|
|
7
|
+
|
|
8
|
+
data:
|
|
9
|
+
post:
|
|
10
|
+
source: "api.posts.getById"
|
|
11
|
+
params: { id: "params.post_id" }
|
|
12
|
+
loading: { skeleton: true }
|
|
13
|
+
comments:
|
|
14
|
+
source: "api.posts.comments"
|
|
15
|
+
params: { id: "params.post_id" }
|
|
16
|
+
loading: { skeleton: true, count: 3 }
|
|
17
|
+
empty: { message: "$t:post.no_comments" }
|
|
18
|
+
|
|
19
|
+
state:
|
|
20
|
+
comment_text: { type: string, default: "" }
|
|
21
|
+
|
|
22
|
+
layout:
|
|
23
|
+
type: scroll_vertical
|
|
24
|
+
sections:
|
|
25
|
+
- id: post_content
|
|
26
|
+
contract: data_display
|
|
27
|
+
variant: hero
|
|
28
|
+
props:
|
|
29
|
+
title: "{post.author.display_name}"
|
|
30
|
+
subtitle: "@{post.author.handle}"
|
|
31
|
+
body: "{post.body}"
|
|
32
|
+
media: "{post.media_url}"
|
|
33
|
+
leading: "{post.author.avatar_url}"
|
|
34
|
+
metadata:
|
|
35
|
+
like_count: "{post.like_count | format:number}"
|
|
36
|
+
comment_count: "{post.comment_count | format:number}"
|
|
37
|
+
timestamp: "{post.published_at | format:date}"
|
|
38
|
+
action:
|
|
39
|
+
type: navigate
|
|
40
|
+
destination: "screens/profile_user"
|
|
41
|
+
params: { user_id: "{post.author_id}" }
|
|
42
|
+
|
|
43
|
+
- id: post_actions
|
|
44
|
+
contract: action_trigger
|
|
45
|
+
variant: secondary
|
|
46
|
+
props:
|
|
47
|
+
label: "$t:post.like_action"
|
|
48
|
+
icon: "like"
|
|
49
|
+
action:
|
|
50
|
+
type: api_call
|
|
51
|
+
endpoint: "api.posts.toggleLike"
|
|
52
|
+
params: { id: "params.post_id" }
|
|
53
|
+
|
|
54
|
+
- id: comments_list
|
|
55
|
+
header: "$t:post.comments_header"
|
|
56
|
+
contract: collection
|
|
57
|
+
variant: list
|
|
58
|
+
props:
|
|
59
|
+
data: "comments"
|
|
60
|
+
item_contract: data_display
|
|
61
|
+
item_props_map:
|
|
62
|
+
title: "item.author.display_name"
|
|
63
|
+
body: "item.body"
|
|
64
|
+
leading: "item.author.avatar_url"
|
|
65
|
+
metadata:
|
|
66
|
+
timestamp: "{item.created_at | format:date_relative}"
|
|
67
|
+
action:
|
|
68
|
+
type: navigate
|
|
69
|
+
destination: "screens/profile_user"
|
|
70
|
+
params: { user_id: "{item.author_id}" }
|
|
71
|
+
|
|
72
|
+
- id: comment_input
|
|
73
|
+
contract: input_field
|
|
74
|
+
input_type: text
|
|
75
|
+
props:
|
|
76
|
+
label: "$t:post.comment_placeholder"
|
|
77
|
+
value: "state.comment_text"
|
|
78
|
+
multiline: true
|
|
79
|
+
trailing_action:
|
|
80
|
+
icon: "send"
|
|
81
|
+
action:
|
|
82
|
+
type: sequence
|
|
83
|
+
actions:
|
|
84
|
+
- { type: api_call, endpoint: "api.posts.comments", method: POST, body: { body: "state.comment_text", post_id: "params.post_id" } }
|
|
85
|
+
- { type: set_state, key: "comment_text", value: "" }
|
|
86
|
+
- { type: feedback, variant: toast, message: "$t:post.comment_sent" }
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
profile_self:
|
|
2
|
+
semantic: "Current user's own profile with posts, stats, and edit action"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
data:
|
|
6
|
+
profile:
|
|
7
|
+
source: "api.profiles.me"
|
|
8
|
+
loading: { skeleton: true }
|
|
9
|
+
posts:
|
|
10
|
+
source: "api.profiles.myPosts"
|
|
11
|
+
loading: { skeleton: true, count: 3 }
|
|
12
|
+
empty: { message: "$t:profile.no_posts_self" }
|
|
13
|
+
|
|
14
|
+
layout:
|
|
15
|
+
type: scroll_vertical
|
|
16
|
+
sections:
|
|
17
|
+
- id: profile_header
|
|
18
|
+
contract: data_display
|
|
19
|
+
variant: hero
|
|
20
|
+
props:
|
|
21
|
+
title: "{profile.display_name}"
|
|
22
|
+
subtitle: "@{profile.handle}"
|
|
23
|
+
body: "{profile.bio}"
|
|
24
|
+
leading: "{profile.avatar_url}"
|
|
25
|
+
trailing:
|
|
26
|
+
contract: action_trigger
|
|
27
|
+
variant: secondary
|
|
28
|
+
props:
|
|
29
|
+
label: "$t:profile.edit_button"
|
|
30
|
+
icon: "edit"
|
|
31
|
+
action:
|
|
32
|
+
type: navigate
|
|
33
|
+
destination: "screens/edit_profile"
|
|
34
|
+
|
|
35
|
+
- id: user_posts
|
|
36
|
+
header: "$t:profile.posts_header"
|
|
37
|
+
contract: collection
|
|
38
|
+
variant: list
|
|
39
|
+
props:
|
|
40
|
+
data: "posts"
|
|
41
|
+
item_contract: data_display
|
|
42
|
+
item_props_map:
|
|
43
|
+
title: "item.author.display_name"
|
|
44
|
+
body: "item.body"
|
|
45
|
+
media: "item.media_url"
|
|
46
|
+
metadata:
|
|
47
|
+
like_count: "{item.like_count | format:number}"
|
|
48
|
+
comment_count: "{item.comment_count | format:number}"
|
|
49
|
+
timestamp: "{item.published_at | format:date_relative}"
|
|
50
|
+
action:
|
|
51
|
+
type: navigate
|
|
52
|
+
destination: "screens/post_detail"
|
|
53
|
+
params: { post_id: "{item.id}" }
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
profile_user:
|
|
2
|
+
semantic: "Another user's profile with their posts and follow action"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
params:
|
|
6
|
+
user_id: { type: string, required: true }
|
|
7
|
+
|
|
8
|
+
data:
|
|
9
|
+
profile:
|
|
10
|
+
source: "api.profiles.getById"
|
|
11
|
+
params: { id: "params.user_id" }
|
|
12
|
+
loading: { skeleton: true }
|
|
13
|
+
posts:
|
|
14
|
+
source: "api.profiles.posts"
|
|
15
|
+
params: { id: "params.user_id" }
|
|
16
|
+
loading: { skeleton: true, count: 3 }
|
|
17
|
+
empty: { message: "$t:profile.no_posts_user" }
|
|
18
|
+
|
|
19
|
+
layout:
|
|
20
|
+
type: scroll_vertical
|
|
21
|
+
sections:
|
|
22
|
+
- id: profile_header
|
|
23
|
+
contract: data_display
|
|
24
|
+
variant: hero
|
|
25
|
+
props:
|
|
26
|
+
title: "{profile.display_name}"
|
|
27
|
+
subtitle: "@{profile.handle}"
|
|
28
|
+
body: "{profile.bio}"
|
|
29
|
+
leading: "{profile.avatar_url}"
|
|
30
|
+
trailing:
|
|
31
|
+
contract: action_trigger
|
|
32
|
+
variant: primary
|
|
33
|
+
props:
|
|
34
|
+
label: "$t:profile.follow_button"
|
|
35
|
+
action:
|
|
36
|
+
type: api_call
|
|
37
|
+
endpoint: "api.profiles.follow"
|
|
38
|
+
params: { id: "params.user_id" }
|
|
39
|
+
|
|
40
|
+
- id: user_posts
|
|
41
|
+
header: "$t:profile.posts_header"
|
|
42
|
+
contract: collection
|
|
43
|
+
variant: list
|
|
44
|
+
props:
|
|
45
|
+
data: "posts"
|
|
46
|
+
item_contract: data_display
|
|
47
|
+
item_props_map:
|
|
48
|
+
title: "item.author.display_name"
|
|
49
|
+
subtitle: "@{item.author.handle}"
|
|
50
|
+
body: "item.body"
|
|
51
|
+
media: "item.media_url"
|
|
52
|
+
leading: "item.author.avatar_url"
|
|
53
|
+
metadata:
|
|
54
|
+
like_count: "{item.like_count | format:number}"
|
|
55
|
+
comment_count: "{item.comment_count | format:number}"
|
|
56
|
+
timestamp: "{item.published_at | format:date_relative}"
|
|
57
|
+
action:
|
|
58
|
+
type: navigate
|
|
59
|
+
destination: "screens/post_detail"
|
|
60
|
+
params: { post_id: "{item.id}" }
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
search_results:
|
|
2
|
+
semantic: "Search results with tabbed views for posts, people, and tags"
|
|
3
|
+
status: draft
|
|
4
|
+
|
|
5
|
+
params:
|
|
6
|
+
query: { type: string, required: true }
|
|
7
|
+
tab: { type: string, default: "posts" }
|
|
8
|
+
|
|
9
|
+
data:
|
|
10
|
+
results:
|
|
11
|
+
source: "api.discover.search"
|
|
12
|
+
params:
|
|
13
|
+
query: "params.query"
|
|
14
|
+
tab: "state.active_tab"
|
|
15
|
+
loading: { skeleton: true, count: 5 }
|
|
16
|
+
empty: { message: "$t:search.no_results" }
|
|
17
|
+
|
|
18
|
+
state:
|
|
19
|
+
active_tab:
|
|
20
|
+
type: enum
|
|
21
|
+
values: [posts, people, tags]
|
|
22
|
+
default: "params.tab"
|
|
23
|
+
|
|
24
|
+
layout:
|
|
25
|
+
type: scroll_vertical
|
|
26
|
+
sections:
|
|
27
|
+
- id: search_bar
|
|
28
|
+
contract: input_field
|
|
29
|
+
input_type: text
|
|
30
|
+
props:
|
|
31
|
+
label: "$t:search.placeholder"
|
|
32
|
+
value: "params.query"
|
|
33
|
+
icon: "search"
|
|
34
|
+
|
|
35
|
+
- id: tab_bar
|
|
36
|
+
contract: collection
|
|
37
|
+
variant: chip_row
|
|
38
|
+
props:
|
|
39
|
+
data: "state.active_tab"
|
|
40
|
+
item_contract: action_trigger
|
|
41
|
+
item_props_map:
|
|
42
|
+
label: "item.label"
|
|
43
|
+
options:
|
|
44
|
+
- { value: "posts", label: "$t:search.tab_posts" }
|
|
45
|
+
- { value: "people", label: "$t:search.tab_people" }
|
|
46
|
+
- { value: "tags", label: "$t:search.tab_tags" }
|
|
47
|
+
|
|
48
|
+
- id: results_list
|
|
49
|
+
contract: collection
|
|
50
|
+
variant: list
|
|
51
|
+
props:
|
|
52
|
+
data: "results"
|
|
53
|
+
item_contract: data_display
|
|
54
|
+
item_props_map:
|
|
55
|
+
title: "item.title"
|
|
56
|
+
subtitle: "item.subtitle"
|
|
57
|
+
body: "item.body"
|
|
58
|
+
leading: "item.avatar_url"
|
|
59
|
+
action:
|
|
60
|
+
type: navigate
|
|
61
|
+
destination: "screens/post_detail"
|
|
62
|
+
params: { post_id: "{item.id}" }
|