5htp-core 0.2.2 → 0.2.4

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.
Files changed (49) hide show
  1. package/package.json +1 -1
  2. package/src/client/app/component.tsx +1 -2
  3. package/src/client/app/index.ts +2 -6
  4. package/src/client/assets/css/components/button.less +4 -3
  5. package/src/client/assets/css/components/card.less +26 -11
  6. package/src/client/assets/css/components/lists.less +1 -1
  7. package/src/client/assets/css/components/other.less +0 -11
  8. package/src/client/assets/css/components.less +17 -3
  9. package/src/client/assets/css/core.less +55 -0
  10. package/src/client/assets/css/theme.less +0 -4
  11. package/src/client/assets/css/utils/layouts.less +1 -1
  12. package/src/client/assets/css/utils/medias.less +0 -47
  13. package/src/client/components/Dialog/Manager.tsx +1 -4
  14. package/src/client/components/Dialog/card.tsx +1 -1
  15. package/src/client/components/Dialog/index.less +2 -2
  16. package/src/client/components/Form.ts +154 -0
  17. package/src/client/components/{Form → Form_old}/index.tsx +0 -0
  18. package/src/client/components/{Form → Form_old}/index.tsx.old +0 -0
  19. package/src/client/components/Select/index.tsx +159 -24
  20. package/src/client/components/containers/Popover/index.tsx +38 -120
  21. package/src/client/components/data/progressbar/circular/index.tsx +1 -3
  22. package/src/client/components/dropdown/index.tsx +8 -13
  23. package/src/client/components/inputv3/base.less +0 -1
  24. package/src/client/components/inputv3/base.tsx +17 -6
  25. package/src/client/components/inputv3/string/index.tsx +23 -10
  26. package/src/client/services/router/components/Page.tsx +16 -18
  27. package/src/client/services/router/components/router.tsx +3 -3
  28. package/src/client/services/router/index.tsx +17 -14
  29. package/src/client/services/router/request/api.ts +6 -3
  30. package/src/client/services/router/response/index.tsx +4 -0
  31. package/src/client/services/router/response/page.ts +2 -1
  32. package/src/common/router/index.ts +1 -1
  33. package/src/common/router/layouts.ts +38 -6
  34. package/src/common/router/register.ts +3 -9
  35. package/src/common/router/request/api.ts +3 -1
  36. package/src/common/validation/index.ts +1 -1
  37. package/src/common/validation/schema.ts +8 -3
  38. package/src/common/validation/validators.ts +21 -10
  39. package/src/server/app/index.ts +2 -1
  40. package/src/server/services/console/bugReporter.ts +2 -19
  41. package/src/server/services/database/index.ts +27 -19
  42. package/src/server/services/router/index.ts +3 -3
  43. package/src/server/services/router/request/api.ts +3 -0
  44. package/src/server/services/router/response/index.ts +7 -4
  45. package/src/server/services/router/response/mask/Filter.ts +16 -72
  46. package/src/server/services/router/response/mask/index.ts +4 -7
  47. package/src/server/services/router/response/page/document.tsx +2 -2
  48. package/src/server/services/router/response/page/index.tsx +2 -2
  49. package/src/server/services/schema/request.ts +4 -2
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.2.2",
4
+ "version": "0.2.4",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -21,8 +21,7 @@ export default function App ({ context }: {
21
21
  context: TClientOrServerContext,
22
22
  }) {
23
23
 
24
- const route = context.route;
25
- const curLayout = route.options.layout;
24
+ const curLayout = context.page?.layout;
26
25
  const [layout, setLayout] = React.useState<Layout | false | undefined>(curLayout);
27
26
 
28
27
  // TODO: context.page is always provided in the context on the client side
@@ -102,11 +102,7 @@ export default abstract class Application {
102
102
  })
103
103
  }
104
104
 
105
- public handleError( error: CoreError | Error, httpCode?: number ) {
106
-
107
- /*console.error(`[api] Network error:`, e);
108
- context.toast.error("Please check your internet connection and try again.", undefined, null, { autohide: false });*/
109
- }
105
+ public abstract handleError( error: CoreError | Error, httpCode?: number );
110
106
 
