Skip to content

Commit 1109973

Browse files
committed
feat: new component
1 parent c6aa4ef commit 1109973

File tree

17 files changed

+243
-47
lines changed

17 files changed

+243
-47
lines changed

demo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"@fontsource/vazirmatn": "^5.0.19",
1414
"@gecut/components": "workspace:^",
1515
"@gecut/lit-helper": "workspace:^",
16-
"@gecut/signal": "^2.2.1",
16+
"@gecut/signal": "^2.2.2",
1717
"@gecut/styles": "workspace:^",
1818
"@gecut/types": "^2.2.1",
1919
"@tailwindcss/aspect-ratio": "^0.4.2",

demo/snack-bar/index.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!doctype html>
2+
<html lang="en" class="color-scheme-auto bg-background font-vazirmatn">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Gecut Snack Bar</title>
7+
<link rel="icon" href="/favicon.ico" sizes="any" />
8+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
9+
<link rel="manifest" href="/manifest.json" />
10+
<script type="module" src="../main/global.ts"></script>
11+
<script type="module" src="./scripts.ts"></script>
12+
</head>
13+
<body class="bg-surface max-w-screen-sm mx-auto p-4"></body>
14+
</html>

demo/snack-bar/scripts.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {SnackBarManager} from '@gecut/components';
2+
import {render, html} from 'lit/html.js';
3+
4+
const sbm = new SnackBarManager({gapBottom: '0'});
5+
let index = 0;
6+
7+
const x = setInterval(() => {
8+
sbm.open('s-' + index++, {
9+
message: 'Hello ' + index,
10+
});
11+
12+
if (x > 5) clearInterval(x);
13+
}, 5000);
14+
15+
render(html` <div class="mx-auto max-w-sm flex flex-col gap-4">${sbm.html}</div> `, document.body);

demo/vite.config.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {defineConfig} from 'vite';
22
import Unfonts from 'unplugin-fonts/vite';
33
import tsconfigPaths from 'vite-tsconfig-paths';
44

5-
const entries = ['dialog', 'top-bar', 'button', 'lists', 'cards', 'icon-button'];
5+
const entries = ['dialog', 'top-bar', 'button', 'lists', 'cards', 'icon-button', 'snack-bar'];
66
const DIST_PATH = './dist/';
77
const pages = entries.reduce((result, name) => {
88
result[name] = `./${name}/index.html`;

packages/components/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@
5050
],
5151
"dependencies": {
5252
"@gecut/lit-helper": "workspace:^",
53-
"@gecut/logger": "^1.4.3",
54-
"@gecut/signal": "^2.2.1",
53+
"@gecut/logger": "^1.4.4",
54+
"@gecut/signal": "^2.2.2",
5555
"@gecut/types": "^2.2.1",
56-
"@gecut/utilities": "^5.3.0",
56+
"@gecut/utilities": "^5.4.0",
5757
"@types/node": "^20.11.30",
5858
"lit": "^3.1.3"
5959
}

packages/components/src/components.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ export * from './button/button.js';
22
export * from './dialog/dialog.js';
33
export * from './dialog/helper.js';
44
export * from './divider/divider.js';
5-
export * from './icon/icon.js';
65
export * from './icon-button/icon-button.js';
7-
export * from './list/list.js';
6+
export * from './icon/icon.js';
87
export * from './list/item.js';
8+
export * from './list/list.js';
99
export * from './navigation-bar/navigation-bar.js';
1010
export * from './navigation-drawer/navigation-drawer.js';
11+
export * from './snack-bar/snack-bar.js';
12+
export * from './snack-bar/manager.js';
1113
export * from './top-bar/center-top-bar.js';
1214
export * from './top-bar/small-top-bar.js';

packages/components/src/dialog/dialog.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ export class GecutDialogDirective extends GecutDirective {
167167
return () => {
168168
this.log.methodArgs?.('close', {value});
169169

170-
content.controller.setValue('close');
171-
content.provider.setValue(value);
170+
content.controller.value = 'close';
171+
content.provider.value = value;
172172
};
173173
}
174174
}

