Skip to content

Commit 03c4070

Browse files
committed
chore: merge with clean-starter
2 parents 57bb5be + 93ff815 commit 03c4070

File tree

3 files changed

+98
-9
lines changed

3 files changed

+98
-9
lines changed

README.md

+48-1
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,55 @@ Empower Your Lists App with a Robust Backend 🚀
5757

5858
The @state-less/clean-starter repository is designed to provide a starting point for developers exploring React Server. It includes essential backend components, utilities, and examples that illustrate the fundamental concepts and capabilities of React Server.
5959

60+
# React Server
6061
React Server allows the creation of server-side React components using TSX, promoting a component-driven architecture for building robust and maintainable backend solutions. By using @state-less/clean-starter, developers can quickly get started with this innovative approach to full-stack development.
6162

63+
```tsx
64+
import { Scopes, useState, clientKey } from '@state-less/react-server';
65+
import { ServerSideProps } from './ServerSideProps';
66+
67+
export const HelloWorldExample2 = (props, { key, context }) => {
68+
// The useState hook looks familiar?
69+
const [count, setState] = useState(0, {
70+
key: "count",
71+
scope: Scopes.Global,
72+
});
73+
74+
// A simple function that can be executed from the client side.
75+
const increase = () => {
76+
setState(count + 1);
77+
};
78+
79+
return (
80+
// Simply pass down props to the client side.
81+
<ServerSideProps
82+
key={clientKey(`${key}-props`, context)}
83+
count={count}
84+
increase={increase}
85+
/>
86+
);
87+
};
88+
```
89+
90+
Use the familiar approach of React to build serverside applications in a declarative way. React has proven to be a successful framework for building large scale applications while keeping a clean state-management solution to provide reactive realtime enabled modern UIs. React favors a clean codebase due to its inherently modular structure and component driven approach. React allows you to cleanly abstract the complexity of modern applications using *states*, *hooks* and *components*.
91+
92+
React Server brings the same flexibility to the server side by giving you a Framework that handles TSX compilation, a small React engine that powers *hooks*, *states* and the lifecycle of *components*. It also abstracts data storage and data transportation into a common concept of *states*. Data is stored in *Stores* which can be accessed by components using *hooks* (`useState`). The `useState` hook provides reactivity and automatically re-renders the component when its value is updated using the setter. Data is transported by consuming server-side states / components on the clientside using the `useComponent` hook. We are using *GraphQL* as transportation layer to provide a robust foundation.
93+
94+
Developers familiar with **React** and JSX components `<Component hello="world" />` are able to jump right into developing full-stack applications. It really works well and provides a seamless reactive experience on both the backend and the frontend. States are synchronized to all connected clients using PUB / SUB.
95+
6296
For detailed documentation and in-depth guides, please visit the official website at [state-less.cloud](https://state-less.cloud).
6397

98+
## Explore Examples
99+
Dive into real-world examples, like the [Lists App](https://lists.state-less.cloud), showcasing the potential of React Server.
100+
101+
## Key Features
102+
103+
- **Server-Side React**: Create server-side React components using TSX for efficient, component-driven backend development.
104+
- **@state-less/clean-starter**: Jumpstart your project with essential backend components, utilities, and examples.
105+
- **Explore the Future**: Harness the power of server-side real-time TSX components.
106+
107+
For comprehensive documentation and detailed guides, visit the official [state-less.cloud](https://state-less.cloud) website.
108+
64109
## Getting Started
65110

66111
### Backend
@@ -175,4 +220,6 @@ _Note: You can still override the provided client if you pass one in the options
175220

176221
That's it, your App is now powered by the same backend as the documentation under [state-less.cloud](https://state-less.cloud).
177222

178-
Happy Hacking!
223+
---------
224+
225+
**License**: This project is under the **MIT License** - see the [LICENSE.md](/LICENSE.txt) file for details.

dist/components/Lists.js

+26-4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ var Todo = function Todo(_ref3, _ref4) {
8181
dueDate = _ref3$dueDate === void 0 ? null : _ref3$dueDate,
8282
_ref3$dueTime = _ref3.dueTime,
8383
dueTime = _ref3$dueTime === void 0 ? null : _ref3$dueTime,
84+
note = _ref3.note,
8485
_changeType = _ref3.changeType,
8586
createdAt = _ref3.createdAt,
8687
color = _ref3.color;
@@ -108,6 +109,7 @@ var Todo = function Todo(_ref3, _ref4) {
108109
valuePoints: valuePoints,
109110
creditedValuePoints: creditedValuePoints,
110111
negativePoints: negativePoints,
112+
note: note,
111113
dueDate: dueDate,
112114
dueTime: dueTime,
113115
type: 'Todo',
@@ -180,6 +182,14 @@ var Todo = function Todo(_ref3, _ref4) {
180182
reset: 1000 * 60 * 60 * reset
181183
}));
182184
};
185+
var setNote = function setNote(note) {
186+
if (typeof note !== 'string' || note.length > 32000) {
187+
throw new Error('Invalid note');
188+
}
189+
setTodo(_objectSpread(_objectSpread({}, todo), {}, {
190+
note: note
191+
}));
192+
};
183193
var setValuePoints = function setValuePoints(valuePoints) {
184194
if (typeof valuePoints !== 'number' && valuePoints < 0 || valuePoints > 100) {
185195
throw new Error('Invalid value points');
@@ -226,6 +236,7 @@ var Todo = function Todo(_ref3, _ref4) {
226236
setTitle: setTitle,
227237
setDueDate: setDueDate,
228238
setDueTime: setDueTime,
239+
setNote: setNote,
229240
type: "Todo",
230241
createdAt: createdAt,
231242
lastModified: todo.lastModified,
@@ -549,7 +560,7 @@ var List = function List(_ref9, _ref10) {
549560
var _user16, _todo$value, _todo$value2;
550561
var store = _reactServer.Dispatcher.getCurrent().getStore();
551562
var todo = store.getState(null, {
552-
key: "todo-".concat(todoId),
563+
key: "todo",
553564
scope: "".concat(todoId, ".").concat(((_user16 = user) === null || _user16 === void 0 ? void 0 : _user16.id) || _reactServer.Scopes.Client)
554565
});
555566
setOrder(order.filter(function (id) {
@@ -559,6 +570,7 @@ var List = function List(_ref9, _ref10) {
559570
return todo.id !== todoId;
560571
}));
561572
points.value = points.value - 1 - (todo !== null && todo !== void 0 && (_todo$value = todo.value) !== null && _todo$value !== void 0 && _todo$value.archived ? 1 : 0) - ((todo === null || todo === void 0 ? void 0 : (_todo$value2 = todo.value) === null || _todo$value2 === void 0 ? void 0 : _todo$value2.valuePoints) || 0);
573+
return todo.value;
562574
};
563575
var addLabel = function addLabel(label) {
564576
var labelId = (0, _uuid.v4)();
@@ -725,6 +737,10 @@ var exportData = function exportData(_ref11) {
725737
key: 'color',
726738
scope: "".concat("list-".concat(list.id), ".", (user === null || user === void 0 ? void 0 : user.id) || clientId)
727739
});
740+
var title = store.getState(null, {
741+
key: 'title',
742+
scope: "".concat("list-".concat(list.id), ".", (user === null || user === void 0 ? void 0 : user.id) || clientId)
743+
});
728744
var settings = store.getState(null, {
729745
key: 'settings',
730746
scope: "".concat("list-".concat(list.id), ".", (user === null || user === void 0 ? void 0 : user.id) || clientId)
@@ -737,6 +753,7 @@ var exportData = function exportData(_ref11) {
737753
Object.assign(todo, stored.value);
738754
});
739755
data[list.id] = _objectSpread(_objectSpread({}, list), {}, {
756+
title: title.value,
740757
color: color.value,
741758
order: order.value,
742759
todos: todos.value,
@@ -786,9 +803,10 @@ var MyLists = function MyLists(_, _ref12) {
786803
order = state.order;
787804
var addEntry = function addEntry(list) {
788805
var id = (0, _uuid.v4)();
789-
var newList = _objectSpread(_objectSpread({}, list), {}, {
806+
var newList = _objectSpread(_objectSpread({
807+
id: id
808+
}, list), {}, {
790809
order: [],
791-
id: id,
792810
settings: {
793811
defaultValuePoints: DEFAULT_VALUE_POINTS,
794812
defaultType: 'Todo',
@@ -798,11 +816,14 @@ var MyLists = function MyLists(_, _ref12) {
798816
});
799817
var newLists = [newList].concat((0, _toConsumableArray2["default"])(state.lists));
800818
setState({
801-
order: [id].concat((0, _toConsumableArray2["default"])(state.order)),
819+
order: [newList.id].concat((0, _toConsumableArray2["default"])(state.order)),
802820
lists: newLists
803821
});
804822
};
805823
var removeEntry = function removeEntry(id) {
824+
var removed = state.lists.find(function (list) {
825+
return list.id === id;
826+
});
806827
setState({
807828
lists: state.lists.filter(function (list) {
808829
return list.id !== id;
@@ -811,6 +832,7 @@ var MyLists = function MyLists(_, _ref12) {
811832
return listId !== id;
812833
})
813834
});
835+
return removed;
814836
};
815837
var exportUserData = function exportUserData() {
816838
return exportData({

src/components/Lists.tsx

+24-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type TodoObject = {
2424
key?: string;
2525
id: string | null;
2626
title: string;
27+
note?: string;
2728
completed: boolean;
2829
archived: boolean;
2930
lastModified?: number;
@@ -124,6 +125,7 @@ export const Todo = (
124125
lastNotified,
125126
dueDate = null,
126127
dueTime = null,
128+
note,
127129
changeType,
128130
createdAt,
129131
color,
@@ -156,6 +158,7 @@ export const Todo = (
156158
valuePoints,
157159
creditedValuePoints,
158160
negativePoints,
161+
note,
159162
dueDate,
160163
dueTime,
161164
type: 'Todo',
@@ -258,7 +261,15 @@ export const Todo = (
258261
reset: 1000 * 60 * 60 * reset,
259262
});
260263
};
261-
264+
const setNote = (note) => {
265+
if (typeof note !== 'string' || note.length > 32000) {
266+
throw new Error('Invalid note');
267+
}
268+
setTodo({
269+
...todo,
270+
note,
271+
});
272+
};
262273
const setValuePoints = (valuePoints) => {
263274
if (
264275
(typeof valuePoints !== 'number' && valuePoints < 0) ||
@@ -317,6 +328,7 @@ export const Todo = (
317328
setTitle={setTitle}
318329
setDueDate={setDueDate}
319330
setDueTime={setDueTime}
331+
setNote={setNote}
320332
type="Todo"
321333
createdAt={createdAt}
322334
lastModified={todo.lastModified}
@@ -675,7 +687,7 @@ export const List = (
675687
const removeEntry = (todoId: string) => {
676688
const store = Dispatcher.getCurrent().getStore();
677689
const todo = store.getState<TodoObject>(null, {
678-
key: `todo-${todoId}`,
690+
key: `todo`,
679691
scope: `${todoId}.${user?.id || Scopes.Client}`,
680692
});
681693
setOrder(order.filter((id) => id !== todoId));
@@ -685,6 +697,7 @@ export const List = (
685697
1 -
686698
(todo?.value?.archived ? 1 : 0) -
687699
(todo?.value?.valuePoints || 0);
700+
return todo.value;
688701
};
689702

690703
const addLabel = (label: TodoObject) => {
@@ -876,6 +889,10 @@ const exportData = ({ key, user }) => {
876889
key: 'color',
877890
scope: `${`list-${list.id}`}.${user?.id || clientId}`,
878891
});
892+
const title = store.getState(null, {
893+
key: 'title',
894+
scope: `${`list-${list.id}`}.${user?.id || clientId}`,
895+
});
879896
const settings = store.getState(null, {
880897
key: 'settings',
881898
scope: `${`list-${list.id}`}.${user?.id || clientId}`,
@@ -890,6 +907,7 @@ const exportData = ({ key, user }) => {
890907

891908
data[list.id] = {
892909
...list,
910+
title: title.value,
893911
color: color.value,
894912
order: order.value,
895913
todos: todos.value,
@@ -939,9 +957,9 @@ export const MyLists = (_: { key?: string }, { context, key }) => {
939957
const addEntry = (list: ListObject) => {
940958
const id = v4();
941959
const newList = {
960+
id,
942961
...list,
943962
order: [],
944-
id,
945963
settings: {
946964
defaultValuePoints: DEFAULT_VALUE_POINTS,
947965
defaultType: 'Todo',
@@ -950,14 +968,16 @@ export const MyLists = (_: { key?: string }, { context, key }) => {
950968
createdAt: Date.now(),
951969
};
952970
const newLists = [newList, ...state.lists];
953-
setState({ order: [id, ...state.order], lists: newLists });
971+
setState({ order: [newList.id, ...state.order], lists: newLists });
954972
};
955973

956974
const removeEntry = (id: string) => {
975+
const removed = state.lists.find((list) => list.id === id);
957976
setState({
958977
lists: state.lists.filter((list) => list.id !== id),
959978
order: state.order.filter((listId) => listId !== id),
960979
});
980+
return removed;
961981
};
962982

963983
const exportUserData = () => {

0 commit comments

Comments
 (0)