111
107
  public reportBug = (infos: TBugReportInfos) => fetch('/help/bug/gui', {
112
108
  method: 'POST',
@@ -116,7 +112,7 @@ export default abstract class Application {
116
112
  },
117
113
  body: JSON.stringify({
118
114
  url: window.location.pathname,
119
- ssrData: JSON.stringify(window["ssr"]),
115
+ context: JSON.stringify(window["ssr"]),
120
116
  guiVersion: BUILD_DATE,
121
117
  ...infos
122
118
  })
@@ -94,9 +94,6 @@
94
94
  ----------------------------------*/
95
95
 
96
96
  &.bg {
97
-
98
- background: var(--cBg);
99
- color: var(--cTxtBase);
100
97
 
101
98
  &:not(:disabled) {
102
99
  &:hover,
@@ -316,6 +313,10 @@ ul.col {
316
313
  }
317
314
  }
318
315
 
316
+ &.menu > li > .btn {
317
+ width: 100%;
318
+ }
319
+
319
320
  .btn.icon > .label,
320
321
  > li > .btn + ul {
321
322
  left: 100%;
@@ -20,23 +20,38 @@
20
20
 
21
21
  &.row {
22
22
  padding: @cardPadding @cardPaddingLong;
23
+
24
+ // TODO: rename & move elsewere
25
+ &.inside {
26
+
27
+ padding: 0;
28
+ gap: 0;
29
+ align-items: stretch;
30
+
31
+ > * {
32
+ padding: @cardPadding @cardPaddingLong;
33
+ &:first-child {
34
+ border-top-left-radius: inherit;
35
+ border-bottom-left-radius: inherit;
36
+ }
37
+ &:last-child {
38
+ border-top-right-radius: inherit;
39
+ border-bottom-right-radius: inherit;
40
+ }
41
+ }
42
+ }
43
+
44
+ &.sep {
45
+ > * + * {
46
+ border-left: solid 1px #eee;
47
+ }
48
+ }
23
49
  }
24
50
 
25
51
  &.col {
26
52
  padding: @cardPaddingLong @cardPadding;
27
53
  }
28
54
 
29
- &.bg {
30
- --cBg: difference(@cBgPage, #0a0a0a);
31
- --cBg2: difference(@cBgPage, #111);
32
- background: var(--cBg);
33
-
34
- &.img {
35
- background-position: center;
36
- background-size: cover;
37
- }
38
- }
39
-
40
55
  &.selected {
41
56
 
42
57
  box-shadow: 0 0 0 3px @c1;
@@ -123,7 +123,7 @@ ol.steps {
123
123
  ol.steps > li:before,
124
124
  strong.step {
125
125
 
126
- background: @c1SuperLight;
126
+ background: @c1 + #666;
127
127
  color: @c1;
128
128
 
129
129
  text-align: center;
@@ -27,17 +27,6 @@
27
27
  background: var(--cBgAccent);
28
28
  }
29
29
 
30
- .bg-cover {
31
- background-color: #000;
32
- background-repeat: no-repeat;
33
- background-position: center;
34
- background-size: cover;
35
- }
36
-
37
- img.bg-cover {
38
- object-fit: cover;
39
- }
40
-
41
30
  .clickable {
42
31
  cursor: pointer;
43
32
  }
@@ -31,7 +31,6 @@
31
31
  }
32
32
 
33
33
  .card,
34
- .input.text,
35
34
  .btn,
36
35
  .table,
37
36
  i.solid {
@@ -48,9 +47,24 @@ i.solid {
48
47
  }
49
48
  }
50
49
 
50
+ .input.text {
51
+ border: solid 0.25em #eee;
52
+
53
+ &:hover {
54
+ border-color: #ddd;
55
+ }
56
+
57
+ &.focus {
58
+ border-color: @c1;
59
+ }
60
+
61
+ &.error {
62
+ border-color: @cError;
63
+ }
64
+ }
65
+
51
66
  //.card.clickable:hover,
52
67
  .btn:hover,
53
68
  .input.text.focus {
54
- z-index: 5;
55
- box-shadow: 0 10px 50px fade(#000, 15%);
69
+
56
70
  }
@@ -12,6 +12,61 @@
12
12
  .bg {
13
13
  background: var(--cBg);
14
14
  color: var(--cTxtBase);
15
+
16
+ &.img {
17
+ background-size: cover;
18
+ background-repeat: no-repeat;
19
+ background-position: center;
20
+
21
+ .build-theme-bg(#000, #fff);
22
+ text-shadow: 0 0 10px fade(#000, 20%);
23
+
24
+ --cTxtDiscret: fade(#fff, 40%)
25
+ --cTxtDesc: fade(#fff, 60%);
26
+ --cTxtBase: fade(#fff, 80%);
27
+ --cTxtImportant: fade(#fff, 100%);
28
+ --cTxtAccent: fade(#fff, 20%);
29
+
30
+ &.light {
31
+ --cTxtDiscret: fade(#000, 40%)
32
+ --cTxtDesc: fade(#000, 60%);
33
+ --cTxtBase: fade(#000, 80%);
34
+ --cTxtImportant: fade(#000, 100%);
35
+ --cTxtAccent: fade(#000, 20%);
36
+ }
37
+
38
+ &.colorize {
39
+ position: relative;
40
+
41
+ &::after {
42
+ content: ' ';
43
+ display: block;
44
+ background-color: inherit;
45
+ opacity: 0.5;
46
+ border-radius: inherit;
47
+
48
+ position: absolute;
49
+ top: 0; right: 0; bottom: 0; left: 0;
50
+ z-index: 1;
51
+ }
52
+
53
+ > * {
54
+ z-index: 2;
55
+ position: relative;
56
+ }
57
+ }
58
+ }
59
+
60
+ &.bg-cover {
61
+ background-color: #000;
62
+ background-repeat: no-repeat;
63
+ background-position: center;
64
+ background-size: cover;
65
+ }
66
+
67
+ &img.bg-cover {
68
+ object-fit: cover;
69
+ }
15
70
  }
16
71
 
17
72
  html {
@@ -45,10 +45,6 @@
45
45
  border: if(@bg = #ffffff, solid 2px var(--cLine), none);
46
46
  }*/
47
47
  }
48
-
49
- .overlay {
50
- background: fade(@bg, 50%);
51
- }
52
48
  }
53
49
 
54
50
  .build-theme-fg( @cTxtBase, @bg: @cBgPage, @apply: true ) {
@@ -151,7 +151,7 @@
151
151
  &-3 { flex: 3; }
152
152
 
153
153
  &.menu {
154
- gap: @spacing / 2;
154
+ gap: 1px;
155
155
  }
156
156
  }
157
157
 
@@ -4,25 +4,6 @@ img.img,
4
4
  background: @cBgPage - #101010;
5
5
  }
6
6
 
7
- .bg.img {
8
- .build-theme-bg(#000, #fff);
9
- text-shadow: 0 0 10px fade(#000, 20%);
10
-
11
- --cTxtDiscret: fade(#fff, 40%)
12
- --cTxtDesc: fade(#fff, 60%);
13
- --cTxtBase: fade(#fff, 80%);
14
- --cTxtImportant: fade(#fff, 100%);
15
- --cTxtAccent: fade(#fff, 20%);
16
-
17
- &.light {
18
- --cTxtDiscret: fade(#000, 40%)
19
- --cTxtDesc: fade(#000, 60%);
20
- --cTxtBase: fade(#000, 80%);
21
- --cTxtImportant: fade(#000, 100%);
22
- --cTxtAccent: fade(#000, 20%);
23
- }
24
- }
25
-
26
7
  img {
27
8
  max-width: 100%;
28
9
  display: block;
@@ -36,34 +17,6 @@ img {
36
17
  - IMAGE CONFIG
37
18
  ----------------------------------*/
38
19
 
39
- // Default: cover
40
- .bg.img {
41
- background-size: cover;
42
- background-repeat: no-repeat;
43
- background-position: center;
44
-
45
- &.colorize {
46
- position: relative;
47
-
48
- &::after {
49
- content: ' ';
50
- display: block;
51
- background-color: inherit;
52
- opacity: 0.5;
53
- border-radius: inherit;
54
-
55
- position: absolute;
56
- top: 0; right: 0; bottom: 0; left: 0;
57
- z-index: 1;
58
- }
59
-
60
- > * {
61
- z-index: 2;
62
- position: relative;
63
- }
64
- }
65
- }
66
-
67
20
  img.img {
68
21
  object-fit: cover;
69
22
  object-position: center;
@@ -137,10 +137,7 @@ export const createDialog = (app: Application, isToast: boolean): DialogActions
137
137
 
138
138
  if (!isToast)
139
139
  render = (
140
- <div class="modal" onClick={(e) => {
141
- if (e.target === e.currentTarget && !paramsInit?.prison)
142
- close(false);
143
- }}>
140
+ <div class="modal">
144
141
  {render}
145
142
  </div>
146
143
  )
@@ -149,7 +149,7 @@ export default ({
149
149
 
150
150
  </div>
151
151
  ) : (
152
- <div class={"card pd-2 col"} style={width === undefined
152
+ <div class={"card pd-2 col al-top"} style={width === undefined
153
153
  ? {}
154
154
  : { minWidth: width + "px", maxWidth: width + "px" }
155
155
  }>
@@ -82,8 +82,7 @@
82
82
  gap: @spacing;
83
83
  z-index: @modal-zindex;
84
84
 
85
- background: fade(#fff, 20%);
86
- backdrop-filter: blur(30px) saturate(2);
85
+ background: fade(#000, 20%);
87
86
  border-radius: @radius;
88
87
 
89
88
  // Desktop = vertically center the modal
@@ -109,6 +108,7 @@
109
108
  max-height: 100vh;
110
109
  box-shadow: none;
111
110
  padding: @spacing * 2;
111
+ overflow-y: auto;
112
112
 
113
113
  // Pas d'anim quand pas card,
114
114
  // Car peut contenir bcp d'elemnts => performance
@@ -0,0 +1,154 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // npm
6
+ import React from 'react';
7
+
8
+ // Core
9
+ import type { Schema } from '@common/validation';
10
+
11
+ /*----------------------------------
12
+ - TYPES
13
+ ----------------------------------*/
14
+ type TFormOptions<TFormData extends {}> = {
15
+ data?: Partial<TFormData>,
16
+ submit?: (data: TFormData) => Promise<void>
17
+ }
18
+
19
+ type FieldsAttrs<TFormData extends {}> = {
20
+ [fieldName in keyof TFormData]: {}
21
+ }
22
+
23
+ export type Form<TFormData extends {} = {}> = {
24
+ data: TFormData,
25
+ set: (data: Partial<TFormData>) => void,
26
+ submit: (additionnalData?: Partial<TFormData>) => Promise<any>,
27
+ fields: FieldsAttrs<TFormData>,
28
+ } & FormState
29
+
30
+ type FormState = {
31
+ isLoading: boolean,
32
+ errorsCount: number,
33
+ errors: {[fieldName: string]: string[]},
34
+ changed: boolean
35
+ }
36
+
37
+ /*----------------------------------
38
+ - HOOK
39
+ ----------------------------------*/
40
+ export default function useForm<TFormData extends {}>( schema: Schema<TFormData>, options: TFormOptions<TFormData> ) {
41
+
42
+ /*----------------------------------
43
+ - INIT
44
+ ----------------------------------*/
45
+ const fields = React.useRef<FieldsAttrs<TFormData>>(null);
46
+
47
+ const [data, setData] = React.useState<TFormData>( options.data || {} );
48
+ const [state, setState] = React.useState<FormState>({
49
+ isLoading: false,
50
+ errorsCount: 0,
51
+ errors: {},
52
+ changed: false
53
+ });
54
+
55
+ // Validate data when it changes
56
+ React.useEffect(() => {
57
+ state.changed && validate(data);
58
+ }, [data]);
59
+
60
+ /*----------------------------------
61
+ - ACTIONS
62
+ ----------------------------------*/
63
+ const validate = (allData: TFormData) => {
64
+
65
+ const validated = schema.validate(allData, allData);
66
+
67
+ // Update errors
68
+ if (validated.nbErreurs !== state.errorsCount) {
69
+ rebuildFieldsAttrs({
70
+ errorsCount: validated.nbErreurs,
71
+ errors: validated.erreurs,
72
+ });
73
+ }
74
+
75
+ return validated;
76
+ }
77
+
78
+ const submit = (additionnalData: Partial<TFormData> = {}) => {
79
+
80
+ const allData = { ...data, ...additionnalData }
81
+
82
+ // Validation
83
+ const validated = validate(allData);
84
+ if (validated.nbErreurs !== 0)
85
+ return;
86
+
87
+ // Callback
88
+ if (options.submit)
89
+ return options.submit(validated.values);
90
+ }
91
+
92
+ const rebuildFieldsAttrs = (newState: Partial<FormState> = {}) => {
93
+ // Force rebuilding the fields definition on the next state change
94
+ fields.current = null;
95
+ // Force state change
96
+ setState( old => ({
97
+ ...old,
98
+ ...newState,
99
+ changed: true
100
+ }));
101
+ }
102
+
103
+ // Rebuild the fields attrs when the schema changes
104
+ if (fields.current === null || Object.keys(schema).join(',') !== Object.keys(fields.current).join(',')){
105
+ fields.current = {}
106
+ for (const fieldName in schema.fields) {
107
+ fields.current[fieldName] = {
108
+
109
+ // Value control
110
+ value: data[fieldName],
111
+ onChange: (val) => {
112
+ setState( old => ({
113
+ ...old,
114
+ changed: true
115
+ }));
116
+ setData( old => {
117
+ return {
118
+ ...old,
119
+ [fieldName]: typeof val === 'function'
120
+ ? val(old[fieldName])
121
+ : val
122
+ }
123
+ })
124
+ },
125
+
126
+ // Submit on press enter
127
+ onKeyDown: e => {
128
+ if (e.key === 'Enter') {
129
+ submit({ [fieldName]: e.target.value } as Partial<TFormData>);
130
+ }
131
+ },
132
+
133
+ // Error
134
+ errors: state.errors[ fieldName ],
135
+ required: schema.fields[ fieldName ].options?.opt !== true,
136
+ validator: schema.fields[ fieldName ]
137
+ }
138
+ }
139
+ }
140
+
141
+ /*----------------------------------
142
+ - EXPOSE
143
+ ----------------------------------*/
144
+
145
+ const form = {
146
+ data,
147
+ set: setData,
148
+ submit,
149
+ fields: fields.current,
150
+ ...state
151
+ }
152
+
153
+ return [form, fields.current]
154
+ }