packages/components/src/dialog/helper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class DialogHelper {
1717
return gecutDialog(dialogContent, status === 'open');
1818
})}`;
1919

20-
this.controller.setValue('close');
20+
this.controller.value = 'close';
2121
}
2222

2323
controller = new ContextSignal<'open' | 'close'>('dialog-controller');
@@ -28,7 +28,7 @@ export class DialogHelper {
2828
open(content: Partial<DialogHelperContent> = {}) {
2929
this.content = {...this.content, ...content} as DialogHelperContent;
3030

31-
this.controller.setValue('open');
31+
this.controller.value = 'open';
3232
}
3333

3434
onAfterClose() {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {gecutContext} from '@gecut/lit-helper/directives/context.js';
2+
import {ContextSignal} from '@gecut/signal';
3+
4+
import {gecutSnackBar, type SnackBarContent} from './snack-bar.js';
5+
6+
import {repeat} from 'lit/directives/repeat.js';
7+
8+
export interface SnackBarManagerContent {
9+
gapBottom: string;
10+
}
11+
12+
export class SnackBarManager {
13+
constructor(content: SnackBarManagerContent) {
14+
this.content = content;
15+
this.snackBars.value = [];
16+
17+
// this.html = html`${gecutContext<'open' | 'close'>(this.controller, (status) => {
18+
// const dialogContent: DialogContent = {...this.content, controller: this.controller, provider: this.provider};
19+
20+
// return gecutDialog(dialogContent, status === 'open');
21+
// })}`;
22+
23+
// this.controller.value = 'close';
24+
}
25+
26+
content: SnackBarManagerContent;
27+
snackBars = new ContextSignal<[string, SnackBarContent, {open: true}][]>('snack-bars');
28+
html = gecutContext(this.snackBars, (snackBars) =>
29+
repeat(
30+
snackBars,
31+
(snackBar) => snackBar[0],
32+
(snackBar) => gecutSnackBar(snackBar[1]),
33+
),
34+
);
35+
36+
open(id: string, content: SnackBarContent) {
37+
this.snackBars.functionalValue((old) => [[id, content, {open: true}], ...(old ?? [])]);
38+
}
39+
40+
// onAfterClose() {
41+
// return new Promise<string>((resolve) => {
42+
// this.provider.subscribe(resolve, {
43+
// receivePrevious: false,
44+
// once: true,
45+
// priority: 1000,
46+
// });
47+
// });
48+
// }
49+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import {GecutDirective} from '@gecut/lit-helper/directives/directive.js';
2+
import {noChange, nothing, html} from 'lit/html.js';
3+
import {type PartInfo, directive} from 'lit/directive.js';
4+
import {gecutButton, type ButtonContent} from '../button/button.js';
5+
import {gecutIconButton, type IconButtonContent} from '../components.js';
6+
import {classMap, type ClassInfo} from 'lit/directives/class-map.js';
7+
8+
export interface SnackBarContent {
9+
message: string;
10+
11+
action?: Omit<ButtonContent, 'type'>;
12+
close?: boolean | Omit<IconButtonContent, 'type'>;
13+
}
14+
15+
export class GecutSnackBarDirective extends GecutDirective {
16+
constructor(partInfo: PartInfo) {
17+
super(partInfo, 'gecut-snack-bar');
18+
}
19+
20+
protected content?: SnackBarContent;
21+
22+
render(content?: SnackBarContent): unknown {
23+
this.log.methodArgs?.('render', content);
24+
25+
if (content === undefined) return noChange;
26+
27+
this.content = content;
28+
29+
return this.renderSnackBar();
30+
}
31+
32+
protected renderSnackBar() {
33+
if (!this.content) return nothing;
34+
35+
this.log.method?.('renderSnackBar');
36+
37+
return html`
38+
<div class=${classMap(this.getRenderClasses())}>
39+
<span class="gecut-snack-bar-message">${this.content.message}</span>
40+
${this.renderAction()} ${this.renderClose()}
41+
</div>
42+
`;
43+
}
44+
protected renderAction(): unknown {
45+
if (!this.content?.action) return nothing;
46+
47+
this.log.method?.('renderAction');
48+
49+
return gecutButton({...this.content.action, type: 'text'});
50+
}
51+
protected renderClose(): unknown {
52+
if (!this.content?.close) return nothing;
53+
54+
this.log.method?.('renderClose');
55+
56+
return gecutIconButton({
57+
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-dasharray="12" stroke-dashoffset="12" stroke-linecap="round" stroke-width="2" d="M12 12L19 19M12 12L5 5M12 12L5 19M12 12L19 5"><animate fill="freeze" attributeName="stroke-dashoffset" dur="1.2s" values="12;0"/></path></svg>',
58+
59+
...(typeof this.content.close !== 'boolean' ? this.content.close : {}),
60+
});
61+
}
62+
63+
protected override getRenderClasses(): ClassInfo {
64+
return {
65+
...super.getRenderClasses(),
66+
67+
'longer-action': (this.content?.action?.label?.length ?? 0) > 10,
68+
};
69+
}
70+
}
71+
72+
export const gecutSnackBar = directive(GecutSnackBarDirective);

packages/i18n/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
"url": "https://github.com/gecut/hybrid-ui/issues"
3333
},
3434
"dependencies": {
35-
"@gecut/logger": "^1.4.3",
36-
"@gecut/signal": "^2.2.1",
35+
"@gecut/logger": "^1.4.4",
36+
"@gecut/signal": "^2.2.2",
3737
"@gecut/types": "^2.2.1",
3838
"type-fest": "^4.13.0"
3939
}

packages/i18n/src/i18n.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export class GecutI18N implements I18nInterface {
4242
html.dir = this.locale.dir;
4343
}
4444

45-
this.context.setValue(this.locale);
45+
this.context.value = this.locale;
4646
}
4747

