@tthr/vue 0.0.8 → 0.0.10
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/dist/index.d.ts +23 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/nuxt/runtime/components/TetherWelcome.vue +357 -24
- package/nuxt/runtime/composables.ts +8 -0
- package/nuxt/runtime/server/mutation.post.ts +1 -1
- package/nuxt/runtime/server/query.post.ts +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,22 @@ export interface MutationFunction<TArgs = void, TResult = unknown> {
|
|
|
65
65
|
_args?: TArgs;
|
|
66
66
|
_result?: TResult;
|
|
67
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Options for useMutation
|
|
70
|
+
*/
|
|
71
|
+
export interface UseMutationOptions {
|
|
72
|
+
/**
|
|
73
|
+
* Query names to invalidate after mutation succeeds.
|
|
74
|
+
* This will trigger a refetch for all active subscriptions matching these queries.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* // When creating a comment, also refresh the posts list to update comment counts
|
|
78
|
+
* const createComment = useMutation(api.comments.create, {
|
|
79
|
+
* invalidates: ['posts.list', 'posts.byId']
|
|
80
|
+
* });
|
|
81
|
+
*/
|
|
82
|
+
invalidates?: string[];
|
|
83
|
+
}
|
|
68
84
|
/**
|
|
69
85
|
* Mutation composable
|
|
70
86
|
*
|
|
@@ -76,11 +92,16 @@ export interface MutationFunction<TArgs = void, TResult = unknown> {
|
|
|
76
92
|
*
|
|
77
93
|
* const createPost = useMutation(api.posts.create);
|
|
78
94
|
* await createPost.mutate({ title: 'Hello', content: '...' });
|
|
95
|
+
*
|
|
96
|
+
* // With query invalidation - refreshes posts list when a comment is added
|
|
97
|
+
* const createComment = useMutation(api.comments.create, {
|
|
98
|
+
* invalidates: ['posts.list']
|
|
99
|
+
* });
|
|
79
100
|
* </script>
|
|
80
101
|
* ```
|
|
81
102
|
*/
|
|
82
|
-
export declare function useMutation<TArgs, TResult>(mutation: MutationFunction<TArgs, TResult
|
|
83
|
-
export type { TetherClientOptions } from '@tthr/client';
|
|
103
|
+
export declare function useMutation<TArgs, TResult>(mutation: MutationFunction<TArgs, TResult>, options?: UseMutationOptions): MutationState<TArgs, TResult>;
|
|
104
|
+
export type { TetherClientOptions, MutationOptions } from '@tthr/client';
|
|
84
105
|
/**
|
|
85
106
|
* Tether Nuxt/Vue project configuration
|
|
86
107
|
*/
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAA+B,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAKtE;;GAEG;AACH,eAAO,MAAM,YAAY;iBACV,GAAG,WAAW,mBAAmB;uBAK3B,mBAAmB;CAGvC,CAAC;AAEF;;GAEG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAKxC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzB,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EACrC,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,EACpC,IAAI,CAAC,EAAE,KAAK,GACX,UAAU,CAAC,OAAO,CAAC,CA4CrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,OAAO;IAC3C,IAAI,EAAE,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC/B,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAA+B,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAKtE;;GAEG;AACH,eAAO,MAAM,YAAY;iBACV,GAAG,WAAW,mBAAmB;uBAK3B,mBAAmB;CAGvC,CAAC;AAEF;;GAEG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAKxC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzB,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EACrC,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,EACpC,IAAI,CAAC,EAAE,KAAK,GACX,UAAU,CAAC,OAAO,CAAC,CA4CrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,OAAO;IAC3C,IAAI,EAAE,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC/B,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EACxC,QAAQ,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,EAC1C,OAAO,CAAC,EAAE,kBAAkB,GAC3B,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAqC/B;AAGD,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAE/D"}
|
package/dist/index.js
CHANGED
|
@@ -92,10 +92,15 @@ export function useQuery(query, args) {
|
|
|
92
92
|
*
|
|
93
93
|
* const createPost = useMutation(api.posts.create);
|
|
94
94
|
* await createPost.mutate({ title: 'Hello', content: '...' });
|
|
95
|
+
*
|
|
96
|
+
* // With query invalidation - refreshes posts list when a comment is added
|
|
97
|
+
* const createComment = useMutation(api.comments.create, {
|
|
98
|
+
* invalidates: ['posts.list']
|
|
99
|
+
* });
|
|
95
100
|
* </script>
|
|
96
101
|
* ```
|
|
97
102
|
*/
|
|
98
|
-
export function useMutation(mutation) {
|
|
103
|
+
export function useMutation(mutation, options) {
|
|
99
104
|
const data = ref();
|
|
100
105
|
const error = ref(null);
|
|
101
106
|
const isPending = ref(false);
|
|
@@ -104,7 +109,9 @@ export function useMutation(mutation) {
|
|
|
104
109
|
isPending.value = true;
|
|
105
110
|
error.value = null;
|
|
106
111
|
const client = useTether();
|
|
107
|
-
const result = await client.mutation(mutation._name, args
|
|
112
|
+
const result = await client.mutation(mutation._name, args, {
|
|
113
|
+
invalidates: options?.invalidates,
|
|
114
|
+
});
|
|
108
115
|
data.value = result;
|
|
109
116
|
return result;
|
|
110
117
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAsB,MAAM,KAAK,CAAC;AACtE,OAAO,EAAE,YAAY,EAA4B,MAAM,cAAc,CAAC;AAEtE,yBAAyB;AACzB,IAAI,YAAY,GAAwB,IAAI,CAAC;AAE7C;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,OAAO,CAAC,GAAQ,EAAE,OAA4B;QAC5C,YAAY,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;QACzC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACtC,CAAC;IAED,SAAS,CAAC,OAA4B;QACpC,YAAY,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAqBD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAoC,EACpC,IAAY;IAEZ,MAAM,IAAI,GAAG,GAAG,EAAW,CAAC;IAC5B,MAAM,KAAK,GAAG,GAAG,CAAe,IAAI,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;IAE5B,IAAI,WAAW,GAAwB,IAAI,CAAC;IAE5C,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE;QAC3B,IAAI,CAAC;YACH,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;YACvB,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;YAEnB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACrD,IAAI,CAAC,KAAK,GAAG,MAAiB,CAAC;QACjC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,KAAK,CAAC,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,KAAK,GAAG,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC,CAAC;IAEF,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,SAAS,EAAE,CAAC;QAElB,uBAAuB;QACvB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE;YAC5D,IAAI,CAAC,KAAK,GAAG,OAAkB,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,WAAW,CAAC,GAAG,EAAE;QACf,IAAI,WAAW,EAAE,CAAC;YAChB,WAAW,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,IAAgC;QACtC,KAAK;QACL,SAAS;QACT,OAAO,EAAE,SAAS;KACnB,CAAC;AACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,21 +53,84 @@
|
|
|
53
53
|
v-for="post in posts.data.value"
|
|
54
54
|
:key="post.id"
|
|
55
55
|
class="tether-welcome__post"
|
|
56
|
+
:class="{ 'tether-welcome__post--expanded': expandedPostId === post.id }"
|
|
56
57
|
>
|
|
57
|
-
<div class="tether-welcome__post-
|
|
58
|
-
<
|
|
59
|
-
|
|
58
|
+
<div class="tether-welcome__post-header">
|
|
59
|
+
<div class="tether-welcome__post-content">
|
|
60
|
+
<h3>{{ post.title }}</h3>
|
|
61
|
+
<time>{{ formatDate(post.createdAt) }}</time>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="tether-welcome__post-actions">
|
|
64
|
+
<button
|
|
65
|
+
class="tether-welcome__post-comment-toggle"
|
|
66
|
+
@click="toggleComments(post.id)"
|
|
67
|
+
title="Toggle comments"
|
|
68
|
+
>
|
|
69
|
+
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
70
|
+
<path fill-rule="evenodd" d="M18 10c0 3.866-3.582 7-8 7a8.841 8.841 0 01-4.083-.98L2 17l1.338-3.123C2.493 12.767 2 11.434 2 10c0-3.866 3.582-7 8-7s8 3.134 8 7zM7 9H5v2h2V9zm8 0h-2v2h2V9zM9 9h2v2H9V9z" clip-rule="evenodd" />
|
|
71
|
+
</svg>
|
|
72
|
+
<span v-if="getCommentCount(post.id) > 0">{{ getCommentCount(post.id) }}</span>
|
|
73
|
+
</button>
|
|
74
|
+
<button
|
|
75
|
+
class="tether-welcome__post-delete"
|
|
76
|
+
@click="handleDeletePost(post.id)"
|
|
77
|
+
:disabled="deletePost.isPending.value"
|
|
78
|
+
title="Delete post"
|
|
79
|
+
>
|
|
80
|
+
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
81
|
+
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
|
|
82
|
+
</svg>
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<!-- Comments section -->
|
|
88
|
+
<div v-if="expandedPostId === post.id" class="tether-welcome__comments">
|
|
89
|
+
<form class="tether-welcome__comment-form" @submit.prevent="handleCreateComment(post.id)">
|
|
90
|
+
<input
|
|
91
|
+
v-model="newCommentText"
|
|
92
|
+
type="text"
|
|
93
|
+
placeholder="Add a comment..."
|
|
94
|
+
class="tether-welcome__comment-input"
|
|
95
|
+
:disabled="createComment.isPending.value"
|
|
96
|
+
/>
|
|
97
|
+
<button
|
|
98
|
+
type="submit"
|
|
99
|
+
class="tether-welcome__comment-submit"
|
|
100
|
+
:disabled="!newCommentText.trim() || createComment.isPending.value"
|
|
101
|
+
>
|
|
102
|
+
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
103
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-8.707l-3-3a1 1 0 00-1.414 1.414L10.586 9H7a1 1 0 100 2h3.586l-1.293 1.293a1 1 0 101.414 1.414l3-3a1 1 0 000-1.414z" clip-rule="evenodd" />
|
|
104
|
+
</svg>
|
|
105
|
+
</button>
|
|
106
|
+
</form>
|
|
107
|
+
|
|
108
|
+
<div class="tether-welcome__comment-list">
|
|
109
|
+
<div
|
|
110
|
+
v-for="comment in postComments[post.id] || []"
|
|
111
|
+
:key="comment.id"
|
|
112
|
+
class="tether-welcome__comment"
|
|
113
|
+
>
|
|
114
|
+
<p>{{ comment.content }}</p>
|
|
115
|
+
<div class="tether-welcome__comment-meta">
|
|
116
|
+
<time>{{ formatDate(comment.createdAt) }}</time>
|
|
117
|
+
<button
|
|
118
|
+
class="tether-welcome__comment-delete"
|
|
119
|
+
@click="handleDeleteComment(comment.id, post.id)"
|
|
120
|
+
:disabled="deleteComment.isPending.value"
|
|
121
|
+
title="Delete comment"
|
|
122
|
+
>
|
|
123
|
+
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
124
|
+
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
|
125
|
+
</svg>
|
|
126
|
+
</button>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
<p v-if="!postComments[post.id]?.length" class="tether-welcome__no-comments">
|
|
130
|
+
No comments yet
|
|
131
|
+
</p>
|
|
132
|
+
</div>
|
|
60
133
|
</div>
|
|
61
|
-
<button
|
|
62
|
-
class="tether-welcome__post-delete"
|
|
63
|
-
@click="handleDeletePost(post.id)"
|
|
64
|
-
:disabled="deletePost.isPending.value"
|
|
65
|
-
title="Delete post"
|
|
66
|
-
>
|
|
67
|
-
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
68
|
-
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
|
|
69
|
-
</svg>
|
|
70
|
-
</button>
|
|
71
134
|
</article>
|
|
72
135
|
</template>
|
|
73
136
|
<p v-else class="tether-welcome__empty">
|
|
@@ -117,18 +180,116 @@ interface Post {
|
|
|
117
180
|
updatedAt: string;
|
|
118
181
|
}
|
|
119
182
|
|
|
183
|
+
interface Comment {
|
|
184
|
+
id: string;
|
|
185
|
+
postId: string;
|
|
186
|
+
content: string;
|
|
187
|
+
authorId: string;
|
|
188
|
+
createdAt: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
120
191
|
const newPostTitle = ref('');
|
|
192
|
+
const expandedPostId = ref<string | null>(null);
|
|
193
|
+
const newCommentText = ref('');
|
|
194
|
+
const postComments = ref<Record<string, Comment[]>>({});
|
|
121
195
|
|
|
122
196
|
// Set up queries and mutations (these use SSR-safe server routes)
|
|
123
197
|
const posts = useQuery<void, Post[]>('posts.list');
|
|
124
198
|
const createPost = useMutation<{ title: string; content?: string }, { id: string }>('posts.create');
|
|
125
199
|
const deletePost = useMutation<{ id: string }, void>('posts.remove');
|
|
200
|
+
const createComment = useMutation<{ postId: string; content: string }, { id: string }>('comments.create');
|
|
201
|
+
const deleteComment = useMutation<{ id: string }, void>('comments.remove');
|
|
126
202
|
|
|
127
203
|
// Set up WebSocket subscription for realtime updates (client-side only)
|
|
128
|
-
|
|
129
|
-
|
|
204
|
+
// Uses setData to hot-swap data without full reload
|
|
205
|
+
const { isConnected } = useTetherSubscription('posts.list', undefined, (data) => {
|
|
206
|
+
if (data && Array.isArray(data)) {
|
|
207
|
+
posts.setData(data as Post[]);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Subscribe to comments updates
|
|
212
|
+
useTetherSubscription('comments.list', undefined, (data) => {
|
|
213
|
+
if (data && Array.isArray(data)) {
|
|
214
|
+
// Group comments by postId
|
|
215
|
+
const grouped: Record<string, Comment[]> = {};
|
|
216
|
+
for (const comment of data as Comment[]) {
|
|
217
|
+
if (!grouped[comment.postId]) {
|
|
218
|
+
grouped[comment.postId] = [];
|
|
219
|
+
}
|
|
220
|
+
grouped[comment.postId].push(comment);
|
|
221
|
+
}
|
|
222
|
+
postComments.value = grouped;
|
|
223
|
+
}
|
|
130
224
|
});
|
|
131
225
|
|
|
226
|
+
async function toggleComments(postId: string) {
|
|
227
|
+
if (expandedPostId.value === postId) {
|
|
228
|
+
expandedPostId.value = null;
|
|
229
|
+
} else {
|
|
230
|
+
expandedPostId.value = postId;
|
|
231
|
+
// Load comments for this post if not already loaded
|
|
232
|
+
if (!postComments.value[postId]) {
|
|
233
|
+
try {
|
|
234
|
+
const response = await $fetch<{ data: Comment[] }>('/api/_tether/query', {
|
|
235
|
+
method: 'POST',
|
|
236
|
+
body: {
|
|
237
|
+
function: 'comments.listByPost',
|
|
238
|
+
args: { postId },
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
postComments.value[postId] = response.data || [];
|
|
242
|
+
} catch {
|
|
243
|
+
postComments.value[postId] = [];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function handleCreateComment(postId: string) {
|
|
250
|
+
if (!newCommentText.value.trim()) return;
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
await createComment.mutate({
|
|
254
|
+
postId,
|
|
255
|
+
content: newCommentText.value.trim(),
|
|
256
|
+
});
|
|
257
|
+
newCommentText.value = '';
|
|
258
|
+
// Refresh comments for this post
|
|
259
|
+
const response = await $fetch<{ data: Comment[] }>('/api/_tether/query', {
|
|
260
|
+
method: 'POST',
|
|
261
|
+
body: {
|
|
262
|
+
function: 'comments.listByPost',
|
|
263
|
+
args: { postId },
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
postComments.value[postId] = response.data || [];
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.error('Failed to create comment:', error);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async function handleDeleteComment(commentId: string, postId: string) {
|
|
273
|
+
try {
|
|
274
|
+
await deleteComment.mutate({ id: commentId });
|
|
275
|
+
// Refresh comments for this post
|
|
276
|
+
const response = await $fetch<{ data: Comment[] }>('/api/_tether/query', {
|
|
277
|
+
method: 'POST',
|
|
278
|
+
body: {
|
|
279
|
+
function: 'comments.listByPost',
|
|
280
|
+
args: { postId },
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
postComments.value[postId] = response.data || [];
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error('Failed to delete comment:', error);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function getCommentCount(postId: string): number {
|
|
290
|
+
return postComments.value[postId]?.length || 0;
|
|
291
|
+
}
|
|
292
|
+
|
|
132
293
|
async function handleCreatePost() {
|
|
133
294
|
if (!newPostTitle.value.trim()) return;
|
|
134
295
|
|
|
@@ -165,9 +326,15 @@ function formatDate(dateString: string): string {
|
|
|
165
326
|
}
|
|
166
327
|
</script>
|
|
167
328
|
|
|
329
|
+
<style>
|
|
330
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
331
|
+
body { padding: 0; margin: 0; height: 100dvh; }
|
|
332
|
+
#__nuxt { height: 100dvh; }
|
|
333
|
+
</style>
|
|
334
|
+
|
|
168
335
|
<style scoped>
|
|
169
336
|
.tether-welcome {
|
|
170
|
-
min-height:
|
|
337
|
+
min-height: 100dvh;
|
|
171
338
|
background: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 50%, #16213e 100%);
|
|
172
339
|
color: #e4e4e7;
|
|
173
340
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
@@ -200,10 +367,7 @@ function formatDate(dateString: string): string {
|
|
|
200
367
|
font-size: 2.5rem;
|
|
201
368
|
font-weight: 700;
|
|
202
369
|
margin: 0;
|
|
203
|
-
|
|
204
|
-
-webkit-background-clip: text;
|
|
205
|
-
-webkit-text-fill-color: transparent;
|
|
206
|
-
background-clip: text;
|
|
370
|
+
color: #f4f4f5;
|
|
207
371
|
}
|
|
208
372
|
|
|
209
373
|
.tether-welcome__subtitle {
|
|
@@ -342,20 +506,32 @@ function formatDate(dateString: string): string {
|
|
|
342
506
|
|
|
343
507
|
.tether-welcome__post {
|
|
344
508
|
display: flex;
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
padding: 0.875rem 1rem;
|
|
509
|
+
flex-direction: column;
|
|
510
|
+
gap: 0;
|
|
511
|
+
padding: 0;
|
|
349
512
|
background: rgba(0, 0, 0, 0.2);
|
|
350
513
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
351
514
|
border-radius: 0.5rem;
|
|
352
515
|
transition: background 0.2s;
|
|
516
|
+
overflow: hidden;
|
|
353
517
|
}
|
|
354
518
|
|
|
355
519
|
.tether-welcome__post:hover {
|
|
356
520
|
background: rgba(0, 0, 0, 0.3);
|
|
357
521
|
}
|
|
358
522
|
|
|
523
|
+
.tether-welcome__post--expanded {
|
|
524
|
+
background: rgba(0, 0, 0, 0.3);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.tether-welcome__post-header {
|
|
528
|
+
display: flex;
|
|
529
|
+
align-items: center;
|
|
530
|
+
justify-content: space-between;
|
|
531
|
+
gap: 1rem;
|
|
532
|
+
padding: 0.875rem 1rem;
|
|
533
|
+
}
|
|
534
|
+
|
|
359
535
|
.tether-welcome__post-content {
|
|
360
536
|
flex: 1;
|
|
361
537
|
min-width: 0;
|
|
@@ -376,6 +552,36 @@ function formatDate(dateString: string): string {
|
|
|
376
552
|
color: #71717a;
|
|
377
553
|
}
|
|
378
554
|
|
|
555
|
+
.tether-welcome__post-actions {
|
|
556
|
+
display: flex;
|
|
557
|
+
gap: 0.25rem;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.tether-welcome__post-comment-toggle {
|
|
561
|
+
flex-shrink: 0;
|
|
562
|
+
display: flex;
|
|
563
|
+
align-items: center;
|
|
564
|
+
gap: 0.25rem;
|
|
565
|
+
padding: 0.375rem 0.5rem;
|
|
566
|
+
background: transparent;
|
|
567
|
+
border: none;
|
|
568
|
+
border-radius: 0.375rem;
|
|
569
|
+
color: #71717a;
|
|
570
|
+
font-size: 0.75rem;
|
|
571
|
+
cursor: pointer;
|
|
572
|
+
transition: color 0.2s, background 0.2s;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.tether-welcome__post-comment-toggle:hover {
|
|
576
|
+
color: #a1a1aa;
|
|
577
|
+
background: rgba(255, 255, 255, 0.05);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
.tether-welcome__post-comment-toggle svg {
|
|
581
|
+
width: 16px;
|
|
582
|
+
height: 16px;
|
|
583
|
+
}
|
|
584
|
+
|
|
379
585
|
.tether-welcome__post-delete {
|
|
380
586
|
flex-shrink: 0;
|
|
381
587
|
width: 32px;
|
|
@@ -406,6 +612,133 @@ function formatDate(dateString: string): string {
|
|
|
406
612
|
height: 18px;
|
|
407
613
|
}
|
|
408
614
|
|
|
615
|
+
/* Comments styles */
|
|
616
|
+
.tether-welcome__comments {
|
|
617
|
+
padding: 0.75rem 1rem 1rem;
|
|
618
|
+
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
|
619
|
+
background: rgba(0, 0, 0, 0.15);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
.tether-welcome__comment-form {
|
|
623
|
+
display: flex;
|
|
624
|
+
gap: 0.5rem;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.tether-welcome__comment-input {
|
|
628
|
+
flex: 1;
|
|
629
|
+
padding: 0.5rem 0.75rem;
|
|
630
|
+
background: rgba(0, 0, 0, 0.3);
|
|
631
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
632
|
+
border-radius: 0.375rem;
|
|
633
|
+
color: #e4e4e7;
|
|
634
|
+
font-size: 0.8125rem;
|
|
635
|
+
outline: none;
|
|
636
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.tether-welcome__comment-input:focus {
|
|
640
|
+
border-color: #6366f1;
|
|
641
|
+
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
.tether-welcome__comment-input::placeholder {
|
|
645
|
+
color: #71717a;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.tether-welcome__comment-submit {
|
|
649
|
+
display: flex;
|
|
650
|
+
align-items: center;
|
|
651
|
+
justify-content: center;
|
|
652
|
+
width: 32px;
|
|
653
|
+
height: 32px;
|
|
654
|
+
background: #6366f1;
|
|
655
|
+
border: none;
|
|
656
|
+
border-radius: 0.375rem;
|
|
657
|
+
color: white;
|
|
658
|
+
cursor: pointer;
|
|
659
|
+
transition: opacity 0.2s;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.tether-welcome__comment-submit:hover:not(:disabled) {
|
|
663
|
+
opacity: 0.9;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.tether-welcome__comment-submit:disabled {
|
|
667
|
+
opacity: 0.5;
|
|
668
|
+
cursor: not-allowed;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.tether-welcome__comment-submit svg {
|
|
672
|
+
width: 16px;
|
|
673
|
+
height: 16px;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.tether-welcome__comment-list {
|
|
677
|
+
display: flex;
|
|
678
|
+
flex-direction: column;
|
|
679
|
+
gap: 0.5rem;
|
|
680
|
+
padding-top: 0.75rem;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.tether-welcome__comment {
|
|
684
|
+
padding: 0.5rem 0.75rem;
|
|
685
|
+
background: rgba(255, 255, 255, 0.03);
|
|
686
|
+
border-radius: 0.375rem;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.tether-welcome__comment p {
|
|
690
|
+
margin: 0 0 0.25rem 0;
|
|
691
|
+
font-size: 0.8125rem;
|
|
692
|
+
color: #e4e4e7;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.tether-welcome__comment-meta {
|
|
696
|
+
display: flex;
|
|
697
|
+
align-items: center;
|
|
698
|
+
justify-content: space-between;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.tether-welcome__comment-meta time {
|
|
702
|
+
font-size: 0.6875rem;
|
|
703
|
+
color: #71717a;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.tether-welcome__comment-delete {
|
|
707
|
+
display: flex;
|
|
708
|
+
align-items: center;
|
|
709
|
+
justify-content: center;
|
|
710
|
+
width: 20px;
|
|
711
|
+
height: 20px;
|
|
712
|
+
background: transparent;
|
|
713
|
+
border: none;
|
|
714
|
+
border-radius: 0.25rem;
|
|
715
|
+
color: #71717a;
|
|
716
|
+
cursor: pointer;
|
|
717
|
+
transition: color 0.2s;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.tether-welcome__comment-delete:hover:not(:disabled) {
|
|
721
|
+
color: #ef4444;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.tether-welcome__comment-delete:disabled {
|
|
725
|
+
opacity: 0.5;
|
|
726
|
+
cursor: not-allowed;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.tether-welcome__comment-delete svg {
|
|
730
|
+
width: 12px;
|
|
731
|
+
height: 12px;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
.tether-welcome__no-comments {
|
|
735
|
+
margin: 0;
|
|
736
|
+
padding: 0.5rem;
|
|
737
|
+
text-align: center;
|
|
738
|
+
font-size: 0.75rem;
|
|
739
|
+
color: #71717a;
|
|
740
|
+
}
|
|
741
|
+
|
|
409
742
|
.tether-welcome__links {
|
|
410
743
|
display: flex;
|
|
411
744
|
justify-content: center;
|
|
@@ -16,6 +16,8 @@ export interface QueryState<T> {
|
|
|
16
16
|
error: Ref<Error | null>;
|
|
17
17
|
isLoading: Ref<boolean>;
|
|
18
18
|
refetch: () => Promise<void>;
|
|
19
|
+
/** Update data directly (used for hot-swapping from WebSocket) */
|
|
20
|
+
setData: (newData: T) => void;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -77,11 +79,17 @@ export function useQuery<TArgs, TResult>(
|
|
|
77
79
|
fetchData();
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
// Direct data setter for hot-swapping from WebSocket
|
|
83
|
+
const setData = (newData: TResult) => {
|
|
84
|
+
data.value = newData;
|
|
85
|
+
};
|
|
86
|
+
|
|
80
87
|
return {
|
|
81
88
|
data: data as Ref<TResult | undefined>,
|
|
82
89
|
error,
|
|
83
90
|
isLoading,
|
|
84
91
|
refetch: fetchData,
|
|
92
|
+
setData,
|
|
85
93
|
};
|
|
86
94
|
}
|
|
87
95
|
|
|
@@ -37,7 +37,7 @@ export default defineEventHandler(async (event) => {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const response = await fetch(`${url}/api/v1/${projectId}/mutation`, {
|
|
40
|
+
const response = await fetch(`${url}/api/v1/projects/${projectId}/mutation`, {
|
|
41
41
|
method: 'POST',
|
|
42
42
|
headers: {
|
|
43
43
|
'Content-Type': 'application/json',
|
|
@@ -37,7 +37,7 @@ export default defineEventHandler(async (event) => {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const response = await fetch(`${url}/api/v1/${projectId}/query`, {
|
|
40
|
+
const response = await fetch(`${url}/api/v1/projects/${projectId}/query`, {
|
|
41
41
|
method: 'POST',
|
|
42
42
|
headers: {
|
|
43
43
|
'Content-Type': 'application/json',
|