5htp-core 0.0.8-2 → 0.0.9
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/package.json +1 -1
- package/src/client/assets/css/components/card.less +0 -7
- package/src/client/assets/css/layouts.less +11 -10
- package/src/client/assets/css/text/icons.less +0 -0
- package/src/client/assets/css/text/text.less +11 -6
- package/src/client/components/Select/index.tsx +58 -0
- package/src/client/components/data/progressbar/circular/index.tsx +1 -1
- package/src/client/components/data/progressbar/index.less +4 -2
- package/src/client/components/dropdown/index.tsx +12 -21
- package/src/client/components/input/BaseV2/index.tsx +4 -2
- package/src/client/context/index.ts +45 -40
- package/src/client/router/component.tsx +1 -0
- package/src/client/router/request/index.ts +0 -0
- package/src/common/data/number/percentage.ts +4 -2
- package/src/common/router/index.ts +1 -1
- package/src/server/data/Cache.ts +10 -4
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "5htp-core",
|
|
3
3
|
"description": "5-HTP, scientifically called 5-Hydroxytryptophan, is the precursor of happiness neurotransmitter.",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.9",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp-core.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -217,6 +217,7 @@
|
|
|
217
217
|
Déclarer une grid: grid x-3
|
|
218
218
|
Placer un element: x1-3
|
|
219
219
|
*/
|
|
220
|
+
@gridUnit: 6.66rem;
|
|
220
221
|
.zones(@nb, @i: 1) when (@i <= @nb) {
|
|
221
222
|
/*----------------------------------
|
|
222
223
|
- ZONES DE LA GRILLE
|
|
@@ -287,23 +288,23 @@
|
|
|
287
288
|
// Automatique
|
|
288
289
|
.taille-auto(@min, @max) when (@min <= @max) {
|
|
289
290
|
&.xa@{min}-@{max} {
|
|
290
|
-
grid-template-columns: repeat(auto-fit, minmax(@min *
|
|
291
|
+
grid-template-columns: repeat(auto-fit, minmax(@min * @gridUnit, @max * @gridUnit))
|
|
291
292
|
}
|
|
292
293
|
&.ya@{min}-@{max} {
|
|
293
|
-
grid-template-rows: repeat(auto-fit, minmax(@min *
|
|
294
|
+
grid-template-rows: repeat(auto-fit, minmax(@min * @gridUnit, @max * @gridUnit))
|
|
294
295
|
}
|
|
295
296
|
.taille-auto(@min + 1, @max);
|
|
296
297
|
}
|
|
297
298
|
&.xa@{i} {
|
|
298
|
-
grid-template-columns: repeat(auto-fit, minmax(@i *
|
|
299
|
+
grid-template-columns: repeat(auto-fit, minmax(@i * @gridUnit, 1fr));
|
|
299
300
|
&5 {
|
|
300
|
-
grid-template-columns: repeat(auto-fit, minmax(@i *
|
|
301
|
+
grid-template-columns: repeat(auto-fit, minmax(@i * @gridUnit + 4.15rem, 1fr));
|
|
301
302
|
}
|
|
302
303
|
}
|
|
303
304
|
&.ya@{i} {
|
|
304
|
-
grid-template-rows: repeat(auto-fit, minmax(@i *
|
|
305
|
+
grid-template-rows: repeat(auto-fit, minmax(@i * @gridUnit, 1fr));
|
|
305
306
|
&5 {
|
|
306
|
-
grid-template-rows: repeat(auto-fit, minmax(@i *
|
|
307
|
+
grid-template-rows: repeat(auto-fit, minmax(@i * @gridUnit + 4.15rem, 1fr));
|
|
307
308
|
}
|
|
308
309
|
}
|
|
309
310
|
.taille-auto(1, @i);
|
|
@@ -347,10 +348,10 @@
|
|
|
347
348
|
break-inside: avoid;
|
|
348
349
|
}
|
|
349
350
|
|
|
350
|
-
&.xa1 { column-width:
|
|
351
|
-
&.xa2 { column-width:
|
|
351
|
+
&.xa1 { column-width: @gridUnit; }
|
|
352
|
+
&.xa2 { column-width: @gridUnit * 2; }
|
|
352
353
|
&,
|
|
353
|
-
&.xa3 { column-width:
|
|
354
|
-
&.xa4 { column-width:
|
|
354
|
+
&.xa3 { column-width: @gridUnit * 3; }
|
|
355
|
+
&.xa4 { column-width: @gridUnit * 4; }
|
|
355
356
|
|
|
356
357
|
}
|
|
File without changes
|
|
@@ -5,6 +5,7 @@ a {
|
|
|
5
5
|
color: inherit;
|
|
6
6
|
cursor: pointer;
|
|
7
7
|
text-decoration: underline;
|
|
8
|
+
text-decoration: none;
|
|
8
9
|
|
|
9
10
|
&:not([disabled]):hover,
|
|
10
11
|
&.active {
|
|
@@ -12,12 +13,16 @@ a {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
&.super {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
z-index:
|
|
16
|
+
text-decoration: none;
|
|
17
|
+
&::after {
|
|
18
|
+
content: ' ';
|
|
19
|
+
position: absolute;
|
|
20
|
+
top: 0; left: 0; right: 0; bottom: 0;
|
|
21
|
+
z-index: 5;
|
|
22
|
+
|
|
23
|
+
~ a, ~ * a, ~ button, ~ * button {
|
|
24
|
+
z-index: 6;
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
28
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
// Core
|
|
9
|
+
import Button from '@client/components/button';
|
|
10
|
+
import Dropdown, { TDialogControls, Props as DropdownProps } from '@client/components/dropdown';
|
|
11
|
+
|
|
12
|
+
/*----------------------------------
|
|
13
|
+
- CONST
|
|
14
|
+
----------------------------------*/
|
|
15
|
+
|
|
16
|
+
/*----------------------------------
|
|
17
|
+
- TYPES
|
|
18
|
+
----------------------------------*/
|
|
19
|
+
|
|
20
|
+
type Choices = string[]
|
|
21
|
+
|
|
22
|
+
type SearchResultsFunction = (keywords: string) => Choices
|
|
23
|
+
|
|
24
|
+
export type Props = DropdownProps & {
|
|
25
|
+
title: string,
|
|
26
|
+
choices: Choices,
|
|
27
|
+
value?: string,
|
|
28
|
+
onChange: (value: string) => void,
|
|
29
|
+
search?: true | SearchResultsFunction
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/*----------------------------------
|
|
33
|
+
- COMONENT
|
|
34
|
+
----------------------------------*/
|
|
35
|
+
|
|
36
|
+
export default ({ title, choices, value, onChange, ...dropDownProps }: Props) => {
|
|
37
|
+
const refModal = React.useRef<TDialogControls>(null);
|
|
38
|
+
return (
|
|
39
|
+
<Dropdown {...dropDownProps} content={(
|
|
40
|
+
<ul class="card col menu">
|
|
41
|
+
{choices.map( jt => (
|
|
42
|
+
<li>
|
|
43
|
+
<Button active={jt === value} onClick={() => {
|
|
44
|
+
onChange(jt);
|
|
45
|
+
refModal.current?.close();
|
|
46
|
+
}}>
|
|
47
|
+
{jt}
|
|
48
|
+
</Button>
|
|
49
|
+
</li>
|
|
50
|
+
))}
|
|
51
|
+
</ul>
|
|
52
|
+
)} iconR="chevron-down" refModal={refModal}>
|
|
53
|
+
|
|
54
|
+
{value || title}
|
|
55
|
+
|
|
56
|
+
</Dropdown>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
@@ -99,8 +99,8 @@ div.progressbar_old {
|
|
|
99
99
|
.progressbar-svg {
|
|
100
100
|
|
|
101
101
|
position: relative;
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
width: @sizeComponent;
|
|
103
|
+
height: @sizeComponent;
|
|
104
104
|
|
|
105
105
|
> svg {
|
|
106
106
|
|
|
@@ -142,6 +142,8 @@ div.progressbar_old {
|
|
|
142
142
|
left: 0;
|
|
143
143
|
right: 0;
|
|
144
144
|
bottom: 0;
|
|
145
|
+
// Text should fit inside the progressbar
|
|
146
|
+
font-size: 0.8em;
|
|
145
147
|
|
|
146
148
|
> i,
|
|
147
149
|
> img {
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
// Npm
|
|
6
6
|
import React from 'react';
|
|
7
|
-
import { ComponentChild } from 'preact';
|
|
7
|
+
import { ComponentChild, RefObject } from 'preact';
|
|
8
8
|
|
|
9
9
|
// Core
|
|
10
10
|
import Button, { Props as ButtonProps } from '../button';
|
|
11
|
+
import { TDialogControls } from '../Dialog/Manager';
|
|
12
|
+
export type { TDialogControls } from '../Dialog/Manager';
|
|
11
13
|
|
|
12
14
|
// Libs
|
|
13
15
|
import useContexte from '@client/context';
|
|
@@ -17,23 +19,8 @@ import useContexte from '@client/context';
|
|
|
17
19
|
----------------------------------*/
|
|
18
20
|
|
|
19
21
|
export type Props = ButtonProps & {
|
|
20
|
-
content: ComponentChild
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export type TAction<TDonnee> = {
|
|
24
|
-
icone?: TIcons,
|
|
25
|
-
label: ComponentChild,
|
|
26
|
-
multi?: boolean,
|
|
27
|
-
|
|
28
|
-
onClick?: (donnees: TDonnee, index: number) => void,
|
|
29
|
-
lien?: (donnees: TDonnee, index: number) => string,
|
|
30
|
-
bouton?: (donnees: TDonnee, index: number) => ButtonProps
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export type TActionsPopover = {
|
|
34
|
-
show: () => void,
|
|
35
|
-
hide: () => void,
|
|
36
|
-
toggle: () => void
|
|
22
|
+
content: ComponentChild,
|
|
23
|
+
refModal?: RefObject<TDialogControls>
|
|
37
24
|
}
|
|
38
25
|
|
|
39
26
|
/*----------------------------------
|
|
@@ -45,15 +32,19 @@ export default (props: Props) => {
|
|
|
45
32
|
|
|
46
33
|
let {
|
|
47
34
|
content,
|
|
48
|
-
|
|
35
|
+
refModal,
|
|
49
36
|
...buttonProps
|
|
50
37
|
} = props;
|
|
51
38
|
|
|
52
39
|
const refButton = React.useRef<HTMLElement>(null);
|
|
53
40
|
|
|
54
|
-
const open = () =>
|
|
41
|
+
const open = () => {
|
|
42
|
+
const modalInstance = modal.show(() => content);
|
|
43
|
+
if (refModal)
|
|
44
|
+
refModal.current = modalInstance;
|
|
45
|
+
}
|
|
55
46
|
|
|
56
47
|
return (
|
|
57
|
-
<Button {...buttonProps} onClick={open} refElem={refButton} />
|
|
48
|
+
<Button {...buttonProps} onClick={(open)} refElem={refButton} />
|
|
58
49
|
)
|
|
59
50
|
}
|
|
@@ -57,8 +57,10 @@ export function useInput<TValue>(
|
|
|
57
57
|
// External value change
|
|
58
58
|
React.useEffect(() => {
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
if (externalValue !== undefined && externalValue !== state.value) {
|
|
61
|
+
console.log("External value change", externalValue);
|
|
62
|
+
setState({ value: externalValue, valueSource: 'external' })
|
|
63
|
+
}
|
|
62
64
|
|
|
63
65
|
}, [externalValue]);
|
|
64
66
|
|
|
@@ -112,42 +112,6 @@ export class ClientContext {
|
|
|
112
112
|
this.request = request;
|
|
113
113
|
this.user = this.request.user || { ...GuestUser };
|
|
114
114
|
|
|
115
|
-
this.api.reload = (ids?: string | string[], params?: TObjetDonnees) => {
|
|
116
|
-
|
|
117
|
-
if (this.page === undefined)
|
|
118
|
-
throw new Error("context.page is missing");
|
|
119
|
-
|
|
120
|
-
if (ids === undefined)
|
|
121
|
-
ids = Object.keys(this.page.fetchers);
|
|
122
|
-
else if (typeof ids === 'string')
|
|
123
|
-
ids = [ids];
|
|
124
|
-
|
|
125
|
-
console.log("[api] Reload data", ids, params, this.page.fetchers);
|
|
126
|
-
|
|
127
|
-
for (const id of ids) {
|
|
128
|
-
|
|
129
|
-
const fetcher = this.page.fetchers[id];
|
|
130
|
-
if (fetcher === undefined)
|
|
131
|
-
return console.error(`Unable to reload ${id}: Request not found in fetchers list.`);
|
|
132
|
-
|
|
133
|
-
if (params !== undefined)
|
|
134
|
-
fetcher.data = { ...(fetcher.data || {}), ...params };
|
|
135
|
-
|
|
136
|
-
console.log("[api][reload]", id, fetcher.method, fetcher.path, fetcher.data);
|
|
137
|
-
const indicator = this.toast.loading("Loading ...");
|
|
138
|
-
|
|
139
|
-
this.request.fetchAsync(fetcher.method, fetcher.path, fetcher.data).then((data) => {
|
|
140
|
-
|
|
141
|
-
this.api.set({ [id]: data });
|
|
142
|
-
|
|
143
|
-
}).finally(() => {
|
|
144
|
-
|
|
145
|
-
indicator.close(true);
|
|
146
|
-
|
|
147
|
-
})
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
115
|
}
|
|
152
116
|
|
|
153
117
|
// Is overwrote by the native app
|
|
@@ -194,10 +158,51 @@ export class ClientContext {
|
|
|
194
158
|
|
|
195
159
|
// fetch doit appartenir à response, et non clientcontxt
|
|
196
160
|
// car la méthode varie selon client (http) ou serveur (router.resolve)
|
|
197
|
-
public api =
|
|
198
|
-
|
|
199
|
-
set: (
|
|
200
|
-
|
|
161
|
+
public api = {
|
|
162
|
+
...this.request.api,
|
|
163
|
+
set: (newData: TObjetDonnees) => {
|
|
164
|
+
|
|
165
|
+
console.log("[api] Update page data", newData);
|
|
166
|
+
if (this.page)
|
|
167
|
+
this.page.setAllData(curData => ({ ...curData, ...newData }));
|
|
168
|
+
|
|
169
|
+
},
|
|
170
|
+
reload: (ids?: string | string[], params?: TObjetDonnees) => {
|
|
171
|
+
|
|
172
|
+
if (this.page === undefined)
|
|
173
|
+
throw new Error("context.page is missing");
|
|
174
|
+
|
|
175
|
+
if (ids === undefined)
|
|
176
|
+
ids = Object.keys(this.page.fetchers);
|
|
177
|
+
else if (typeof ids === 'string')
|
|
178
|
+
ids = [ids];
|
|
179
|
+
|
|
180
|
+
console.log("[api] Reload data", ids, params, this.page.fetchers);
|
|
181
|
+
|
|
182
|
+
for (const id of ids) {
|
|
183
|
+
|
|
184
|
+
const fetcher = this.page.fetchers[id];
|
|
185
|
+
if (fetcher === undefined)
|
|
186
|
+
return console.error(`Unable to reload ${id}: Request not found in fetchers list.`);
|
|
187
|
+
|
|
188
|
+
if (params !== undefined)
|
|
189
|
+
fetcher.data = { ...(fetcher.data || {}), ...params };
|
|
190
|
+
|
|
191
|
+
console.log("[api][reload]", id, fetcher.method, fetcher.path, fetcher.data);
|
|
192
|
+
const indicator = this.toast.loading("Loading ...");
|
|
193
|
+
|
|
194
|
+
this.request.fetchAsync(fetcher.method, fetcher.path, fetcher.data).then((data) => {
|
|
195
|
+
|
|
196
|
+
this.api.set({ [id]: data });
|
|
197
|
+
|
|
198
|
+
}).finally(() => {
|
|
199
|
+
|
|
200
|
+
indicator.close(true);
|
|
201
|
+
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
201
206
|
|
|
202
207
|
public handleError(e: Error) {
|
|
203
208
|
switch (e.http) {
|
|
@@ -50,6 +50,7 @@ const Page = ({ page, isCurrent }: { page: PageResponse, isCurrent?: boolean })
|
|
|
50
50
|
id={page.id === undefined ? undefined : 'page_' + page.id}
|
|
51
51
|
>
|
|
52
52
|
|
|
53
|
+
{/* Make request parameters and api data accessible from the page component */}
|
|
53
54
|
{page.component ? (
|
|
54
55
|
|
|
55
56
|
<page.component {...gui.request.data} {...data} />
|
|
File without changes
|
|
@@ -11,11 +11,13 @@ export type TVariation = {
|
|
|
11
11
|
color: string,
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export const variationStr = (value: number, reference: number,
|
|
14
|
+
export const variationStr = (value: number, reference: number, options: {
|
|
15
|
+
lowerIsBetter?: boolean
|
|
16
|
+
} = {}): TVariation => {
|
|
15
17
|
const pc = variation(value, reference);
|
|
16
18
|
const pcStr = pc.toFixed(2);
|
|
17
19
|
return {
|
|
18
20
|
txt: ((pc > 0) ? '+' + pcStr : pcStr) + '%',
|
|
19
|
-
color: (lowerIsBetter ? pc > 0 : pc < 0) ? 'ea3943' : '16c784'
|
|
21
|
+
color: (options.lowerIsBetter ? pc > 0 : pc < 0) ? 'ea3943' : '16c784'
|
|
20
22
|
}
|
|
21
23
|
}
|
|
@@ -35,7 +35,7 @@ const getLayout = (routePath: string | undefined): Layout | undefined => {
|
|
|
35
35
|
if (routePath === layoutPath || routePath.startsWith( layoutPath + '/' ))
|
|
36
36
|
layout = { path: layoutPath, Component: layouts[layoutPath] };
|
|
37
37
|
}
|
|
38
|
-
layout && console.log(
|
|
38
|
+
//layout && console.log(`${routePath}: Using Layout: ${layout.path}`);
|
|
39
39
|
return layout;
|
|
40
40
|
}
|
|
41
41
|
|
package/src/server/data/Cache.ts
CHANGED
|
@@ -14,6 +14,12 @@ import app from '@server/app';
|
|
|
14
14
|
|
|
15
15
|
// Libs
|
|
16
16
|
|
|
17
|
+
/*----------------------------------
|
|
18
|
+
- CONFIG
|
|
19
|
+
----------------------------------*/
|
|
20
|
+
|
|
21
|
+
const debug = false;
|
|
22
|
+
|
|
17
23
|
/*----------------------------------
|
|
18
24
|
- TYPES
|
|
19
25
|
----------------------------------*/
|
|
@@ -50,7 +56,7 @@ class Cache {
|
|
|
50
56
|
|
|
51
57
|
private cleanMem() {
|
|
52
58
|
|
|
53
|
-
console.log("[cache] Clean memory");
|
|
59
|
+
debug && console.log("[cache] Clean memory");
|
|
54
60
|
|
|
55
61
|
const now = Date.now();
|
|
56
62
|
for (const key in this.data) {
|
|
@@ -88,11 +94,11 @@ class Cache {
|
|
|
88
94
|
|
|
89
95
|
let retour: CacheEntry | undefined = this.data[cle];
|
|
90
96
|
|
|
91
|
-
console.log(`[cache] Get "${cle}".`);
|
|
97
|
+
debug && console.log(`[cache] Get "${cle}".`);
|
|
92
98
|
|
|
93
99
|
// Expired
|
|
94
100
|
if (retour?.expiration && retour.expiration < Date.now()){
|
|
95
|
-
console.log(`[cache] Key ${cle} expired.`);
|
|
101
|
+
debug && console.log(`[cache] Key ${cle} expired.`);
|
|
96
102
|
retour = undefined;
|
|
97
103
|
}
|
|
98
104
|
|
|
@@ -133,7 +139,7 @@ class Cache {
|
|
|
133
139
|
*/
|
|
134
140
|
public set( cle: string, val: TPrimitiveValue, expiration: TExpirationDelay = null ): void {
|
|
135
141
|
|
|
136
|
-
console.log("[cache] Updating cache " + cle);
|
|
142
|
+
debug && console.log("[cache] Updating cache " + cle);
|
|
137
143
|
this.data[ cle ] = {
|
|
138
144
|
value: val,
|
|
139
145
|
expiration: this.delayToTimestamp(expiration)
|