4848
msg(source: string, variables: Record<`{${number}}`, string> = {}): string {

packages/lit-helper/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
},
3838
"dependencies": {
3939
"@gecut/data-manager": "^1.2.3",
40-
"@gecut/logger": "^1.4.3",
40+
"@gecut/logger": "^1.4.4",
4141
"@gecut/mixins": "workspace:^",
42-
"@gecut/signal": "^2.2.1",
42+
"@gecut/signal": "^2.2.2",
4343
"@gecut/types": "^2.2.1",
44-
"@gecut/utilities": "^5.3.0",
44+
"@gecut/utilities": "^5.4.0",
4545
"@material/web": "^1.4.1",
4646
"@vaadin/router": "^1.7.5",
4747
"lit": "^3.1.3",

packages/mixins/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@
5656
"directory": "packages/mixins"
5757
},
5858
"dependencies": {
59-
"@gecut/logger": "^1.4.3",
60-
"@gecut/signal": "^2.2.1",
59+
"@gecut/logger": "^1.4.4",
60+
"@gecut/signal": "^2.2.2",
6161
"@gecut/types": "^2.2.1",
62-
"@gecut/utilities": "^5.3.0",
62+
"@gecut/utilities": "^5.4.0",
6363
"lit": "^3.1.3"
6464
}
6565
}

packages/styles/src/components/components.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
@import './icon.css';
55
@import './item.css';
66
@import './list.css';
7+
@import './snack-bar.css';
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
@layer components {
2+
.gecut-snack-bar {
3+
&.open {
4+
@apply flex animate-fadeInSlide;
5+
}
6+
&.close {
7+
@apply flex animate-fadeOutSlide;
8+
}
9+
10+
&.longer-action {
11+
.gecut-button.text {
12+
@apply self-end;
13+
}
14+
.gecut-icon-button.normal {
15+
@apply hidden;
16+
}
17+
18+
@apply flex-col items-baseline pb-1;
19+
}
20+
21+
&-message {
22+
@apply text-inverseOnSurface text-bodyMedium grow my-3.5;
23+
}
24+
25+
.gecut-button.text {
26+
@apply text-inversePrimary text-labelLarge px-4;
27+
}
28+
29+
.gecut-icon-button.normal {
30+
@apply text-inverseOnSurface m-0;
31+
}
32+
33+
@apply hidden items-center bg-inverseSurface elevation-3 rounded min-h-12 ps-4 pe-1;
34+
}
35+
}

0 commit comments

Comments
 (0)