From 86b6dce747a8a9c11ebf478fa5b8572fa6f65f59 Mon Sep 17 00:00:00 2001 From: Ivan Balias Date: Thu, 7 Nov 2024 22:07:41 +0200 Subject: [PATCH] initialize project --- .editorconfig | 16 + .eslintrc.json | 77 ++ .github/workflows/deploy.yml | 55 ++ .gitignore | 45 ++ .prettierignore | 6 + .prettierrc | 25 + CNAME | 1 + README.md | 12 + angular.json | 169 +++++ karma.conf.js | 44 ++ package.json | 53 ++ proxy.conf.json | 10 + src/app/app.component.html | 1 + src/app/app.component.scss | 0 src/app/app.component.ts | 8 + src/app/app.module.ts | 174 +++++ src/app/core/animations/core.animations.ts | 80 ++ src/app/core/core.module.ts | 54 ++ .../boolean/boolean.component.html | 11 + .../boolean/boolean.component.scss | 0 .../boolean/boolean.component.ts | 19 + .../button/button.component.html | 5 + .../button/button.component.scss | 66 ++ .../formcomponents/button/button.component.ts | 26 + .../formcomponents/date/date.component.html | 12 + .../formcomponents/date/date.component.scss | 0 .../formcomponents/date/date.component.ts | 19 + .../formcomponents/email/email.component.html | 17 + .../formcomponents/email/email.component.scss | 0 .../formcomponents/email/email.component.ts | 19 + .../formcomponents/formcomponents.module.ts | 115 +++ .../number/number.component.html | 12 + .../number/number.component.scss | 0 .../formcomponents/number/number.component.ts | 16 + .../password/password.component.html | 34 + .../password/password.component.scss | 95 +++ .../password/password.component.ts | 19 + .../formcomponents/photo/photo.component.html | 10 + .../formcomponents/photo/photo.component.scss | 0 .../formcomponents/photo/photo.component.ts | 15 + .../photos/photos.component.html | 12 + .../photos/photos.component.scss | 0 .../formcomponents/photos/photos.component.ts | 15 + .../select/select.component.html | 16 + .../select/select.component.scss | 232 ++++++ .../formcomponents/select/select.component.ts | 23 + .../formcomponents/tags/tags.component.html | 19 + .../formcomponents/tags/tags.component.scss | 0 .../formcomponents/tags/tags.component.ts | 35 + .../formcomponents/text/text.component.html | 15 + .../formcomponents/text/text.component.scss | 0 .../formcomponents/text/text.component.ts | 19 + .../formcomponents/time/time.component.html | 12 + .../formcomponents/time/time.component.scss | 0 .../formcomponents/time/time.component.ts | 15 + src/app/core/guards/admins.guard.ts | 23 + src/app/core/guards/authenticated.guard.ts | 17 + src/app/core/guards/guest.guard.ts | 17 + src/app/core/icons/icons.module.ts | 14 + .../core/icons/spider/spider.component.html | 63 ++ .../core/icons/spider/spider.component.scss | 0 src/app/core/icons/spider/spider.component.ts | 10 + src/app/core/modules/button/.gitignore | 104 +++ src/app/core/modules/button/LICENSE | 21 + src/app/core/modules/button/README.md | 108 +++ .../core/modules/button/button.component.html | 19 + .../core/modules/button/button.component.scss | 0 .../core/modules/button/button.component.ts | 82 +++ src/app/core/modules/button/button.module.ts | 11 + src/app/core/modules/button/module.json | 3 + src/app/core/modules/calendar/.gitignore | 104 +++ src/app/core/modules/calendar/LICENSE | 21 + src/app/core/modules/calendar/README.md | 1 + .../modules/calendar/calendar.component.html | 286 ++++++++ .../modules/calendar/calendar.component.scss | 225 ++++++ .../modules/calendar/calendar.component.ts | 226 ++++++ .../modules/calendar/calendar.interface.ts | 5 + .../core/modules/calendar/calendar.module.ts | 11 + src/app/core/modules/calendar/module.json | 3 + src/app/core/modules/card/.gitignore | 104 +++ src/app/core/modules/card/LICENSE | 21 + src/app/core/modules/card/README.md | 117 +++ src/app/core/modules/card/card.component.html | 16 + src/app/core/modules/card/card.component.scss | 44 ++ src/app/core/modules/card/card.component.ts | 42 ++ src/app/core/modules/card/card.module.ts | 13 + src/app/core/modules/card/module.json | 3 + src/app/core/modules/collapse/.gitignore | 104 +++ src/app/core/modules/collapse/LICENSE | 21 + src/app/core/modules/collapse/README.md | 23 + .../modules/collapse/collapse.component.html | 19 + .../modules/collapse/collapse.component.scss | 18 + .../modules/collapse/collapse.component.ts | 34 + .../modules/collapse/collapse.interface.ts | 6 + .../core/modules/collapse/collapse.module.ts | 11 + src/app/core/modules/collapse/module.json | 3 + .../file-cropper/file-cropper.component.html | 14 + .../file-cropper/file-cropper.component.scss | 0 .../file-cropper/file-cropper.component.ts | 25 + src/app/core/modules/file/file.component.html | 22 + src/app/core/modules/file/file.component.scss | 70 ++ src/app/core/modules/file/file.component.ts | 159 ++++ src/app/core/modules/file/file.module.ts | 13 + src/app/core/modules/file/file.service.ts | 40 + src/app/core/modules/file/module.json | 10 + src/app/core/modules/file/readme.MD | 115 +++ .../form-component.component.html | 42 ++ .../form-component.component.scss | 63 ++ .../form-component.component.ts | 138 ++++ src/app/core/modules/form/form.component.html | 19 + src/app/core/modules/form/form.component.scss | 0 src/app/core/modules/form/form.component.ts | 85 +++ src/app/core/modules/form/form.module.ts | 21 + src/app/core/modules/form/form.service.ts | 298 ++++++++ .../form/interfaces/component.interface.ts | 30 + .../modules/form/interfaces/form.interface.ts | 12 + .../modal-form-button.component.html | 13 + .../modal-form-button.component.scss | 0 .../modal-form-button.component.ts | 25 + .../modal-form/modal-form.component.html | 18 + .../modal-form/modal-form.component.scss | 9 + .../modals/modal-form/modal-form.component.ts | 30 + .../modal-unique/modal-unique.component.html | 1 + .../modal-unique/modal-unique.component.scss | 0 .../modal-unique/modal-unique.component.ts | 34 + src/app/core/modules/input/.gitignore | 104 +++ src/app/core/modules/input/LICENSE | 21 + src/app/core/modules/input/README.md | 118 +++ .../core/modules/input/input.component.html | 90 +++ .../core/modules/input/input.component.scss | 190 +++++ src/app/core/modules/input/input.component.ts | 207 ++++++ src/app/core/modules/input/input.module.ts | 12 + src/app/core/modules/input/module.json | 3 + src/app/core/modules/list/.gitignore | 104 +++ src/app/core/modules/list/LICENSE | 21 + src/app/core/modules/list/README.md | 103 +++ src/app/core/modules/list/list.component.html | 15 + src/app/core/modules/list/list.component.scss | 32 + src/app/core/modules/list/list.component.ts | 122 ++++ src/app/core/modules/list/list.directive.ts | 8 + src/app/core/modules/list/list.module.ts | 12 + src/app/core/modules/list/module.json | 3 + src/app/core/modules/select/.gitignore | 104 +++ src/app/core/modules/select/LICENSE | 21 + src/app/core/modules/select/README.md | 121 ++++ src/app/core/modules/select/module.json | 3 + .../core/modules/select/select.component.html | 165 +++++ .../core/modules/select/select.component.scss | 236 ++++++ .../core/modules/select/select.component.ts | 165 +++++ src/app/core/modules/select/select.module.ts | 13 + src/app/core/modules/table/README.md | 77 ++ src/app/core/modules/table/module.json | 6 + src/app/core/modules/table/per-page.pipe.ts | 49 ++ .../core/modules/table/table.component.html | 341 +++++++++ .../core/modules/table/table.component.scss | 475 ++++++++++++ src/app/core/modules/table/table.component.ts | 275 +++++++ src/app/core/modules/table/table.directive.ts | 57 ++ src/app/core/modules/table/table.module.ts | 45 ++ src/app/core/modules/translate/.gitignore | 104 +++ src/app/core/modules/translate/LICENSE | 21 + src/app/core/modules/translate/README.md | 72 ++ src/app/core/modules/translate/languages.ts | 682 ++++++++++++++++++ src/app/core/modules/translate/module.json | 3 + .../translates/translates.component.html | 70 ++ .../translates/translates.component.scss | 193 +++++ .../pages/translates/translates.component.ts | 185 +++++ .../pages/translates/translates.module.ts | 33 + .../modules/translate/translate.directive.ts | 22 + .../modules/translate/translate.module.ts | 14 + .../core/modules/translate/translate.pipe.ts | 19 + .../modules/translate/translate.service.ts | 323 +++++++++ .../test/test-selector.component.html | 5 + .../test/test-selector.component.scss | 0 .../selectors/test/test-selector.component.ts | 32 + src/app/core/services/test.service.ts | 44 ++ src/app/core/theme/guest/guest.component.html | 1 + src/app/core/theme/guest/guest.component.scss | 0 src/app/core/theme/guest/guest.component.ts | 8 + src/app/core/theme/user/user.component.html | 95 +++ src/app/core/theme/user/user.component.scss | 305 ++++++++ src/app/core/theme/user/user.component.ts | 24 + .../customforms/customforms.component.html | 22 + .../customforms/customforms.component.scss | 0 .../customforms/customforms.component.ts | 356 +++++++++ .../pages/customforms/customforms.module.ts | 23 + .../mutate-form/mutate-form.component.html | 88 +++ .../mutate-form/mutate-form.component.scss | 153 ++++ .../mutate-form/mutate-form.component.ts | 34 + .../customform/services/customform.service.ts | 71 ++ src/app/modules/user/LICENSE | 21 + src/app/modules/user/README.md | 1 + .../modules/user/interfaces/user.interface.ts | 11 + src/app/modules/user/module.json | 3 + .../user/pages/clients/clients.component.html | 8 + .../user/pages/clients/clients.component.scss | 73 ++ .../user/pages/clients/clients.component.ts | 134 ++++ .../user/pages/clients/clients.module.ts | 23 + .../user/pages/users/users.component.html | 11 + .../user/pages/users/users.component.scss | 73 ++ .../user/pages/users/users.component.ts | 91 +++ .../modules/user/pages/users/users.module.ts | 18 + .../user/user-selector.component.html | 5 + .../user/user-selector.component.scss | 0 .../selectors/user/user-selector.component.ts | 31 + src/app/modules/user/services/user.service.ts | 169 +++++ src/app/pages/guest/sign/sign.component.html | 29 + src/app/pages/guest/sign/sign.component.scss | 217 ++++++ src/app/pages/guest/sign/sign.component.ts | 199 +++++ src/app/pages/guest/sign/sign.module.ts | 18 + .../pages/user/profile/profile.component.html | 48 ++ .../pages/user/profile/profile.component.scss | 104 +++ .../pages/user/profile/profile.component.ts | 159 ++++ src/app/pages/user/profile/profile.module.ts | 19 + src/assets/default.png | Bin 0 -> 8297 bytes src/assets/favicon.ico | Bin 0 -> 15406 bytes src/assets/logo.png | Bin 0 -> 8297 bytes src/environments/environment.prod.ts | 6 + src/environments/environment.ts | 18 + src/favicon.ico | Bin 0 -> 948 bytes src/fonts/1.woff2 | Bin 0 -> 52316 bytes src/fonts/2.woff2 | Bin 0 -> 52456 bytes src/fonts/3.woff2 | Bin 0 -> 51692 bytes src/fonts/4.woff2 | Bin 0 -> 51800 bytes src/fonts/5.woff2 | Bin 0 -> 115204 bytes src/index.html | 41 ++ src/main.ts | 13 + src/polyfills.ts | 55 ++ src/scss/Classes.md | 69 ++ src/scss/Readme.md | 61 ++ src/scss/atom/display.scss | 41 ++ src/scss/atom/margin.scss | 52 ++ src/scss/atom/other.scss | 4 + src/scss/atom/padding.scss | 51 ++ src/scss/atom/size.scss | 9 + src/scss/atom/text.scss | 34 + src/scss/components/Readme.md | 118 +++ src/scss/components/_w-alert.scss | 546 ++++++++++++++ src/scss/components/_w-btn.scss | 69 ++ src/scss/components/_w-card.scss | 53 ++ src/scss/components/_w-checkbox.scss | 83 +++ src/scss/components/_w-forms.scss | 101 +++ src/scss/components/_w-modal.scss | 82 +++ src/scss/components/_w-radio.scss | 52 ++ src/scss/components/_w-select.scss | 236 ++++++ src/scss/components/_w-switch.scss | 59 ++ src/scss/components/_w-table.scss | 478 ++++++++++++ src/scss/index.scss | 51 ++ src/scss/layout/_base.scss | 36 + src/scss/layout/_grid.scss | 58 ++ src/scss/layout/_scroll.scss | 17 + src/scss/utils/_fonts.scss | 28 + src/scss/utils/_icons.scss | 21 + src/scss/utils/_media.scss | 44 ++ src/scss/utils/_mixins.scss | 14 + src/scss/utils/_vars.scss | 119 +++ src/scss/utils/angular.scss | 4 + src/scss/vendors/_normalize.scss | 98 +++ src/styles.scss | 1 + src/test.ts | 14 + tsconfig.app.json | 15 + tsconfig.json | 33 + tsconfig.spec.json | 18 + 262 files changed, 15719 insertions(+) create mode 100644 .editorconfig create mode 100644 .eslintrc.json create mode 100644 .github/workflows/deploy.yml create mode 100644 .gitignore create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 CNAME create mode 100644 README.md create mode 100644 angular.json create mode 100644 karma.conf.js create mode 100644 package.json create mode 100644 proxy.conf.json create mode 100644 src/app/app.component.html create mode 100644 src/app/app.component.scss create mode 100644 src/app/app.component.ts create mode 100644 src/app/app.module.ts create mode 100644 src/app/core/animations/core.animations.ts create mode 100644 src/app/core/core.module.ts create mode 100644 src/app/core/formcomponents/boolean/boolean.component.html create mode 100644 src/app/core/formcomponents/boolean/boolean.component.scss create mode 100644 src/app/core/formcomponents/boolean/boolean.component.ts create mode 100644 src/app/core/formcomponents/button/button.component.html create mode 100644 src/app/core/formcomponents/button/button.component.scss create mode 100644 src/app/core/formcomponents/button/button.component.ts create mode 100644 src/app/core/formcomponents/date/date.component.html create mode 100644 src/app/core/formcomponents/date/date.component.scss create mode 100644 src/app/core/formcomponents/date/date.component.ts create mode 100644 src/app/core/formcomponents/email/email.component.html create mode 100644 src/app/core/formcomponents/email/email.component.scss create mode 100644 src/app/core/formcomponents/email/email.component.ts create mode 100644 src/app/core/formcomponents/formcomponents.module.ts create mode 100644 src/app/core/formcomponents/number/number.component.html create mode 100644 src/app/core/formcomponents/number/number.component.scss create mode 100644 src/app/core/formcomponents/number/number.component.ts create mode 100644 src/app/core/formcomponents/password/password.component.html create mode 100644 src/app/core/formcomponents/password/password.component.scss create mode 100644 src/app/core/formcomponents/password/password.component.ts create mode 100644 src/app/core/formcomponents/photo/photo.component.html create mode 100644 src/app/core/formcomponents/photo/photo.component.scss create mode 100644 src/app/core/formcomponents/photo/photo.component.ts create mode 100644 src/app/core/formcomponents/photos/photos.component.html create mode 100644 src/app/core/formcomponents/photos/photos.component.scss create mode 100644 src/app/core/formcomponents/photos/photos.component.ts create mode 100644 src/app/core/formcomponents/select/select.component.html create mode 100644 src/app/core/formcomponents/select/select.component.scss create mode 100644 src/app/core/formcomponents/select/select.component.ts create mode 100644 src/app/core/formcomponents/tags/tags.component.html create mode 100644 src/app/core/formcomponents/tags/tags.component.scss create mode 100644 src/app/core/formcomponents/tags/tags.component.ts create mode 100644 src/app/core/formcomponents/text/text.component.html create mode 100644 src/app/core/formcomponents/text/text.component.scss create mode 100644 src/app/core/formcomponents/text/text.component.ts create mode 100644 src/app/core/formcomponents/time/time.component.html create mode 100644 src/app/core/formcomponents/time/time.component.scss create mode 100644 src/app/core/formcomponents/time/time.component.ts create mode 100644 src/app/core/guards/admins.guard.ts create mode 100644 src/app/core/guards/authenticated.guard.ts create mode 100644 src/app/core/guards/guest.guard.ts create mode 100644 src/app/core/icons/icons.module.ts create mode 100644 src/app/core/icons/spider/spider.component.html create mode 100644 src/app/core/icons/spider/spider.component.scss create mode 100644 src/app/core/icons/spider/spider.component.ts create mode 100644 src/app/core/modules/button/.gitignore create mode 100644 src/app/core/modules/button/LICENSE create mode 100644 src/app/core/modules/button/README.md create mode 100644 src/app/core/modules/button/button.component.html create mode 100644 src/app/core/modules/button/button.component.scss create mode 100644 src/app/core/modules/button/button.component.ts create mode 100644 src/app/core/modules/button/button.module.ts create mode 100644 src/app/core/modules/button/module.json create mode 100644 src/app/core/modules/calendar/.gitignore create mode 100644 src/app/core/modules/calendar/LICENSE create mode 100644 src/app/core/modules/calendar/README.md create mode 100644 src/app/core/modules/calendar/calendar.component.html create mode 100644 src/app/core/modules/calendar/calendar.component.scss create mode 100644 src/app/core/modules/calendar/calendar.component.ts create mode 100644 src/app/core/modules/calendar/calendar.interface.ts create mode 100644 src/app/core/modules/calendar/calendar.module.ts create mode 100644 src/app/core/modules/calendar/module.json create mode 100644 src/app/core/modules/card/.gitignore create mode 100644 src/app/core/modules/card/LICENSE create mode 100644 src/app/core/modules/card/README.md create mode 100644 src/app/core/modules/card/card.component.html create mode 100644 src/app/core/modules/card/card.component.scss create mode 100644 src/app/core/modules/card/card.component.ts create mode 100644 src/app/core/modules/card/card.module.ts create mode 100644 src/app/core/modules/card/module.json create mode 100644 src/app/core/modules/collapse/.gitignore create mode 100644 src/app/core/modules/collapse/LICENSE create mode 100644 src/app/core/modules/collapse/README.md create mode 100644 src/app/core/modules/collapse/collapse.component.html create mode 100644 src/app/core/modules/collapse/collapse.component.scss create mode 100644 src/app/core/modules/collapse/collapse.component.ts create mode 100644 src/app/core/modules/collapse/collapse.interface.ts create mode 100644 src/app/core/modules/collapse/collapse.module.ts create mode 100644 src/app/core/modules/collapse/module.json create mode 100644 src/app/core/modules/file/file-cropper/file-cropper.component.html create mode 100644 src/app/core/modules/file/file-cropper/file-cropper.component.scss create mode 100644 src/app/core/modules/file/file-cropper/file-cropper.component.ts create mode 100644 src/app/core/modules/file/file.component.html create mode 100644 src/app/core/modules/file/file.component.scss create mode 100644 src/app/core/modules/file/file.component.ts create mode 100644 src/app/core/modules/file/file.module.ts create mode 100644 src/app/core/modules/file/file.service.ts create mode 100644 src/app/core/modules/file/module.json create mode 100644 src/app/core/modules/file/readme.MD create mode 100644 src/app/core/modules/form/form-component/form-component.component.html create mode 100644 src/app/core/modules/form/form-component/form-component.component.scss create mode 100644 src/app/core/modules/form/form-component/form-component.component.ts create mode 100644 src/app/core/modules/form/form.component.html create mode 100644 src/app/core/modules/form/form.component.scss create mode 100644 src/app/core/modules/form/form.component.ts create mode 100644 src/app/core/modules/form/form.module.ts create mode 100644 src/app/core/modules/form/form.service.ts create mode 100644 src/app/core/modules/form/interfaces/component.interface.ts create mode 100644 src/app/core/modules/form/interfaces/form.interface.ts create mode 100644 src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.html create mode 100644 src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.scss create mode 100644 src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.ts create mode 100644 src/app/core/modules/form/modals/modal-form/modal-form.component.html create mode 100644 src/app/core/modules/form/modals/modal-form/modal-form.component.scss create mode 100644 src/app/core/modules/form/modals/modal-form/modal-form.component.ts create mode 100644 src/app/core/modules/form/modals/modal-unique/modal-unique.component.html create mode 100644 src/app/core/modules/form/modals/modal-unique/modal-unique.component.scss create mode 100644 src/app/core/modules/form/modals/modal-unique/modal-unique.component.ts create mode 100644 src/app/core/modules/input/.gitignore create mode 100644 src/app/core/modules/input/LICENSE create mode 100644 src/app/core/modules/input/README.md create mode 100644 src/app/core/modules/input/input.component.html create mode 100644 src/app/core/modules/input/input.component.scss create mode 100644 src/app/core/modules/input/input.component.ts create mode 100644 src/app/core/modules/input/input.module.ts create mode 100644 src/app/core/modules/input/module.json create mode 100644 src/app/core/modules/list/.gitignore create mode 100644 src/app/core/modules/list/LICENSE create mode 100644 src/app/core/modules/list/README.md create mode 100644 src/app/core/modules/list/list.component.html create mode 100644 src/app/core/modules/list/list.component.scss create mode 100644 src/app/core/modules/list/list.component.ts create mode 100644 src/app/core/modules/list/list.directive.ts create mode 100644 src/app/core/modules/list/list.module.ts create mode 100644 src/app/core/modules/list/module.json create mode 100644 src/app/core/modules/select/.gitignore create mode 100644 src/app/core/modules/select/LICENSE create mode 100644 src/app/core/modules/select/README.md create mode 100644 src/app/core/modules/select/module.json create mode 100644 src/app/core/modules/select/select.component.html create mode 100644 src/app/core/modules/select/select.component.scss create mode 100644 src/app/core/modules/select/select.component.ts create mode 100644 src/app/core/modules/select/select.module.ts create mode 100644 src/app/core/modules/table/README.md create mode 100644 src/app/core/modules/table/module.json create mode 100644 src/app/core/modules/table/per-page.pipe.ts create mode 100644 src/app/core/modules/table/table.component.html create mode 100644 src/app/core/modules/table/table.component.scss create mode 100644 src/app/core/modules/table/table.component.ts create mode 100644 src/app/core/modules/table/table.directive.ts create mode 100644 src/app/core/modules/table/table.module.ts create mode 100644 src/app/core/modules/translate/.gitignore create mode 100644 src/app/core/modules/translate/LICENSE create mode 100644 src/app/core/modules/translate/README.md create mode 100644 src/app/core/modules/translate/languages.ts create mode 100644 src/app/core/modules/translate/module.json create mode 100644 src/app/core/modules/translate/pages/translates/translates.component.html create mode 100644 src/app/core/modules/translate/pages/translates/translates.component.scss create mode 100644 src/app/core/modules/translate/pages/translates/translates.component.ts create mode 100644 src/app/core/modules/translate/pages/translates/translates.module.ts create mode 100644 src/app/core/modules/translate/translate.directive.ts create mode 100644 src/app/core/modules/translate/translate.module.ts create mode 100644 src/app/core/modules/translate/translate.pipe.ts create mode 100644 src/app/core/modules/translate/translate.service.ts create mode 100644 src/app/core/selectors/test/test-selector.component.html create mode 100644 src/app/core/selectors/test/test-selector.component.scss create mode 100644 src/app/core/selectors/test/test-selector.component.ts create mode 100644 src/app/core/services/test.service.ts create mode 100644 src/app/core/theme/guest/guest.component.html create mode 100644 src/app/core/theme/guest/guest.component.scss create mode 100644 src/app/core/theme/guest/guest.component.ts create mode 100644 src/app/core/theme/user/user.component.html create mode 100644 src/app/core/theme/user/user.component.scss create mode 100644 src/app/core/theme/user/user.component.ts create mode 100644 src/app/modules/customform/pages/customforms/customforms.component.html create mode 100644 src/app/modules/customform/pages/customforms/customforms.component.scss create mode 100644 src/app/modules/customform/pages/customforms/customforms.component.ts create mode 100644 src/app/modules/customform/pages/customforms/customforms.module.ts create mode 100644 src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.html create mode 100644 src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.scss create mode 100644 src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.ts create mode 100644 src/app/modules/customform/services/customform.service.ts create mode 100644 src/app/modules/user/LICENSE create mode 100644 src/app/modules/user/README.md create mode 100644 src/app/modules/user/interfaces/user.interface.ts create mode 100644 src/app/modules/user/module.json create mode 100644 src/app/modules/user/pages/clients/clients.component.html create mode 100644 src/app/modules/user/pages/clients/clients.component.scss create mode 100644 src/app/modules/user/pages/clients/clients.component.ts create mode 100644 src/app/modules/user/pages/clients/clients.module.ts create mode 100644 src/app/modules/user/pages/users/users.component.html create mode 100644 src/app/modules/user/pages/users/users.component.scss create mode 100644 src/app/modules/user/pages/users/users.component.ts create mode 100644 src/app/modules/user/pages/users/users.module.ts create mode 100644 src/app/modules/user/selectors/user/user-selector.component.html create mode 100644 src/app/modules/user/selectors/user/user-selector.component.scss create mode 100644 src/app/modules/user/selectors/user/user-selector.component.ts create mode 100644 src/app/modules/user/services/user.service.ts create mode 100644 src/app/pages/guest/sign/sign.component.html create mode 100644 src/app/pages/guest/sign/sign.component.scss create mode 100644 src/app/pages/guest/sign/sign.component.ts create mode 100644 src/app/pages/guest/sign/sign.module.ts create mode 100644 src/app/pages/user/profile/profile.component.html create mode 100644 src/app/pages/user/profile/profile.component.scss create mode 100644 src/app/pages/user/profile/profile.component.ts create mode 100644 src/app/pages/user/profile/profile.module.ts create mode 100644 src/assets/default.png create mode 100644 src/assets/favicon.ico create mode 100644 src/assets/logo.png create mode 100644 src/environments/environment.prod.ts create mode 100644 src/environments/environment.ts create mode 100644 src/favicon.ico create mode 100644 src/fonts/1.woff2 create mode 100644 src/fonts/2.woff2 create mode 100644 src/fonts/3.woff2 create mode 100644 src/fonts/4.woff2 create mode 100644 src/fonts/5.woff2 create mode 100644 src/index.html create mode 100644 src/main.ts create mode 100644 src/polyfills.ts create mode 100644 src/scss/Classes.md create mode 100644 src/scss/Readme.md create mode 100644 src/scss/atom/display.scss create mode 100644 src/scss/atom/margin.scss create mode 100644 src/scss/atom/other.scss create mode 100644 src/scss/atom/padding.scss create mode 100644 src/scss/atom/size.scss create mode 100644 src/scss/atom/text.scss create mode 100644 src/scss/components/Readme.md create mode 100644 src/scss/components/_w-alert.scss create mode 100644 src/scss/components/_w-btn.scss create mode 100644 src/scss/components/_w-card.scss create mode 100644 src/scss/components/_w-checkbox.scss create mode 100644 src/scss/components/_w-forms.scss create mode 100644 src/scss/components/_w-modal.scss create mode 100644 src/scss/components/_w-radio.scss create mode 100644 src/scss/components/_w-select.scss create mode 100644 src/scss/components/_w-switch.scss create mode 100644 src/scss/components/_w-table.scss create mode 100644 src/scss/index.scss create mode 100644 src/scss/layout/_base.scss create mode 100644 src/scss/layout/_grid.scss create mode 100644 src/scss/layout/_scroll.scss create mode 100644 src/scss/utils/_fonts.scss create mode 100644 src/scss/utils/_icons.scss create mode 100644 src/scss/utils/_media.scss create mode 100644 src/scss/utils/_mixins.scss create mode 100644 src/scss/utils/_vars.scss create mode 100644 src/scss/utils/angular.scss create mode 100644 src/scss/vendors/_normalize.scss create mode 100644 src/styles.scss create mode 100644 src/test.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.spec.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3d9a482 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = tab +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..7a39eaa --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,77 @@ +{ + "root": true, + "ignorePatterns": ["projects/**/*"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": [ + "../../tsconfig.json", + "tsconfig.json", + "e2e/tsconfig.json" + ], + "createDefaultProgram": true + }, + "extends": [ + "plugin:@angular-eslint/recommended", + "plugin:@angular-eslint/template/process-inline-templates", + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:prettier/recommended" + ], + "rules": { + "no-console": "warn", + "@typescript-eslint/explicit-function-return-type": "error", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/unbound-method": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "variable", + "format": ["camelCase", "UPPER_CASE"] + } + ], + "lines-between-class-members": "off", + "@typescript-eslint/lines-between-class-members": "off", + "padding-line-between-statements": "off", + "@typescript-eslint/padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "prev": "*", + "next": "*" + }, + { + "blankLine": "never", + "prev": "import", + "next": "import" + }, + { + "blankLine": "never", + "prev": ["case", "default"], + "next": "*" + } + ], + "@typescript-eslint/explicit-member-accessibility": [ + "error", + { + "accessibility": "no-public" + } + ] + } + }, + { + "files": ["*.html"], + "extends": [ + "plugin:@angular-eslint/template/recommended", + "plugin:prettier/recommended" + ], + "rules": {} + } + ] +} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..4e6948b --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,55 @@ +name: Deploy to GitHub Pages + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Build Angular app + run: npm run build + + - name: Copy CNAME file + run: cp CNAME dist/app/browser/ + + - name: Set up SSH + env: + SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + run: | + mkdir -p ~/.ssh + echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + ssh-keyscan github.com >> ~/.ssh/known_hosts + + - name: Commit and push to gh-pages using SSH + env: + GIT_SSH_COMMAND: "ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no" + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + cd dist/app/browser + git init # Initialize a new git repository + git add --all . # Add all changes + git commit -m "Deploy to GitHub Pages" + git checkout -B gh-pages # Switch to gh-pages branch + git push git@github.com:${{ github.repository }} gh-pages --force + + - name: Clean up SSH + run: | + rm -f ~/.ssh/id_rsa + rm -f ~/.ssh/known_hosts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b62fff --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# Compiled output +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db +dist +.angular +.vscode +.husky diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..004bdca --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +package-lock.json +dist +.angular +.github +.vscode +*.yaml diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3d0f648 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,25 @@ +{ + "quoteProps": "as-needed", + "trailingComma": "none", + "bracketSpacing": true, + "arrowParens": "always", + "singleQuote": true, + "endOfLine": "auto", + "printWidth": 80, + "useTabs": true, + "tabWidth": 4, + "semi": true, + "overrides": [{ + "files": "*.component.html", + "options": { + "parser": "angular" + } + }, + { + "files": "*.html", + "options": { + "parser": "html" + } + } + ] +} diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..de9dc62 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +ngx.webart.work diff --git a/README.md b/README.md new file mode 100644 index 0000000..53f3156 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# App + +## CLI commands +[waw Angular CLI](https://github.com/WebArtWork/waw-angular) + +## Class Structure +1) readonly +2) variables +3) contructor +4) public functions +5) private variables +6) private functions diff --git a/angular.json b/angular.json new file mode 100644 index 0000000..72d7811 --- /dev/null +++ b/angular.json @@ -0,0 +1,169 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "app": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss", + "skipTests": true, + "standalone": false + }, + "@schematics/angular:class": { + "skipTests": true + }, + "@schematics/angular:directive": { + "skipTests": true + }, + "@schematics/angular:guard": { + "skipTests": true + }, + "@schematics/angular:interceptor": { + "skipTests": true + }, + "@schematics/angular:pipe": { + "skipTests": true + }, + "@schematics/angular:resolver": { + "skipTests": true + }, + "@schematics/angular:service": { + "skipTests": true + }, + "@schematics/angular:application": { + "strict": true + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:application", + "options": { + "outputPath": "dist/app", + "index": "src/index.html", + "polyfills": ["src/polyfills.ts"], + "tsConfig": "src/../tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": ["src/favicon.ico", "src/assets"], + "styles": ["src/styles.scss"], + "scripts": [], + "stylePreprocessorOptions": { + "includePaths": ["src/scss/utils", "."] + }, + "browser": "src/main.ts" + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "750kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "20kb", + "maximumError": "100kb" + } + ], + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "outputHashing": "all", + "outputPath": "dist/app" + }, + "docs": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "750kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "20kb", + "maximumError": "100kb" + } + ], + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "outputHashing": "all", + "outputPath": "docs" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true, + "outputPath": "dist/app" + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "app:build:production" + }, + "development": { + "buildTarget": "app:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "app:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "inlineStyleLanguage": "scss", + "assets": ["src/favicon.ico", "src/assets"], + "styles": ["src/styles.scss"], + "scripts": [], + "stylePreprocessorOptions": { + "includePaths": ["src/scss/utils"] + } + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"] + } + } + } + } + }, + "cli": { + "analytics": false, + "schematicCollections": ["@angular-eslint/schematics"] + }, + "schematics": { + "@angular-eslint/schematics:application": { + "setParserOptionsProject": true + }, + "@angular-eslint/schematics:library": { + "setParserOptionsProject": true + } + } +} diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..c6a90c1 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,44 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, './coverage/client'), + subdir: '.', + reporters: [ + { type: 'html' }, + { type: 'text-summary' } + ] + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..b2be4c1 --- /dev/null +++ b/package.json @@ -0,0 +1,53 @@ +{ + "name": "app", + "version": "1.0.0", + "scripts": { + "start": "ng serve -o --proxy-config proxy.conf.json", + "build": "ng build --configuration production" + }, + "private": true, + "dependencies": { + "@angular/animations": "^18.2.10", + "@angular/cdk": "^18.2.11", + "@angular/common": "^18.2.10", + "@angular/compiler": "^18.2.10", + "@angular/core": "^18.2.10", + "@angular/forms": "^18.2.10", + "@angular/platform-browser": "^18.2.10", + "@angular/platform-browser-dynamic": "^18.2.10", + "@angular/router": "^18.2.10", + "@types/node": "^20.1.5", + "ngx-image-cropper": "^7.1.1", + "rxjs": "~7.5.0", + "socket.io-client": "^4.5.1", + "tslib": "^2.3.0", + "wacom": "^18.2.7", + "zone.js": "~0.14.10" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^18.2.11", + "@angular-eslint/builder": "18.4.0", + "@angular-eslint/eslint-plugin": "18.4.0", + "@angular-eslint/eslint-plugin-template": "18.4.0", + "@angular-eslint/schematics": "18.4.0", + "@angular-eslint/template-parser": "18.4.0", + "@angular/cli": "~18.2.11", + "@angular/compiler-cli": "^18.2.10", + "@types/jasmine": "~4.3.0", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", + "husky": "^8.0.1", + "jasmine-core": "~4.6.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.0.0", + "prettier": "^2.7.1", + "prettier-eslint-cli": "^7.1.0", + "typescript": "~5.4.5" + } +} diff --git a/proxy.conf.json b/proxy.conf.json new file mode 100644 index 0000000..1c35bbb --- /dev/null +++ b/proxy.conf.json @@ -0,0 +1,10 @@ +{ + "/api": { + "target": "http://localhost:8080", + "secure": false + }, + "/waw": { + "target": "http://localhost:8080", + "secure": false + } +} diff --git a/src/app/app.component.html b/src/app/app.component.html new file mode 100644 index 0000000..0680b43 --- /dev/null +++ b/src/app/app.component.html @@ -0,0 +1 @@ + diff --git a/src/app/app.component.scss b/src/app/app.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/app.component.ts b/src/app/app.component.ts new file mode 100644 index 0000000..745cb8e --- /dev/null +++ b/src/app/app.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent {} diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100644 index 0000000..51a717d --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,174 @@ +import { RouterModule, Routes, PreloadAllModules } from '@angular/router'; +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +// Core +import { GuestComponent } from './core/theme/guest/guest.component'; +import { UserComponent } from './core/theme/user/user.component'; +import { AppComponent } from './app.component'; +import { CoreModule } from 'src/app/core/core.module'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +// config +import { WacomModule, MetaGuard } from 'wacom'; +import { environment } from 'src/environments/environment'; +import { AuthenticatedGuard } from './core/guards/authenticated.guard'; +import { GuestGuard } from './core/guards/guest.guard'; +import { AdminsGuard } from './core/guards/admins.guard'; +import { HashLocationStrategy, LocationStrategy } from '@angular/common'; + +const routes: Routes = [ + { + path: '', + redirectTo: '/sign', + pathMatch: 'full' + }, + { + path: '', + canActivate: [GuestGuard], + component: GuestComponent, + children: [ + /* guest */ + { + path: 'sign', + canActivate: [MetaGuard], + data: { + meta: { + title: 'Sign' + } + }, + loadChildren: () => + import('./pages/guest/sign/sign.module').then( + (m) => m.SignModule + ) + } + ] + }, + { + path: '', + canActivate: [AuthenticatedGuard], + component: UserComponent, + children: [ + /* user */ + { + path: 'profile', + canActivate: [MetaGuard], + data: { + meta: { + title: 'My Profile' + } + }, + loadChildren: () => + import('./pages/user/profile/profile.module').then( + (m) => m.ProfileModule + ) + } + ] + }, + { + path: 'admin', + canActivate: [AdminsGuard], + component: UserComponent, + children: [ + /* admin */ + { + path: 'users', + canActivate: [MetaGuard], + data: { + meta: { + title: 'Users' + } + }, + loadChildren: () => + import('./modules/user/pages/users/users.module').then( + (m) => m.UsersModule + ) + }, + { + path: 'forms', + canActivate: [MetaGuard], + data: { + meta: { + title: 'Forms' + } + }, + loadChildren: () => + import( + './modules/customform/pages/customforms/customforms.module' + ).then((m) => m.CustomformsModule) + }, + { + path: 'translates', + canActivate: [MetaGuard], + data: { + meta: { + title: 'Translates' + } + }, + loadChildren: () => + import( + './core/modules/translate/pages/translates/translates.module' + ).then((m) => m.TranslatesModule) + } + ] + }, + { + path: '**', + redirectTo: 'profile', + pathMatch: 'full' + } +]; + +@NgModule({ + declarations: [AppComponent, GuestComponent, UserComponent], + imports: [ + CoreModule, + BrowserModule, + BrowserAnimationsModule, + WacomModule.forRoot({ + store: {}, + http: { + url: environment.url + }, + socket: environment.production, + meta: { + useTitleSuffix: true, + defaults: { + title: 'Web Art Work', + titleSuffix: ' | Web Art Work', + 'og:image': 'https://webart.work/api/user/cdn/waw-logo.png' + } + }, + modal: { + modals: { + /* modals */ + } + }, + alert: { + alerts: { + /* alerts */ + } + }, + loader: { + loaders: { + /* loaders */ + } + }, + popup: { + popups: { + /* popups */ + } + } + }), + RouterModule.forRoot(routes, { + scrollPositionRestoration: 'enabled', + preloadingStrategy: PreloadAllModules + }) + ], + providers: [ + AuthenticatedGuard, + GuestGuard, + AdminsGuard, + { provide: LocationStrategy, useClass: HashLocationStrategy } + ], + bootstrap: [AppComponent] +}) +export class AppModule {} diff --git a/src/app/core/animations/core.animations.ts b/src/app/core/animations/core.animations.ts new file mode 100644 index 0000000..72fc79b --- /dev/null +++ b/src/app/core/animations/core.animations.ts @@ -0,0 +1,80 @@ +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; + +export const coreAnimation = [ + trigger('flyInOut', [ + state('in', style({ transform: 'translateX(0)' })), + transition('void => *', [ + style({ + transform: 'translateY(-10px)', + opacity: 0, + height: '0' + }), + animate(400) + ]), + transition('* => void', [ + animate( + 400, + style({ + opacity: 0, + height: '0', + transform: 'translateY(-10px)' + }) + ) + ]) + ]), + trigger('tabInOut', [ + state('in', style({ transform: 'translateX(0)' })), + transition('void => *', [ + style({ + transform: 'translateX(10px)', + opacity: 0 + }), + animate(300) + ]), + transition('* => void', [ + animate( + 300, + style({ + opacity: 0, + // height: '50px' + transform: 'translateX(10px)' + }) + ) + ]) + ]), + trigger('showInOut', [ + state('in', style({})), + transition('void => *', [ + style({ + opacity: 0 + }), + animate(300) + ]), + transition('* => void', [ + animate( + 300, + style({ + opacity: 0 + }) + ) + ]) + ]) +]; + +// Readme +// === html directive === +// (click)="variable" +// *ngIf="!variable" +// [@flyInOut]="variable" + +// === import to component === +// import { flyAnimation } from "./animation" +// @Component({ +// animations: [ flyAnimation ] +// }) diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts new file mode 100644 index 0000000..bdb05b2 --- /dev/null +++ b/src/app/core/core.module.ts @@ -0,0 +1,54 @@ +import { NgModule, Type } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { WacomModule } from 'wacom'; +import { ButtonModule } from 'src/app/core/modules/button/button.module'; +import { InputModule } from 'src/app/core/modules/input/input.module'; +import { CardModule } from 'src/app/core/modules/card/card.module'; +import { TableModule } from './modules/table/table.module'; +import { IconsModule } from './icons/icons.module'; +import { TranslateModule } from './modules/translate/translate.module'; +import { FormcomponentsModule } from './formcomponents/formcomponents.module'; +import { SelectModule } from './modules/select/select.module'; +import { FormModule } from './modules/form/form.module'; +/* imports */ + +const components: Type[] = [ + /* components */ +]; + +const selectors: Type[] = [ + /* selectors */ +]; + +const pipes: Type[] = [ + /* pipes */ +]; + +@NgModule({ + declarations: components.concat(selectors).concat(pipes), + exports: [ + TranslateModule, + SelectModule, + CommonModule, + FormsModule, + WacomModule, + ButtonModule, + InputModule, + CardModule, + FormModule, + TableModule, + IconsModule + ] + .concat(components) + .concat(selectors) + .concat(pipes), + imports: [ + FormcomponentsModule, + SelectModule, + CommonModule, + FormsModule, + WacomModule + ] +}) +export class CoreModule {} diff --git a/src/app/core/formcomponents/boolean/boolean.component.html b/src/app/core/formcomponents/boolean/boolean.component.html new file mode 100644 index 0000000..c8db08e --- /dev/null +++ b/src/app/core/formcomponents/boolean/boolean.component.html @@ -0,0 +1,11 @@ + + + diff --git a/src/app/core/formcomponents/boolean/boolean.component.scss b/src/app/core/formcomponents/boolean/boolean.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/boolean/boolean.component.ts b/src/app/core/formcomponents/boolean/boolean.component.ts new file mode 100644 index 0000000..4a9ad44 --- /dev/null +++ b/src/app/core/formcomponents/boolean/boolean.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; + +interface Interface {} + +@Component({ + templateUrl: './boolean.component.html', + styleUrl: './boolean.component.scss' +}) +export class BooleanComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + + constructor(private _form: FormService) {} + + ngOnInit(): void { + this._form.addTemplateComponent('Boolean', this.templateRef); + } +} diff --git a/src/app/core/formcomponents/button/button.component.html b/src/app/core/formcomponents/button/button.component.html new file mode 100644 index 0000000..fba52c7 --- /dev/null +++ b/src/app/core/formcomponents/button/button.component.html @@ -0,0 +1,5 @@ + + {{data.field.Label}} + diff --git a/src/app/core/formcomponents/button/button.component.scss b/src/app/core/formcomponents/button/button.component.scss new file mode 100644 index 0000000..f3a74fa --- /dev/null +++ b/src/app/core/formcomponents/button/button.component.scss @@ -0,0 +1,66 @@ +.w-btn { + font-size: var(--fs); + font-weight: 500; + font-family: var(--ff-base); + background-color: var(--c-primary); + border-radius: var(--b-radius-btn); + transition: var(--transition); + color: var(--c-white); + position: relative; + padding: 11px 25px; + line-height: 19px; + text-align: center; + white-space: nowrap; + display: inline-flex; + justify-content: center; + align-items: center; + user-select: none; + text-align: center; + width: 100%; + border: none; + cursor: pointer; + transition: all .3s; + border-radius: 4px; + &._primary { + background-color: var(--c-primary); + + &:hover { + background-color: var(--c-primary-hover); + } + } + + &._second { + border: 1px solid #256eff; + background-color: var(--c-white); + color: #256eff; + } + + &._danger { + background-color: var(--c-secondary); + color: white; + + &:hover { + background: var(--c-secondary-hover); + } + } + + &._link { + background: transparent; + color: var(--c-text-primary); + font-size: 14px; + font-weight: 400; + + &:hover { + color: var(--c-text-secondary); + } + } + + &:disabled { + background-color: var(--c-grey-dark); + cursor: default; + + &:hover { + background-color: var(--c-grey-dark); + } + } +} diff --git a/src/app/core/formcomponents/button/button.component.ts b/src/app/core/formcomponents/button/button.component.ts new file mode 100644 index 0000000..81c964e --- /dev/null +++ b/src/app/core/formcomponents/button/button.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; + +interface Interface {} + +@Component({ + selector: 'button-formcomponents', + templateUrl: './button.component.html', + styleUrls: ['./button.component.scss'] +}) +export class ButtonComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + + constructor(private _form: FormService) {} + + ngOnInit(): void { + this._form.addTemplateComponent('Button', this.templateRef); + } + + click(data: any): void { + if (typeof data.field.Click === 'function') { + data.field.Click(); + } + } +} diff --git a/src/app/core/formcomponents/date/date.component.html b/src/app/core/formcomponents/date/date.component.html new file mode 100644 index 0000000..e49235c --- /dev/null +++ b/src/app/core/formcomponents/date/date.component.html @@ -0,0 +1,12 @@ + + + diff --git a/src/app/core/formcomponents/date/date.component.scss b/src/app/core/formcomponents/date/date.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/date/date.component.ts b/src/app/core/formcomponents/date/date.component.ts new file mode 100644 index 0000000..dff6524 --- /dev/null +++ b/src/app/core/formcomponents/date/date.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; + +interface Interface {} + +@Component({ + templateUrl: './date.component.html', + styleUrls: ['./date.component.scss'] +}) +export class DateComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + + constructor(private _form: FormService) {} + + ngOnInit(): void { + this._form.addTemplateComponent('Date', this.templateRef); + } +} diff --git a/src/app/core/formcomponents/email/email.component.html b/src/app/core/formcomponents/email/email.component.html new file mode 100644 index 0000000..488f3dd --- /dev/null +++ b/src/app/core/formcomponents/email/email.component.html @@ -0,0 +1,17 @@ + + + diff --git a/src/app/core/formcomponents/email/email.component.scss b/src/app/core/formcomponents/email/email.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/email/email.component.ts b/src/app/core/formcomponents/email/email.component.ts new file mode 100644 index 0000000..15c7ef8 --- /dev/null +++ b/src/app/core/formcomponents/email/email.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; + +interface Interface {} + +@Component({ + templateUrl: './email.component.html', + styleUrls: ['./email.component.scss'] +}) +export class EmailComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + + constructor(private _form: FormService) {} + + ngOnInit(): void { + this._form.addTemplateComponent('Email', this.templateRef); + } +} diff --git a/src/app/core/formcomponents/formcomponents.module.ts b/src/app/core/formcomponents/formcomponents.module.ts new file mode 100644 index 0000000..5b6ab26 --- /dev/null +++ b/src/app/core/formcomponents/formcomponents.module.ts @@ -0,0 +1,115 @@ +import { ButtonModule } from 'src/app/core/modules/button/button.module'; +import { InputModule } from 'src/app/core/modules/input/input.module'; +import { FileModule } from 'src/app/core/modules/file/file.module'; +import { FormService } from 'src/app/core/modules/form/form.service'; +import { SelectModule } from 'src/app/core/modules/select/select.module'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +/* componnets */ +import { EmailComponent } from './email/email.component'; +import { NumberComponent } from './number/number.component'; +import { TimeComponent } from './time/time.component'; +import { PhotoComponent } from './photo/photo.component'; +import { PhotosComponent } from './photos/photos.component'; +import { DateComponent } from './date/date.component'; +import { TextComponent } from './text/text.component'; +import { ButtonComponent } from './button/button.component'; +import { PasswordComponent } from './password/password.component'; +import { SelectComponent } from './select/select.component'; +import { BooleanComponent } from './boolean/boolean.component'; +import { TagsComponent } from './tags/tags.component'; + +@NgModule({ + imports: [ + InputModule, + ButtonModule, + CommonModule, + FileModule, + SelectModule + ], + declarations: [ + /* declarations */ + EmailComponent, + NumberComponent, + TimeComponent, + DateComponent, + PhotoComponent, + PhotosComponent, + PasswordComponent, + SelectComponent, + TextComponent, + ButtonComponent, + BooleanComponent, + TagsComponent + ] +}) +export class FormcomponentsModule { + constructor(private _form: FormService) { + /* addComponents */ + this._form.injectComponent( + 'Boolean', + BooleanComponent, + ['Label'] + ); + + this._form.injectComponent('Button', ButtonComponent, [ + 'Label' + ]); + + this._form.injectComponent('Date', DateComponent); + + this._form.injectComponent('Email', EmailComponent); + + this._form.injectComponent('Number', NumberComponent); + + this._form.injectComponent( + 'Password', + PasswordComponent + ); + + this._form.injectComponent( + 'Photo', + PhotoComponent, + ['Label', 'Width', 'Height'], + { + Width: 'Number', + Height: 'Number' + } + ); + + this._form.injectComponent( + 'Photos', + PhotosComponent, + ['Label', 'Width', 'Height'], + { + Width: 'Number', + Height: 'Number' + } + ); + + this._form.injectComponent( + 'Select', + SelectComponent, + ['Placeholder', 'Label', 'Items', 'Multiple'], + { + Items: 'Tags', + Multiple: 'Boolean' + } + ); + + this._form.injectComponent('Tags', TagsComponent, [ + 'Button', + 'Placeholder', + 'Label' + ]); + + this._form.injectComponent( + 'Text', + TextComponent, + ['Textarea', 'Placeholder', 'Label'], + { Textarea: 'Boolean' } + ); + + this._form.injectComponent('Time', TimeComponent); + } +} diff --git a/src/app/core/formcomponents/number/number.component.html b/src/app/core/formcomponents/number/number.component.html new file mode 100644 index 0000000..5effc51 --- /dev/null +++ b/src/app/core/formcomponents/number/number.component.html @@ -0,0 +1,12 @@ + + + diff --git a/src/app/core/formcomponents/number/number.component.scss b/src/app/core/formcomponents/number/number.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/number/number.component.ts b/src/app/core/formcomponents/number/number.component.ts new file mode 100644 index 0000000..79e4581 --- /dev/null +++ b/src/app/core/formcomponents/number/number.component.ts @@ -0,0 +1,16 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; + +interface Interface {} +@Component({ + templateUrl: './number.component.html', + styleUrls: ['./number.component.scss'] +}) +export class NumberComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + constructor(private _form: FormService) {} + ngOnInit(): void { + this._form.addTemplateComponent('Number', this.templateRef); + } +} diff --git a/src/app/core/formcomponents/password/password.component.html b/src/app/core/formcomponents/password/password.component.html new file mode 100644 index 0000000..abaf58b --- /dev/null +++ b/src/app/core/formcomponents/password/password.component.html @@ -0,0 +1,34 @@ + +
+ +
+ + + + +
+
+ + visibility + +
+
+
diff --git a/src/app/core/formcomponents/password/password.component.scss b/src/app/core/formcomponents/password/password.component.scss new file mode 100644 index 0000000..76d4755 --- /dev/null +++ b/src/app/core/formcomponents/password/password.component.scss @@ -0,0 +1,95 @@ +.pass_container { + position: relative; +} + +.smart { + position: absolute; + right: 0; + top: 0; +} + +.red { + width: 3px; + height: 8px; + background-color: rgb(187, 23, 23); + display: inline-block; + margin-left: 5px; +} + +.orange { + width: 3px; + height: 10px; + background-color: rgb(235, 151, 25); + display: inline-block; + margin-left: 5px; +} + +.yellow { + width: 3px; + height: 12px; + background-color: rgb(255, 251, 0); + display: inline-block; + margin-left: 5px; +} + +.green { + width: 3px; + height: 14px; + background-color: rgb(33, 211, 17); + display: inline-block; + margin-left: 5px; +} + +.eye { + position: relative; + cursor: pointer; + span { + position: absolute; + top: -32px; + right: 10px; + font-size: 22px; + color: var(--c-text-primary); + } +} + +@media screen and (max-width: 768px) { + .red { + width: 3px; + height: 8px; + background-color: rgb(187, 23, 23); + display: inline-block; + margin-left: 5px; + } + + .orange { + width: 3px; + height: 10px; + background-color: rgb(235, 151, 25); + display: inline-block; + margin-left: 5px; + } + + .yellow { + width: 3px; + height: 12px; + background-color: rgb(255, 251, 0); + display: inline-block; + margin-left: 5px; + } + + .green { + width: 3px; + height: 14px; + background-color: rgb(33, 211, 17); + display: inline-block; + margin-left: 5px; + } + + #eye { + position: absolute; + left: 165px; + top: 252px; + font-size: 22px; + color: rgb(90, 90, 90); + } +} diff --git a/src/app/core/formcomponents/password/password.component.ts b/src/app/core/formcomponents/password/password.component.ts new file mode 100644 index 0000000..44a1954 --- /dev/null +++ b/src/app/core/formcomponents/password/password.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; +import { UiService } from 'wacom'; +interface Interface {} +@Component({ + templateUrl: './password.component.html', + styleUrls: ['./password.component.scss'] +}) +export class PasswordComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + constructor(private _form: FormService, public ui: UiService) {} + ngOnInit(): void { + this._form.addTemplateComponent( + 'Password', + this.templateRef + ); + } +} diff --git a/src/app/core/formcomponents/photo/photo.component.html b/src/app/core/formcomponents/photo/photo.component.html new file mode 100644 index 0000000..d16bee2 --- /dev/null +++ b/src/app/core/formcomponents/photo/photo.component.html @@ -0,0 +1,10 @@ + + + diff --git a/src/app/core/formcomponents/photo/photo.component.scss b/src/app/core/formcomponents/photo/photo.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/photo/photo.component.ts b/src/app/core/formcomponents/photo/photo.component.ts new file mode 100644 index 0000000..4eac589 --- /dev/null +++ b/src/app/core/formcomponents/photo/photo.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; +interface Interface {} +@Component({ + templateUrl: './photo.component.html', + styleUrls: ['./photo.component.scss'] +}) +export class PhotoComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + constructor(private _form: FormService) {} + ngOnInit(): void { + this._form.addTemplateComponent('Photo', this.templateRef); + } +} diff --git a/src/app/core/formcomponents/photos/photos.component.html b/src/app/core/formcomponents/photos/photos.component.html new file mode 100644 index 0000000..75e4076 --- /dev/null +++ b/src/app/core/formcomponents/photos/photos.component.html @@ -0,0 +1,12 @@ + + + diff --git a/src/app/core/formcomponents/photos/photos.component.scss b/src/app/core/formcomponents/photos/photos.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/photos/photos.component.ts b/src/app/core/formcomponents/photos/photos.component.ts new file mode 100644 index 0000000..243f996 --- /dev/null +++ b/src/app/core/formcomponents/photos/photos.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; +interface Interface { } +@Component({ + templateUrl: './photos.component.html', + styleUrls: ['./photos.component.scss'] +}) +export class PhotosComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + constructor(private _form: FormService) { } + ngOnInit(): void { + this._form.addTemplateComponent('Photos', this.templateRef); + } +} diff --git a/src/app/core/formcomponents/select/select.component.html b/src/app/core/formcomponents/select/select.component.html new file mode 100644 index 0000000..3ef3766 --- /dev/null +++ b/src/app/core/formcomponents/select/select.component.html @@ -0,0 +1,16 @@ + + + diff --git a/src/app/core/formcomponents/select/select.component.scss b/src/app/core/formcomponents/select/select.component.scss new file mode 100644 index 0000000..f81a42d --- /dev/null +++ b/src/app/core/formcomponents/select/select.component.scss @@ -0,0 +1,232 @@ +// waw-select styles +.w-select { + width: 100%; + &__label { + margin-bottom: 5px; + } + &__body { + position: relative; + cursor: pointer; + display: flex; + min-height: 50px; + height: 50px; + align-items: center; + border: 2px solid var(--c-text-primary); + border-radius: 12px; + transition: var(--transition); + //background: var(--c-bg-secondary); + &._active { + border-color: var(--c-sky); + } + } + &__header { + padding-left: 15px; + display: flex; + align-items: center; + width: 100%; + overflow: hidden; + white-space: nowrap; + padding: 14px 10px 14px 40px; + color: #666; + position: relative; + svg { + position: absolute; + left: 10px; + top: 50%; + transform: translateY(-50%); + path{ + fill:var(--c-primary); + } + } + } + &__text { + margin-right: 10px; + flex-grow: 1; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + .text-overflow { + overflow: hidden; + text-overflow: ellipsis; + word-break: keep-all; + color: var(--c-text-primary); + } + } + &__arrow { + margin-right: 15px; + transition: var(--transition); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + svg{ + width: 12px; + height: 12px; + path{ + fill: var(--c-text-primary); + } + } + &._active { + transform: rotate(180deg); + } + } + .item { + padding: 10px; + transition: var(--transition); + border-bottom: 1px solid var(--c-text-primary); + &:hover { + background: var(--c-shadow); + border-bottom: 1px solid #1ac5eb; + color: #1ac5eb; + } + } + &__popup { + z-index: 9; + width: 100%; + left: 0; + position: absolute; + top: calc(100% + 10px); + background: var(--c-white); + box-shadow: 0px 0px 4px var(--c-border); + border-radius: 10px; + border: 2px solid #173b59; + background: #f8f6f6; + color: #666; + padding-bottom: 15px; + padding-top: 15px; + &._search { + padding-top: 60px; + } + .popup-block { + max-height: 180px; + overflow-y: auto; + padding: 0 15px; + &__empty-search { + padding: 15px; + text-align: center; + color: #717171; + } + } + } + &__search { + top: 10px; + position: absolute; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + left: 0; + padding: 0 15px; + .search-input { + outline: none; + width: 100%; + cursor: pointer; + display: flex; + padding: 10px; + padding-right: 30px; + align-items: center; + border: 1px solid var(--c-border); + border-radius: 10px; + transition: var(--transition); + } + .search-icon { + position: absolute; + top: 50%; + right: 25px; + transform: translateY(-50%); + } + } + // scroll styles + *::-webkit-scrollbar { + width: 5px; + height: 5px; + background-color: var(--c-white); + } + * ::-webkit-scrollbar-thumb { + border-radius: 10px; + background-color: var(--c-border); + } + + // checkbox styles + .checkbox { + &__body { + display: inline-flex; + user-select: none; + cursor: pointer; + padding: 6px 8px; + color: var(--c-text); + border-radius: 6px; + overflow: hidden; + transition: var(--transition); + &:not(:last-child) { + margin-right: 6px; + } + &:hover { + background: rgba(var(--c-sky), 0.09); + } + &:hover .checkbox__svg { + border-color: var(--c-sky); + } + } + &__input { + display: none; + &:checked + .checkbox__body .checkbox__svg { + background: var(--c-sky); + border-color: var(--c-sky); + animation: wave 0.4s ease; + } + &:checked + .checkbox__body .checkbox__svg svg { + stroke-dashoffset: 0; + } + } + &__svg { + position: relative; + min-width: 18px; + min-height: 18px; + width: 18px; + height: 18px; + display: inline-block; + border-radius: 4px; + transform: scale(1); + border: 1px solid var(--c-border); + transition: var(--transition); + box-shadow: 0 1px 1px var(--c-shadow); + } + &__svg svg { + position: absolute; + top: 3px; + left: 2px; + fill: none; + stroke: var(--c-white); + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; + stroke-dasharray: 16px; + stroke-dashoffset: 16px; + transition: all 0.3s ease; + transition-delay: 0.1s; + transform: translate3d(0, 0, 0); + } + &__text { + padding-left: 8px; + line-height: 18px; + text-overflow: ellipsis; + overflow: hidden; + } + &__svg-icon { + position: absolute; + width: 0; + height: 0; + pointer-events: none; + user-select: none; + } + @keyframes wave { + 50% { + transform: scale(0.9); + } + } + } +} +.selected { + font-weight: bold; +} \ No newline at end of file diff --git a/src/app/core/formcomponents/select/select.component.ts b/src/app/core/formcomponents/select/select.component.ts new file mode 100644 index 0000000..a0a42d9 --- /dev/null +++ b/src/app/core/formcomponents/select/select.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; + +interface Interface {} + +@Component({ + templateUrl: './select.component.html', + styleUrls: ['./select.component.scss'] +}) +export class SelectComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + + constructor(private _form: FormService) {} + + ngOnInit(): void { + this._form.addTemplateComponent('Select', this.templateRef); + } + + select(data: any): string { + return data.value?.name || (data.value as unknown as string) || ''; + } +} diff --git a/src/app/core/formcomponents/tags/tags.component.html b/src/app/core/formcomponents/tags/tags.component.html new file mode 100644 index 0000000..0b0307f --- /dev/null +++ b/src/app/core/formcomponents/tags/tags.component.html @@ -0,0 +1,19 @@ + +
+ + + + {{tag}} + X + + + + {{data.field.Button || 'Add'}} + +
+
diff --git a/src/app/core/formcomponents/tags/tags.component.scss b/src/app/core/formcomponents/tags/tags.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/tags/tags.component.ts b/src/app/core/formcomponents/tags/tags.component.ts new file mode 100644 index 0000000..8365c7d --- /dev/null +++ b/src/app/core/formcomponents/tags/tags.component.ts @@ -0,0 +1,35 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; + +interface Interface {} + +@Component({ + templateUrl: './tags.component.html', + styleUrls: ['./tags.component.scss'] +}) +export class TagsComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + + constructor(private _form: FormService) {} + + ngOnInit(): void { + this._form.addTemplateComponent('Tags', this.templateRef); + } + + @ViewChild('inputRef', { static: false }) inputRef: any; + + addTag(data: any): void { + data.submition[data.key] = data.submition[data.key] || []; + + data.submition[data.key].push(this.inputRef.value.replace('\n', '')); + + this.inputRef.value = ''; + + data.wChange.emit(); + + setTimeout(() => { + this.inputRef.focus(); + }, 100); + } +} diff --git a/src/app/core/formcomponents/text/text.component.html b/src/app/core/formcomponents/text/text.component.html new file mode 100644 index 0000000..8e0390a --- /dev/null +++ b/src/app/core/formcomponents/text/text.component.html @@ -0,0 +1,15 @@ + + + diff --git a/src/app/core/formcomponents/text/text.component.scss b/src/app/core/formcomponents/text/text.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/text/text.component.ts b/src/app/core/formcomponents/text/text.component.ts new file mode 100644 index 0000000..b7693b5 --- /dev/null +++ b/src/app/core/formcomponents/text/text.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; + +interface Interface {} + +@Component({ + templateUrl: './text.component.html', + styleUrls: ['./text.component.scss'] +}) +export class TextComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + + constructor(private _form: FormService) {} + + ngOnInit(): void { + this._form.addTemplateComponent('Text', this.templateRef); + } +} diff --git a/src/app/core/formcomponents/time/time.component.html b/src/app/core/formcomponents/time/time.component.html new file mode 100644 index 0000000..7bf5f6e --- /dev/null +++ b/src/app/core/formcomponents/time/time.component.html @@ -0,0 +1,12 @@ + + + diff --git a/src/app/core/formcomponents/time/time.component.scss b/src/app/core/formcomponents/time/time.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/formcomponents/time/time.component.ts b/src/app/core/formcomponents/time/time.component.ts new file mode 100644 index 0000000..6a783be --- /dev/null +++ b/src/app/core/formcomponents/time/time.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { FormService } from '../../modules/form/form.service'; +interface Interface {} +@Component({ + templateUrl: './time.component.html', + styleUrls: ['./time.component.scss'] +}) +export class TimeComponent implements OnInit { + @ViewChild('templateRef', { static: true }) + templateRef: TemplateRef; + constructor(private _form: FormService) {} + ngOnInit(): void { + this._form.addTemplateComponent('Time', this.templateRef); + } +} diff --git a/src/app/core/guards/admins.guard.ts b/src/app/core/guards/admins.guard.ts new file mode 100644 index 0000000..72a286a --- /dev/null +++ b/src/app/core/guards/admins.guard.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +@Injectable() +export class AdminsGuard { + constructor(private router: Router) {} + + canActivate(): boolean { + if (localStorage.getItem('waw_user')) { + const user = JSON.parse(localStorage.getItem('waw_user') as string); + + if (user.is && user.is.admin) return true; + + this.router.navigate(['/profile']); + + return false; + } else { + this.router.navigate(['/sign']); + + return false; + } + } +} diff --git a/src/app/core/guards/authenticated.guard.ts b/src/app/core/guards/authenticated.guard.ts new file mode 100644 index 0000000..bd06297 --- /dev/null +++ b/src/app/core/guards/authenticated.guard.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +@Injectable() +export class AuthenticatedGuard { + constructor(private router: Router) {} + + canActivate(): boolean { + if (localStorage.getItem('waw_user')) { + return true; + } else { + this.router.navigateByUrl('/sign'); + + return false; + } + } +} diff --git a/src/app/core/guards/guest.guard.ts b/src/app/core/guards/guest.guard.ts new file mode 100644 index 0000000..8d31bf8 --- /dev/null +++ b/src/app/core/guards/guest.guard.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +@Injectable() +export class GuestGuard { + constructor(private router: Router) {} + + canActivate(): boolean { + if (localStorage.getItem('waw_user')) { + this.router.navigateByUrl('/profile'); + + return false; + } else { + return true; + } + } +} diff --git a/src/app/core/icons/icons.module.ts b/src/app/core/icons/icons.module.ts new file mode 100644 index 0000000..f187bb0 --- /dev/null +++ b/src/app/core/icons/icons.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +/* components */ +import { SpiderComponent } from './spider/spider.component'; + +const icons = [ + /* icons */ + SpiderComponent +]; + +@NgModule({ + declarations: icons, + exports: icons +}) +export class IconsModule {} diff --git a/src/app/core/icons/spider/spider.component.html b/src/app/core/icons/spider/spider.component.html new file mode 100644 index 0000000..360d748 --- /dev/null +++ b/src/app/core/icons/spider/spider.component.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/app/core/icons/spider/spider.component.scss b/src/app/core/icons/spider/spider.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/icons/spider/spider.component.ts b/src/app/core/icons/spider/spider.component.ts new file mode 100644 index 0000000..a04e7e4 --- /dev/null +++ b/src/app/core/icons/spider/spider.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'icon-spider', + templateUrl: './spider.component.html', + styleUrls: ['./spider.component.scss'] +}) +export class SpiderComponent { + +} diff --git a/src/app/core/modules/button/.gitignore b/src/app/core/modules/button/.gitignore new file mode 100644 index 0000000..6704566 --- /dev/null +++ b/src/app/core/modules/button/.gitignore @@ -0,0 +1,104 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/src/app/core/modules/button/LICENSE b/src/app/core/modules/button/LICENSE new file mode 100644 index 0000000..1125219 --- /dev/null +++ b/src/app/core/modules/button/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app/core/modules/button/README.md b/src/app/core/modules/button/README.md new file mode 100644 index 0000000..44fc982 --- /dev/null +++ b/src/app/core/modules/button/README.md @@ -0,0 +1,108 @@ +# Button Module + +The Button Module is a customizable Angular component for creating various types of buttons, including primary, secondary, success, danger, and more. This module provides an easy way to manage button styles, states, and events in your Angular applications. + +## Features + +- Supports multiple button types: primary, secondary, success, danger, warning, info, light, dark, link. +- Customizable classes for additional styling. +- Supports disabled state. +- Emits custom click events. + +## Installation + +To install this module, use the following command: +```cmd +waw add ngx-button +``` +## Usage + +### Importing the Module + +First, import the `ButtonModule` into your Angular module: +```Typescript +import { ButtonModule } from '@your-namespace/button-module'; + +@NgModule({ + declarations: [...], + imports: [ + ButtonModule, + ... + ], + providers: [], + bootstrap: [...] +}) +export class AppModule { } +``` +### Basic Example + +Here's a basic example of how to use the button component in your Angular template: +```Typescript + + Click Me + +``` +### Handling Different Button Types + +The `ButtonComponent` supports a variety of button types: + +- `primary` +- `secondary` +- `success` +- `danger` +- `warning` +- `info` +- `light` +- `dark` +- `link` + +Example: +```Typescript + + Delete + +``` +### Custom Classes + +You can provide custom classes for additional styling: +```Typescript + + Save + +``` +## API + +### Inputs + +- **type** (`string`): The type of button. Options include primary, secondary, success, danger, warning, info, light, dark, and link. +- **class** (`string`): Custom CSS classes to add to the button. +- **disabled** (`boolean`): Whether the button is disabled. +- **disableSubmit** (`boolean`): When true, the button will not submit the form, even if placed inside a form. +- **click** (`(() => void) | undefined`): Custom function to handle the click event. + +### Outputs + +- **wClick** (`EventEmitter`): Emits an event when the button is clicked. + +## Customization + +You can customize the appearance of the button component using custom CSS or by passing additional classes through the `class` input. + +## Contributing + +Feel free to contribute to this project by opening issues or submitting pull requests. Make sure to follow the contribution guidelines. + +## License + +This project is licensed under the MIT License. diff --git a/src/app/core/modules/button/button.component.html b/src/app/core/modules/button/button.component.html new file mode 100644 index 0000000..a6275e4 --- /dev/null +++ b/src/app/core/modules/button/button.component.html @@ -0,0 +1,19 @@ + diff --git a/src/app/core/modules/button/button.component.scss b/src/app/core/modules/button/button.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/modules/button/button.component.ts b/src/app/core/modules/button/button.component.ts new file mode 100644 index 0000000..4d6afbb --- /dev/null +++ b/src/app/core/modules/button/button.component.ts @@ -0,0 +1,82 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +/** + * ButtonComponent is a reusable button component that supports various styles + * and types, such as primary, secondary, success, danger, and more. It also supports + * disabled states and custom click events. + */ +@Component({ + selector: 'wbutton', + templateUrl: './button.component.html', + styleUrls: ['./button.component.scss'] +}) +export class ButtonComponent { + /** + * The type of button. + * Options include: primary, secondary, success, danger, warning, info, light, dark, link. + * Default is 'primary'. + */ + @Input() type: + | 'primary' + | 'secondary' + | 'success' + | 'danger' + | 'warning' + | 'info' + | 'light' + | 'dark' + | 'link' = 'primary'; + + /** + * Custom CSS classes to add to the button. + * Default is an empty string. + */ + @Input() class = ''; + + /** + * Whether the button is disabled. + * Default is false. + */ + @Input() disabled = false; + + /** + * When true, the button will not submit the form even if placed inside a form. + * Default is false. + */ + @Input() disableSubmit = false; + + /** + * Custom function to handle click events. + * If not provided, the button acts as a normal button. + */ + @Input() click: (() => void) | undefined; + + /** + * Event emitted when the button is clicked. + */ + @Output() wClick = new EventEmitter(); + + /** + * Method called when the button is clicked. + * Emits the wClick event and calls the custom click function if provided. + */ + clicked(): void { + if (this.disabled) { + return; + } + + if (typeof this.click === 'function') { + this.click(); + } + + this.wClick.emit(); + } + + /** + * Sets the disabled state of the button. + * @param disabled - Whether the button should be disabled. + */ + setDisabled(disabled: boolean): void { + this.disabled = disabled; + } +} diff --git a/src/app/core/modules/button/button.module.ts b/src/app/core/modules/button/button.module.ts new file mode 100644 index 0000000..e342a6e --- /dev/null +++ b/src/app/core/modules/button/button.module.ts @@ -0,0 +1,11 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ButtonComponent } from './button.component'; + +@NgModule({ + imports: [CommonModule], + declarations: [ButtonComponent], + providers: [], + exports: [ButtonComponent] +}) +export class ButtonModule {} diff --git a/src/app/core/modules/button/module.json b/src/app/core/modules/button/module.json new file mode 100644 index 0000000..cec1b66 --- /dev/null +++ b/src/app/core/modules/button/module.json @@ -0,0 +1,3 @@ +{ + "repo" : "git@github.com:WebArtWork/ngx-button.git" +} diff --git a/src/app/core/modules/calendar/.gitignore b/src/app/core/modules/calendar/.gitignore new file mode 100644 index 0000000..6704566 --- /dev/null +++ b/src/app/core/modules/calendar/.gitignore @@ -0,0 +1,104 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/src/app/core/modules/calendar/LICENSE b/src/app/core/modules/calendar/LICENSE new file mode 100644 index 0000000..1125219 --- /dev/null +++ b/src/app/core/modules/calendar/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app/core/modules/calendar/README.md b/src/app/core/modules/calendar/README.md new file mode 100644 index 0000000..12ed744 --- /dev/null +++ b/src/app/core/modules/calendar/README.md @@ -0,0 +1 @@ +# ngx-alert \ No newline at end of file diff --git a/src/app/core/modules/calendar/calendar.component.html b/src/app/core/modules/calendar/calendar.component.html new file mode 100644 index 0000000..3c3b859 --- /dev/null +++ b/src/app/core/modules/calendar/calendar.component.html @@ -0,0 +1,286 @@ +
+
+ Сьогодні +
+
+
+ + + + + +
+ {{monthTitle[currentMonth]}} + {{currentYear}} +
+ + + + + +
+
+
+ +
+
+ {{week}} + + + {{dayTitle[day]}} + + + + {{startDay + day}} +
+
+ + +
+
+
+ + + +
+ {{day + (i * 7) - skipDays}} +
+
+
+ +
+
+
+ + + +
{{day - keepDays}}
+
+
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+ + + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+ + + +
diff --git a/src/app/core/modules/calendar/calendar.component.scss b/src/app/core/modules/calendar/calendar.component.scss new file mode 100644 index 0000000..6343b7d --- /dev/null +++ b/src/app/core/modules/calendar/calendar.component.scss @@ -0,0 +1,225 @@ +.calendar{ + padding-top: 20px; + display: flex; + flex-direction: column; + height: 100vh; /* 100% высоты экрана */ + &__row{ + flex: 1; /* Каждый ряд занимает равную высоту */ + display: flex; + position: relative; + } + &__stard-day{ + text-align: center; + } + &__day{ + flex: 1; + background: var(--c-calendar); + padding: 10px 5px; + border-radius: 0; + border: 1px solid var(--border); + font-weight: 900; + display: flex; + flex-flow: column wrap; + &-name{ + color: var(--day-name); + font-size: 12px; + font-weight: 700; + padding-bottom: 3px; + text-align: center; + } + } + &__week{ + position: absolute; + width: 30px; + height: 30px; + background: #625959; + display: flex; + align-items: center; + justify-content: center; + border-radius: 5px; + color: #fff; + top: -10px; + left: -10px; + } + &-time{ + display: flex; + align-items: center; + color: var(--c-primary); + line-height: 1; + justify-content: center; + font-weight: 300; + &__clock{ + display: flex; + margin-right: 7px; + svg{ + path{ + fill: var(--c-primary) + } + } + } + } + &-events{ + font-size: 12px; + background: var(--events); + border-radius: 5px; + font-weight: 500; + color: #ffffff; + padding: 5px; + margin-bottom: 5px; + &__text{ + font-weight: 900; + } + &__column{ + margin-right: 20px; + } + &__row{ + display: flex; + border-bottom: 1px solid #fff; + &:last-child{ + border: none; + } + } + &__name{ + color: var(--c-primary); + } + } +} +.calendar-nav{ + display: flex; + align-items: center; + &-year{ + display: flex; + align-items: center; + &__buttons{ + display: flex; + align-items: center; + width: 250px; + justify-content: space-between; + .arrow-back{ + cursor: pointer; + svg{ + path{ + fill: var(--c-primary); + } + } + } + .arrow-next{ + cursor: pointer; + svg{ + path{ + fill: var(--c-primary); + } + } + } + } + &__data{ + margin: 0 15px; + font-size: 20px; + span{ + &:last-child{ + margin-left: 10px; + } + } + } + } + &__today{ + margin-right: 20px; + } +} + +.line{ + width: 100%; + z-index: 1; + background: #fff; + height: 1px; + margin: 15px 0; +} + +.event{ + &__item{ + display: flex; + border-bottom: 1px solid var(--day-name); + margin-bottom: 10px; + } + &__icon{ + margin-right: 10px; + } + &-text{ + &__left{ + display: flex; + } + &__title{ + font-weight: 700; + } + &__row{ + display: flex; + padding-bottom: 5px; + } + &__column{ + margin-right: 20px; + &-from{ + color: var(--c-primary); + font-weight: 900; + } + &-time{ + font-size: 14px; + color: var(--day-name); + } + } + } + &-driver{ + border-left: 1px solid var(--day-name); + padding-left: 10px; + &__name{ + color: var(--c-primary); + font-weight: 900; + } + &__phone{ + font-size: 14px; + color: var(--day-name); + } + } + +} + +.add-event-mobile{ + padding: 10px 20px; + margin-top: 20px; +} + +@media screen and (max-width: 769px) { + .calendar-nav-year__buttons{ + width: unset; + } + .calendar-nav__today{ + margin-right: 10px; + } + .calendar-nav-year__data{ + margin: 0 15px; + font-size: 15px; + font-weight: 600; + } + .calendar-mobile{ + height: fit-content; + .calendar-events{ + span, div{ + display: none; + } + } + .calendar__day{ + margin: 2px; + padding: 8px; + border-radius: 5px; + min-height: 70px; + font-size: 14px; + } + .calendar__week{ + width: 21px; + height: 21px; + font-size: 12px; + } + .calendar-events{ + padding: 2px; + } + } +} diff --git a/src/app/core/modules/calendar/calendar.component.ts b/src/app/core/modules/calendar/calendar.component.ts new file mode 100644 index 0000000..f820a32 --- /dev/null +++ b/src/app/core/modules/calendar/calendar.component.ts @@ -0,0 +1,226 @@ +import { + Component, + HostListener, + Output, + Input, + EventEmitter +} from '@angular/core'; +import { Router } from '@angular/router'; +import { CalendarDate } from './calendar.interface'; + +@Component({ + selector: 'wcalendar', + templateUrl: './calendar.component.html', + styleUrls: ['./calendar.component.scss'] +}) +export class CalendarComponent { + @Input() eventsByDate: Record = {}; + + @Output() createEvent = new EventEmitter(); + + @Output() updateEvent = new EventEmitter(); + + readonly dayTitle: Record = { + 1: 'ПН', + 2: 'ВТ', + 3: 'СР', + 4: 'ЧТ', + 5: 'ПТ', + 6: 'СБ', + 7: 'НД' + }; + readonly monthTitle: Record = { + 0: 'Січень', + 1: 'Лютий', + 2: 'Березень', + 3: 'Квітень', + 4: 'Травень', + 5: 'Червень', + 6: 'Липень', + 7: 'Серпень', + 8: 'Вересень', + 9: 'Жовтень', + 10: 'Листопад', + 11: 'Грудень' + }; + manager = this._router.url.includes('manager'); + constructor(private _router: Router) { + this._onMonthChange(); + + this.onResize(); + } + // Calendar management + currentMonth = new Date().getMonth(); + currentYear = new Date().getFullYear(); + previousMonth: number; + previousYear: number; + nextMonth: number; + nextYear: number; + setNow(): void { + this.currentMonth = new Date().getMonth(); + + this.currentYear = new Date().getFullYear(); + + this._onMonthChange(); + } + setPreviousMonth(): void { + this.currentMonth--; + + if (this.currentMonth === -1) { + this.currentMonth = 11; + + this.currentYear--; + } + + this._onMonthChange(); + } + setNextMonth(): void { + this.currentMonth++; + + if (this.currentMonth === 12) { + this.currentMonth = 0; + + this.currentYear++; + } + + this._onMonthChange(); + } + weeksInMonth: number[] = []; + startDay = 0; // date of previous month, first in first row, -1 + skipDays = 0; // skipped days on first row + keepDays = 0; // days on latest row + private _onMonthChange(): void { + if (this.currentMonth === 11) { + this.previousMonth = 10; + + this.previousYear = this.currentYear; + + this.nextMonth = 0; + + this.nextYear = this.currentYear + 1; + } else if (this.currentMonth === 0) { + this.previousMonth = 11; + + this.previousYear = this.currentYear - 1; + + this.nextMonth = 1; + + this.nextYear = this.currentYear; + } else { + this.previousMonth = this.currentMonth - 1; + + this.previousYear = this.currentYear; + + this.nextMonth = this.currentMonth + 1; + + this.nextYear = this.currentYear; + } + + const firstDayOfMonth = new Date( + this.currentYear, + this.currentMonth, + 1 + ); + + const firstWeek = this.getWeekNumber(firstDayOfMonth); + + this.weeksInMonth = []; + + const weeks = this.getWeeksInMonth(this.currentMonth, this.currentYear); + + for (let i = 0; i < weeks; i++) { + this.weeksInMonth.push(firstWeek + i); + } + + this.skipDays = + (firstDayOfMonth.getDay() === 0 ? 7 : firstDayOfMonth.getDay()) - 1; + + const daysInPreviousMonth = + this.currentMonth > 1 + ? this.getDaysInMonth(this.currentMonth - 1, this.currentYear) + : this.getDaysInMonth(11, this.currentYear - 1); + + const daysInMonth = this.getDaysInMonth( + this.currentMonth, + this.currentYear + ); + + this.startDay = daysInPreviousMonth - this.skipDays; + + this.keepDays = (daysInMonth + this.skipDays) % 7; + + if ( + !this.selectedDate || + this.selectedDate.split('.')[0] !== this.currentYear.toString() || + this.selectedDate.split('.')[1] !== + (this.currentMonth - 1).toString() + ) + this.selectedDate = ''; + } + isMobile: boolean; + @HostListener('window:resize') onResize(): void { + this.isMobile = window.innerWidth <= 768; + } + toDate(year: number, month: number, day: number, join = '.'): string { + return `${year}${join}${month}${join}${day}`; + } + selectedDate: string = localStorage.getItem('travel_selectedDate') || ''; + dateClicked(date: string): void { + if (this.isMobile) { + this.selectedDate = date; + + localStorage.setItem('travel_selectedDate', date); + } else { + // this.createEvent.emit(date); + } + } + eventClicked(date: CalendarDate): void { + if (this.isMobile) { + this.selectedDate = this.date(date); + } else { + this.updateEvent.emit(date); + } + } + + /* move to wacom */ + getWeekNumber(date: Date): number { + const tempDate = new Date(date.getTime()); + + tempDate.setHours(0, 0, 0, 0); + // Set to nearest Thursday: current date + 4 - current day number, making Thursday day 4 + + tempDate.setDate(tempDate.getDate() + 4 - (tempDate.getDay() || 7)); + + const yearStart = new Date(tempDate.getFullYear(), 0, 1); + + // Calculate full weeks to nearest Thursday + + return Math.ceil( + ((tempDate.getTime() - yearStart.getTime()) / 86400000 + 1) / 7 + ); + } + getWeeksInMonth(month: number, year: number): number { + const firstDayOfMonth = new Date(year, month, 1); + + const lastDayOfMonth = new Date(year, month + 1, 0); + + // Get ISO week numbers for the first and last day of the month + const firstWeek = this.getWeekNumber(firstDayOfMonth); + + let lastWeek = this.getWeekNumber(lastDayOfMonth); + + // Special case: when January 1st is in the last week of the previous year + if (firstWeek > lastWeek) { + lastWeek = this.getWeekNumber(new Date(year, 11, 31)); // Get week of the last day of the year + } + + return lastWeek - firstWeek + 1; + } + getDaysInMonth(month: number, year: number): number { + return new Date(year, month + 1, 0).getDate(); + } + + date(ap: CalendarDate, join = '.'): string { + return `${ap.year}${join}${ap.month}${join}${ap.day}`; + } +} diff --git a/src/app/core/modules/calendar/calendar.interface.ts b/src/app/core/modules/calendar/calendar.interface.ts new file mode 100644 index 0000000..737a479 --- /dev/null +++ b/src/app/core/modules/calendar/calendar.interface.ts @@ -0,0 +1,5 @@ +export interface CalendarDate { + year: number; + month: number; + day: number; +} diff --git a/src/app/core/modules/calendar/calendar.module.ts b/src/app/core/modules/calendar/calendar.module.ts new file mode 100644 index 0000000..4e1341b --- /dev/null +++ b/src/app/core/modules/calendar/calendar.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { CalendarComponent } from './calendar.component'; +import { ButtonModule } from '../button/button.module'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + declarations: [CalendarComponent], + imports: [CommonModule, ButtonModule], + exports: [CalendarComponent] +}) +export class CalendarModule {} diff --git a/src/app/core/modules/calendar/module.json b/src/app/core/modules/calendar/module.json new file mode 100644 index 0000000..5940b52 --- /dev/null +++ b/src/app/core/modules/calendar/module.json @@ -0,0 +1,3 @@ +{ + "repo": "git@github.com:WebArtWork/ngx-alert.git" +} diff --git a/src/app/core/modules/card/.gitignore b/src/app/core/modules/card/.gitignore new file mode 100644 index 0000000..6704566 --- /dev/null +++ b/src/app/core/modules/card/.gitignore @@ -0,0 +1,104 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/src/app/core/modules/card/LICENSE b/src/app/core/modules/card/LICENSE new file mode 100644 index 0000000..1125219 --- /dev/null +++ b/src/app/core/modules/card/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app/core/modules/card/README.md b/src/app/core/modules/card/README.md new file mode 100644 index 0000000..752fb3a --- /dev/null +++ b/src/app/core/modules/card/README.md @@ -0,0 +1,117 @@ +# Card Module + +The Card Module is a highly flexible Angular component designed to act as a container for various types of content, such as user profiles, product listings, or any custom content. It allows for easy customization and flexible layouts using CSS Flexbox. + +## Features + +- Flexible layout for various content types. +- Optional header and footer sections. +- Supports custom CSS classes for further styling. +- Uses CSS Flexbox for responsive and adaptive layout design. +- Accepts an array of strings to render multiple body sections. + +## Installation + +To install this module, use the following command: + +waw add ngx-card + +## Usage + +### Importing the Module + +First, import the `CardModule` into your Angular module: +```Typescript +import { CardModule } from '@your-namespace/card-module'; + +@NgModule({ + declarations: [...], + imports: [ + CardModule, + ... + ], + providers: [], + bootstrap: [...] +}) +export class AppModule { } +``` +### Basic Example + +Here’s a basic example of how to use the card component to display custom content: +```Typescript + + + +``` +### Using Header and Footer + +You can optionally add a header and footer to the card: +```Typescript + +
+ Product Picture +

Product Name

+

Product description goes here...

+

Price: $29.99

+
+
+ + +

Product Information

+
+ + + + +``` +### Using `sections` + +The `sections` input allows you to pass an array of strings to the card component. Each string will be rendered as a separate section within the card body: +```Typescript + +
+

Header Content

+
+ +
+ +
+
+``` +### Custom Classes + +You can provide custom classes for additional styling: +```Typescript + +
+ +
+
+``` +## API + +### Inputs + +- **cardClass** (`string`): Custom CSS classes to apply to the card. +- **sections** (`string[] | null`): Array of strings representing multiple content sections in the body. +- **header** (`TemplateRef | null`): Optional header template for the card. +- **footer** (`TemplateRef | null`): Optional footer template for the card. + +## Customization + +You can customize the appearance of the card component using custom CSS or by passing additional classes through the `cardClass` input. + +## Contributing + +Feel free to contribute to this project by opening issues or submitting pull requests. Make sure to follow the contribution guidelines. + +## License + +This project is licensed under the MIT License. diff --git a/src/app/core/modules/card/card.component.html b/src/app/core/modules/card/card.component.html new file mode 100644 index 0000000..321cdd5 --- /dev/null +++ b/src/app/core/modules/card/card.component.html @@ -0,0 +1,16 @@ +
+
+ +
+ +
+ +
+ {{ section }} +
+
+ + +
diff --git a/src/app/core/modules/card/card.component.scss b/src/app/core/modules/card/card.component.scss new file mode 100644 index 0000000..d92e4a2 --- /dev/null +++ b/src/app/core/modules/card/card.component.scss @@ -0,0 +1,44 @@ + +.w-card { + display: flex; + flex-direction: column; + background-color: var(--c-bg-secondary); + border-radius: var(--card-border-radius, 8px); + box-shadow: var(--card-box-shadow, 0 2px 8px rgba(0, 0, 0, 0.1)); + overflow: hidden; + margin-bottom: var(--card-margin-bottom, 20px); + position: relative; + + &__header { + padding: var(--card-header-padding, 16px); + border-bottom: var(--card-border-width, 1px) solid + var(--card-border-color, #eaeaea); + //background-color: var(--card-header-background, #f5f5f5); + flex-shrink: 0; + } + + &__body { + padding: var(--card-body-padding, 16px); + flex-grow: 1; + display: flex; + flex-direction: column; + + &-section { + padding: var(--card-section-padding, 8px 0); + border-bottom: var(--card-border-width, 1px) solid + var(--card-border-color, #eaeaea); + + &:last-child { + border-bottom: none; + } + } + } + + &__footer { + padding: var(--card-footer-padding, 16px); + border-top: var(--card-border-width, 1px) solid + var(--card-border-color, #eaeaea); + background-color: var(--card-footer-background, #f5f5f5); + flex-shrink: 0; + } +} diff --git a/src/app/core/modules/card/card.component.ts b/src/app/core/modules/card/card.component.ts new file mode 100644 index 0000000..109554d --- /dev/null +++ b/src/app/core/modules/card/card.component.ts @@ -0,0 +1,42 @@ +import { Component, Input, AfterContentInit, ContentChild, ElementRef } from '@angular/core'; + +/** + * CardComponent is a flexible container that can be used to display various types + * of content, including user profiles, product rows, or any custom content. + * It supports a flexible layout with optional header and footer sections. + */ +@Component({ + selector: 'wcard', + templateUrl: './card.component.html', + styleUrls: ['./card.component.scss'] +}) +export class CardComponent implements AfterContentInit { + /** + * Custom CSS classes to apply to the card. + */ + @Input() cardClass = ''; + + /** + * Array of strings representing multiple content sections in the body. + * If provided, these sections will be rendered within the body of the card. + */ + @Input() sections: string[] | null = null; + + /** + * Indicates if header content is present. + */ + hasHeader = false; + + /** + * Indicates if footer content is present. + */ + hasFooter = false; + + @ContentChild('header', { static: false }) headerContent: ElementRef | undefined; + @ContentChild('footer', { static: false }) footerContent: ElementRef | undefined; + + ngAfterContentInit(): void { + this.hasHeader = !!this.headerContent; + this.hasFooter = !!this.footerContent; + } +} diff --git a/src/app/core/modules/card/card.module.ts b/src/app/core/modules/card/card.module.ts new file mode 100644 index 0000000..83192e8 --- /dev/null +++ b/src/app/core/modules/card/card.module.ts @@ -0,0 +1,13 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { WacomModule } from 'wacom'; +import { CardComponent } from './card.component'; + +@NgModule({ + imports: [FormsModule, CommonModule, WacomModule], + declarations: [CardComponent], + providers: [], + exports: [CardComponent] +}) +export class CardModule {} diff --git a/src/app/core/modules/card/module.json b/src/app/core/modules/card/module.json new file mode 100644 index 0000000..d5745bc --- /dev/null +++ b/src/app/core/modules/card/module.json @@ -0,0 +1,3 @@ +{ + "repo": "git@github.com:WebArtWork/ngx-card.git" +} diff --git a/src/app/core/modules/collapse/.gitignore b/src/app/core/modules/collapse/.gitignore new file mode 100644 index 0000000..6704566 --- /dev/null +++ b/src/app/core/modules/collapse/.gitignore @@ -0,0 +1,104 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/src/app/core/modules/collapse/LICENSE b/src/app/core/modules/collapse/LICENSE new file mode 100644 index 0000000..1125219 --- /dev/null +++ b/src/app/core/modules/collapse/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app/core/modules/collapse/README.md b/src/app/core/modules/collapse/README.md new file mode 100644 index 0000000..a1a50c0 --- /dev/null +++ b/src/app/core/modules/collapse/README.md @@ -0,0 +1,23 @@ +# ngx-collapse + +## Usage + +```html + +
+

This is the header collapse

+
+
+

This is the body collapse

+
+
+``` + +```html +config = { + show: false, + toggle: function() { this.show = !this.show }, + open: function() { this.show = true }, + close: function() { this.show = false } +} +``` diff --git a/src/app/core/modules/collapse/collapse.component.html b/src/app/core/modules/collapse/collapse.component.html new file mode 100644 index 0000000..57da501 --- /dev/null +++ b/src/app/core/modules/collapse/collapse.component.html @@ -0,0 +1,19 @@ +
+ + +
+ + + + + + + + + +
+
+ +
+ +
diff --git a/src/app/core/modules/collapse/collapse.component.scss b/src/app/core/modules/collapse/collapse.component.scss new file mode 100644 index 0000000..3a26af3 --- /dev/null +++ b/src/app/core/modules/collapse/collapse.component.scss @@ -0,0 +1,18 @@ +.header{ + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px; + background: #22252A; + border-radius: 12px; + &--open{ + border-radius: 12px 12px 0 0; + .accardion__arrow{ + transform: rotate(180deg); + } + } +} +.accardion__arrow{ + display: flex; + transition: all .3s; +} \ No newline at end of file diff --git a/src/app/core/modules/collapse/collapse.component.ts b/src/app/core/modules/collapse/collapse.component.ts new file mode 100644 index 0000000..377b5a4 --- /dev/null +++ b/src/app/core/modules/collapse/collapse.component.ts @@ -0,0 +1,34 @@ +import { Component, Input } from '@angular/core'; +import { Collapse } from './collapse.interface'; + +@Component({ + selector: 'wcollapse', + templateUrl: './collapse.component.html', + styleUrls: ['./collapse.component.scss'] +}) +export class CollapseComponent { + @Input() config: Collapse; + + constructor() { + this.config = this.config || ({} as Collapse); + + this.config.show = + typeof this.config.show === 'boolean' ? this.config.show : false; + + this.config.toggle = this.config.toggle || this.toggle.bind(this); + this.config.open = this.config.open || this.open.bind(this); + this.config.close = this.config.close || this.close.bind(this); + } + + toggle(): void { + this.config.show = !this.config.show; + } + + open(): void { + this.config.show = true; + } + + close(): void { + this.config.show = false; + } +} diff --git a/src/app/core/modules/collapse/collapse.interface.ts b/src/app/core/modules/collapse/collapse.interface.ts new file mode 100644 index 0000000..e992446 --- /dev/null +++ b/src/app/core/modules/collapse/collapse.interface.ts @@ -0,0 +1,6 @@ +export interface Collapse { + show: boolean; + toggle: () => void; + open: () => void; + close: () => void; +} diff --git a/src/app/core/modules/collapse/collapse.module.ts b/src/app/core/modules/collapse/collapse.module.ts new file mode 100644 index 0000000..7f5af26 --- /dev/null +++ b/src/app/core/modules/collapse/collapse.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { CollapseComponent } from './collapse.component'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + imports: [CommonModule], + declarations: [CollapseComponent], + providers: [], + exports: [CollapseComponent] +}) +export class CollapseModule {} diff --git a/src/app/core/modules/collapse/module.json b/src/app/core/modules/collapse/module.json new file mode 100644 index 0000000..a964fd3 --- /dev/null +++ b/src/app/core/modules/collapse/module.json @@ -0,0 +1,3 @@ +{ + "repo" : "git@github.com:WebArtWork/ngx-collapse.git" +} \ No newline at end of file diff --git a/src/app/core/modules/file/file-cropper/file-cropper.component.html b/src/app/core/modules/file/file-cropper/file-cropper.component.html new file mode 100644 index 0000000..039665a --- /dev/null +++ b/src/app/core/modules/file/file-cropper/file-cropper.component.html @@ -0,0 +1,14 @@ + + +Cropper diff --git a/src/app/core/modules/file/file-cropper/file-cropper.component.scss b/src/app/core/modules/file/file-cropper/file-cropper.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/modules/file/file-cropper/file-cropper.component.ts b/src/app/core/modules/file/file-cropper/file-cropper.component.ts new file mode 100644 index 0000000..e511ca9 --- /dev/null +++ b/src/app/core/modules/file/file-cropper/file-cropper.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; +import { ImageCroppedEvent } from 'ngx-image-cropper'; + +@Component({ + selector: 'app-file-cropper', + templateUrl: './file-cropper.component.html', + styleUrl: './file-cropper.component.scss' +}) +export class FileCropperComponent { + close: () => void; + + croppedDataUrl: string; + + dataUrl: string; + + width: number; + + height: number; + + uploadImage: (croppedDataUrl: string) => void; + + imageCropped(event: ImageCroppedEvent): void { + this.croppedDataUrl = event.base64 as string; + } +} diff --git a/src/app/core/modules/file/file.component.html b/src/app/core/modules/file/file.component.html new file mode 100644 index 0000000..05d7344 --- /dev/null +++ b/src/app/core/modules/file/file.component.html @@ -0,0 +1,22 @@ +
+

{{ label }}

+ + + + + +
+
+ Picture + X +
+
+
diff --git a/src/app/core/modules/file/file.component.scss b/src/app/core/modules/file/file.component.scss new file mode 100644 index 0000000..2a655c9 --- /dev/null +++ b/src/app/core/modules/file/file.component.scss @@ -0,0 +1,70 @@ + +.file { + &__img { + display: block; + max-width: 100%; + height: auto; + border-radius: var(--file-img-border-radius, 8px); + cursor: pointer; + + &.round { + border-radius: 50%; + } + } + + &__add { + display: inline-block; + padding: 10px 20px; + background-color: var(--file-add-bg, #007bff); + color: #fff; + border-radius: 4px; + cursor: pointer; + text-align: center; + transition: background-color 0.3s ease; + + &:hover { + background-color: var(--file-add-bg-hover, #0056b3); + } + } + + &__list { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 10px; + } + + &__item { + position: relative; + display: inline-block; + + &-img { + display: block; + width: 100px; + height: 100px; + object-fit: cover; + border-radius: var(--file-item-border-radius, 4px); + cursor: pointer; + } + + &-remove { + position: absolute; + top: 5px; + right: 5px; + background-color: rgba(255, 0, 0, 0.8); + color: #fff; + border-radius: 50%; + width: 20px; + height: 20px; + text-align: center; + line-height: 20px; + font-size: 12px; + cursor: pointer; + transition: background-color 0.3s ease; + + &:hover { + background-color: rgba(255, 0, 0, 1); + } + } + } +} diff --git a/src/app/core/modules/file/file.component.ts b/src/app/core/modules/file/file.component.ts new file mode 100644 index 0000000..3cf0106 --- /dev/null +++ b/src/app/core/modules/file/file.component.ts @@ -0,0 +1,159 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { HttpService, ModalService } from 'wacom'; +import { FileService } from './file.service'; +import { FileCropperComponent } from './file-cropper/file-cropper.component'; + +/** + * The FileComponent is responsible for handling file uploads, primarily images, + * but can also handle other file types. It includes options for cropping and + * multiple file uploads. + */ +@Component({ + selector: 'ngx-file', + templateUrl: './file.component.html', + styleUrls: ['./file.component.scss'] +}) +export class FileComponent implements OnInit { + /** + * The container where the file will be stored (default: 'general'). + */ + @Input() container = 'general'; + + /** + * The name of the file. + */ + @Input() name = ''; + + /** + * Error message for handling errors. + */ + @Input() err = ''; + + /** + * Label for the file input. + */ + @Input() label = ''; + + /** + * Custom CSS class for styling. + */ + @Input() class = ''; + + /** + * Style object for the image. + */ + @Input() imgStyle = {}; + + /** + * Whether multiple files can be uploaded. + */ + @Input() multiple = false; + + /** + * Whether the file is a photo. + */ + @Input() isPhoto = false; + + /** + * Whether the image should be displayed as a round shape. + */ + @Input() isRound = false; + + /** + * Resize factor for the image. + */ + @Input() resize: number; + + /** + * Width for cropping the image. + */ + @Input() width: number; + + /** + * Height for cropping the image. + */ + @Input() height: number; + + /** + * The value of the uploaded file(s). + */ + @Input() value: string | string[] = this.multiple ? [] : ''; + + /** + * Event emitter to notify parent components of updates. + */ + @Output() update = new EventEmitter(); + + /** + * Forcefully set the image URL in case of an error. + */ + force = ''; + + /** + * Returns the list of files if multiple uploads are enabled. + */ + get files(): string[] { + return this.value as string[]; + } + + constructor( + private _modal: ModalService, + private _http: HttpService, + private _fs: FileService + ) {} + + ngOnInit(): void { + if (!this.name && !this.multiple && this.value) { + const paths = ((this.value as string) || '').split('/'); + this.name = paths[paths.length - 1].split('?')[0]; + } + } + + /** + * Initiates the file selection and cropping process. + */ + set(): void { + this._fs.setFile = (dataUrl: string) => { + if (this.width && this.height) { + this._modal.show({ + uploadImage: this.uploadImage.bind(this), + component: FileCropperComponent, + width: this.width, + height: this.height, + dataUrl + }); + } else { + this.uploadImage(dataUrl); + } + }; + } + + /** + * Uploads the image to the server. + * @param dataUrl The data URL of the image. + */ + uploadImage(dataUrl: string): void { + this._http.post( + '/api/file/photo', + { + container: this.container, + name: this.name, + dataUrl + }, + (url) => { + if (this.multiple) { + if (!this.value) { + this.value = []; + } + + (this.value as string[]).push(url); + } else { + this.name = url.split('/')[5].split('?')[0]; + this.value = url; + } + + this.update.emit(this.value); + } + ); + } +} diff --git a/src/app/core/modules/file/file.module.ts b/src/app/core/modules/file/file.module.ts new file mode 100644 index 0000000..7b35a87 --- /dev/null +++ b/src/app/core/modules/file/file.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { FileComponent } from './file.component'; +import { CommonModule } from '@angular/common'; +import { ImageCropperModule } from 'ngx-image-cropper'; +import { FileCropperComponent } from './file-cropper/file-cropper.component'; +import { ButtonModule } from '../button/button.module'; + +@NgModule({ + declarations: [FileCropperComponent, FileComponent], + exports: [FileComponent], + imports: [ImageCropperModule, CommonModule, ButtonModule] +}) +export class FileModule {} diff --git a/src/app/core/modules/file/file.service.ts b/src/app/core/modules/file/file.service.ts new file mode 100644 index 0000000..93756db --- /dev/null +++ b/src/app/core/modules/file/file.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; +import { FileService as WacomFileService } from 'wacom'; + +@Injectable({ + providedIn: 'root' +}) +export class FileService { + setFile: (dataUrl: string) => void; + + constructor(private _file: WacomFileService) { + this._file.add({ + id: 'formPhoto', + // accept: 'image/*', + resize: 1920, + cb: (file: any) => { + if ( + typeof file === 'string' && + typeof this.setFile === 'function' + ) { + this.setFile(file); + } + } + }); + + this._file.add({ + id: 'formPhotos', + // accept: 'image/*', + multiple: true, + resize: 1920, + cb: (file: any) => { + if ( + typeof file === 'string' && + typeof this.setFile === 'function' + ) { + this.setFile(file); + } + } + }); + } +} diff --git a/src/app/core/modules/file/module.json b/src/app/core/modules/file/module.json new file mode 100644 index 0000000..9847fc1 --- /dev/null +++ b/src/app/core/modules/file/module.json @@ -0,0 +1,10 @@ +{ + "repo" : "git@github.com:WebArtWork/ngx-file.git", + "dependencies": { + "ngx-image-cropper": "*" + }, + "modules": { + "button": "*", + "modal": "*" + } +} diff --git a/src/app/core/modules/file/readme.MD b/src/app/core/modules/file/readme.MD new file mode 100644 index 0000000..f96bceb --- /dev/null +++ b/src/app/core/modules/file/readme.MD @@ -0,0 +1,115 @@ +# Ngx File Component + +The `ngx-file` component is an Angular component designed for handling file uploads, primarily for images, but it also supports other file types. It provides a flexible interface for uploading single or multiple files, with optional image cropping. + +## Features + +- Upload single or multiple files. +- Handle image cropping before upload. +- Customizable error handling. +- Flexible styling with CSS variables. +- Support for different file types. + +## Installation + +To install the module, use the following command: + +waw add ngx-file + +## Usage + +### Importing the Module + +First, import the `FileModule` into your Angular module: +```Typescript +import { FileModule } from '@your-namespace/ngx-file'; + +@NgModule({ + declarations: [...], + imports: [ + FileModule, + ... + ], + providers: [], + bootstrap: [...] +}) +export class AppModule { } +``` +### Basic Example + +Here’s a basic example of how to use the `ngx-file` component: +```Typescript + + + + +``` +### Handling Multiple Files + +You can enable multiple file uploads by setting the `multiple` input property: +```Typescript + + +``` +### Inputs + +- **container** (`string`): The container where the file will be stored (default: `'general'`). +- **name** (`string`): The name of the file. +- **err** (`string`): Error message for handling errors. +- **label** (`string`): Label for the file input. +- **class** (`string`): Custom CSS class for styling. +- **imgStyle** (`object`): Style object for the image. +- **multiple** (`boolean`): Whether multiple files can be uploaded. +- **isPhoto** (`boolean`): Whether the file is a photo. +- **isRound** (`boolean`): Whether the image should be displayed as a round shape. +- **resize** (`number`): Resize factor for the image. +- **width** (`number`): Width for cropping the image. +- **height** (`number`): Height for cropping the image. +- **value** (`string | string[]`): The value of the uploaded file(s). + +### Outputs + +- **update** (`EventEmitter`): Event emitter to notify parent components of updates. + +### Methods + +- **set()**: Initiates the file selection and cropping process. +- **uploadImage(dataUrl: string)**: Uploads the image to the server. + +### SCSS Customization + +The component supports CSS variables for easy customization. Below are some of the customizable variables: + +- `--file-img-border-radius`: Border radius for the images (default: `8px`). +- `--file-add-bg`: Background color for the add button (default: `#007bff`). +- `--file-add-bg-hover`: Background color for the add button on hover (default: `#0056b3`). +- `--file-item-border-radius`: Border radius for file items (default: `4px`). + +### Example of Custom CSS Variables + +You can customize the styles using CSS variables in your global styles or component-specific styles: +```scss +:root { + --file-img-border-radius: 50%; + --file-add-bg: #28a745; + --file-add-bg-hover: #218838; + --file-item-border-radius: 10px; +} +``` +## Contributing + +Feel free to contribute to this project by opening issues or submitting pull requests. Make sure to follow the contribution guidelines. + +## License + +This project is licensed under the MIT License. diff --git a/src/app/core/modules/form/form-component/form-component.component.html b/src/app/core/modules/form/form-component/form-component.component.html new file mode 100644 index 0000000..6461682 --- /dev/null +++ b/src/app/core/modules/form/form-component/form-component.component.html @@ -0,0 +1,42 @@ + +
+ + + +
+
+ + +
+ +
+
diff --git a/src/app/core/modules/form/form-component/form-component.component.scss b/src/app/core/modules/form/form-component/form-component.component.scss new file mode 100644 index 0000000..96a206c --- /dev/null +++ b/src/app/core/modules/form/form-component/form-component.component.scss @@ -0,0 +1,63 @@ +:host { + position: relative; +} + +.w-forms { + position: relative; + padding: 0 !important; + background-color: red; + &__component{ + align-items: end; + margin: 0 0 10px 0; + } + &__level { + top: 3px; + right: 5px; + position: absolute; + display: inline-block; + color: var(--c-text-secondary); + // font-size: calc(#{var(--fs)} - 6px); + font-size: 22px; + line-height: calc(#{var(--fs)} + 4px); + letter-spacing: var(--letter-spacing); + transition: var(--transition); + + &._sky { + color: var(--c-info); + } + + &._orange { + color: var(--c-warn); + } + + &._green { + color: var(--c-success); + } + } + + &__input { + padding-right: 35px; + } + + &__input-block { + position: relative; + } + + &__toggle { + display: flex; + position: absolute; + right: 10px; + bottom: 10px; + color: var(--c-placeholder); + transform: translateY(-50%); + cursor: pointer; + + i { + font-size: 21px; + } + } + + .icon-visibility { + color: var(--c-primary); + } +} diff --git a/src/app/core/modules/form/form-component/form-component.component.ts b/src/app/core/modules/form/form-component/form-component.component.ts new file mode 100644 index 0000000..4346991 --- /dev/null +++ b/src/app/core/modules/form/form-component/form-component.component.ts @@ -0,0 +1,138 @@ +import { + Component, + EventEmitter, + Input, + OnInit, + Output, + TemplateRef +} from '@angular/core'; +import { FormComponentInterface } from '../interfaces/component.interface'; +import { FormInterface } from '../interfaces/form.interface'; +import { FormService } from '../form.service'; + +@Component({ + selector: 'form-component', + templateUrl: './form-component.component.html', + styleUrls: ['./form-component.component.scss'] +}) +export class FormComponentComponent implements OnInit { + @Input() index: string; + + @Input() config: FormInterface; + + @Input() component: FormComponentInterface; + + @Input() submition: Record = {}; + + @Output() wSubmit = new EventEmitter(); + + @Output() wChange = new EventEmitter(); + + @Output() wClick = new EventEmitter(); + + submit(): void { + this.wSubmit.emit(this.submition); + } + + change(): void { + this.wChange.emit(this.submition); + } + + click(): void { + this.wClick.emit(this.submition); + } + + get hasComponents(): boolean { + return Array.isArray(this.component.components); + } + + get template(): TemplateRef { + return this._form.getTemplateComponent( + this.component.name as string + ) as TemplateRef; + } + + field: Record = {}; + + localKey: string; + + localSubmition: Record; + + constructor(private _form: FormService) {} + + ngOnInit(): void { + if (Array.isArray(this.component.fields)) { + for (const field of this.component.fields) { + this.field[field.name] = field.value; + } + } + + this.localSubmition = this.submition; + + const keys = (this.component.key || '')?.split('.'); + + while (keys.length > 1) { + let key = keys.shift() as string; + + if (key.endsWith('[]')) { + key = key.replace('[]', ''); + + const index = this._getIndex(); + + this.localSubmition[key] = (this.localSubmition[key] || + []) as Record[]; + + while ( + index + 1 > + (this.localSubmition[key] as Record[]) + .length + ) { + ( + this.localSubmition[key] as Record[] + ).push({}); + } + + this.localSubmition = ( + this.localSubmition[key] as Record[] + )[index]; + } else { + this.localSubmition = this.localSubmition[ + this.localKey + ] as Record; + } + } + + this.localKey = keys[0]; + } + + private _getIndex(components = this.config.components): number { + for (const component of components) { + if (component.components) { + const localIndex = this._getIndex(component.components); + + if (localIndex >= 0) { + for (let i = 0; i < component.components.length; i++) { + for (const comp of component.components[i] + .components as Record[]) { + if (comp === this.component) { + return i; + } + } + } + } + + if ( + component?.components?.indexOf( + this.component as unknown as any + ) >= 0 + ) { + return component.components.indexOf( + this.component as unknown as any + ); + } + } + } + + return -1; + } +} diff --git a/src/app/core/modules/form/form.component.html b/src/app/core/modules/form/form.component.html new file mode 100644 index 0000000..67ab950 --- /dev/null +++ b/src/app/core/modules/form/form.component.html @@ -0,0 +1,19 @@ +
+

{{config.title}}

+
+ + + +
+
diff --git a/src/app/core/modules/form/form.component.scss b/src/app/core/modules/form/form.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/modules/form/form.component.ts b/src/app/core/modules/form/form.component.ts new file mode 100644 index 0000000..e59cf34 --- /dev/null +++ b/src/app/core/modules/form/form.component.ts @@ -0,0 +1,85 @@ +import { + AfterViewInit, + Component, + EventEmitter, + Input, + Output +} from '@angular/core'; +import { FormComponentInterface } from './interfaces/component.interface'; +import { FormInterface } from './interfaces/form.interface'; +import { CoreService } from 'wacom'; + +@Component({ + selector: 'wform', + templateUrl: './form.component.html', + styleUrls: ['./form.component.scss'] +}) +export class FormComponent implements AfterViewInit { + @Input() config: FormInterface; + + @Input() submition: Record = {}; + + @Output() wChange = new EventEmitter(); + + @Output() wSubmit = new EventEmitter(); + + constructor(private _core: CoreService) {} + + ngAfterViewInit(): void { + this.submition['data'] = this.submition['data'] || {}; + } + + component( + key: string, + components = this.config.components + ): FormComponentInterface | false { + for (const component of components) { + if (component.key === key) { + return component; + } + + if (component.components?.length) { + const deepComponent = this.component(key, component.components); + + if (deepComponent) { + return deepComponent; + } + } + } + + return false; + } + + onSubmit(): void { + this._core.afterWhile(this, () => { + for (const component of this.config.components) { + if ( + component.key && + component.required && + ((component.valid && !component.valid()) || + (!component.valid && !this.submition[component.key])) + ) { + if (typeof component.focus === 'function') { + component.focus(); + } + + return; + } + } + + this.wSubmit.emit(this.submition); + }); + } + + onChange(): void { + this._core.afterWhile(this, () => { + this.wChange.emit(this.submition); + }); + } + + onClick(/* component: FormComponentInterface */): void { + // if (typeof component.click === 'function') { + // component.click(this.submition); + // } + } +} diff --git a/src/app/core/modules/form/form.module.ts b/src/app/core/modules/form/form.module.ts new file mode 100644 index 0000000..7f37a34 --- /dev/null +++ b/src/app/core/modules/form/form.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { FormComponent } from './form.component'; +import { FormComponentComponent } from './form-component/form-component.component'; +import { ModalFormComponent } from './modals/modal-form/modal-form.component'; +import { ModalFormButtonComponent } from './modals/modal-form/modal-form-button/modal-form-button.component'; +import { ModalUniqueComponent } from './modals/modal-unique/modal-unique.component'; +import { CommonModule } from '@angular/common'; +import { ButtonModule } from '../button/button.module'; + +@NgModule({ + imports: [CommonModule, ButtonModule], + declarations: [ + FormComponent, + FormComponentComponent, + ModalFormComponent, + ModalFormButtonComponent, + ModalUniqueComponent + ], + exports: [FormComponent] +}) +export class FormModule {} diff --git a/src/app/core/modules/form/form.service.ts b/src/app/core/modules/form/form.service.ts new file mode 100644 index 0000000..a566b53 --- /dev/null +++ b/src/app/core/modules/form/form.service.ts @@ -0,0 +1,298 @@ +import { + ComponentFactoryResolver, + ApplicationRef, + TemplateRef, + Injectable, + Injector, + Type +} from '@angular/core'; +import { ModalService, StoreService } from 'wacom'; +import { TemplateFieldInterface } from './interfaces/component.interface'; +import { FormInterface } from './interfaces/form.interface'; +import { ModalFormComponent } from './modals/modal-form/modal-form.component'; +import { TranslateService } from '../translate/translate.service'; +import { ModalUniqueComponent } from './modals/modal-unique/modal-unique.component'; +import { environment } from 'src/environments/environment'; +import { CustomformService } from 'src/app/modules/customform/services/customform.service'; +import { Modal } from 'wacom/lib/interfaces/modal.interface'; + +export interface FormModalButton { + /** Function to execute on button click */ + click: (submition: unknown, close: () => void) => void; + /** Label for the button */ + label: string; + /** CSS class for the button (optional) */ + class?: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class FormService { + /** Application ID from the environment configuration */ + readonly appId = (environment as unknown as { appId: string }).appId; + + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private _cfs: CustomformService, + private _translate: TranslateService, + private _modal: ModalService, + private _store: StoreService, + private appRef: ApplicationRef, + private injector: Injector + ) { + /** Load form IDs from the store */ + this._store.getJson('formIds', (formIds: string[]) => { + if (Array.isArray(formIds)) { + this.formIds.push(...formIds); + } + }); + } + + private _injectedComponent: Record = {}; + templateFields: Record = {}; + getTemplateFields(name: string): string[] { + return this.templateFields[name] || ['Placeholder', 'Label']; + } + setTemplateFields( + name: string, + fields: string[], + customFields: Record = {} + ): void { + this.templateFields[name] = fields; + + this.customTemplateFields[name] = { + ...(this.customTemplateFields[name] || {}), + ...customFields + }; + } + customTemplateFields: Record> = {}; + getCustomTemplateFields(name: string): Record { + return this.customTemplateFields[name] || {}; + } + injectComponent( + name: string, + component: Type, + fields = ['Placeholder', 'Label'], + customFields: Record = {} + ): void { + if (!this._injectedComponent[name]) { + this._injectedComponent[name] = true; + + this.templateFields[name] = fields; + + this.customTemplateFields[name] = customFields; + + const componentFactory = + this.componentFactoryResolver.resolveComponentFactory( + component + ); + + const componentRef = componentFactory.create(this.injector); + + this.appRef.attachView(componentRef.hostView); + + const domElem = ( + componentRef.hostView as unknown as { rootNodes: HTMLElement[] } + ).rootNodes[0]; + + document.body.appendChild(domElem); + } + } + private _templateComponent: Record> = {}; + addTemplateComponent(name: string, template: TemplateRef): void { + if (!this._templateComponent[name]) { + this._templateComponent[name] = template; + } + } + getTemplateComponent(name: string): TemplateRef | undefined { + return this._templateComponent[name]; + } + getTemplateComponentsNames(): string[] { + const names = []; + + for (const name in this._templateComponent) { + names.push(name); + } + + return names; + } + + /** Translates the form title and its components' fields */ + translateForm(form: FormInterface): void { + if (form.title) { + form.title = this._translate.translate( + `Form_${form.formId}.${form.title}`, + (title: string) => { + form.title = title; + } + ); + + for (const component of form.components) { + for (const field of component.fields || []) { + this.translateFormComponent(form, field); + } + } + } + } + /** Translates individual form components' fields */ + translateFormComponent( + form: FormInterface, + field: TemplateFieldInterface + ): void { + const fieldValue = field.value; + + if (typeof fieldValue === 'string' && !field.skipTranslation) { + field.value = this._translate.translate( + `Form_${form.formId}.${fieldValue}`, + (value: string) => { + field.value = value; + } + ); + } + } + + /** List of forms managed by the service */ + forms: FormInterface[] = []; + + /** List of form IDs managed by the service */ + formIds: string[] = []; + + /** Creates a default form with specified components */ + getDefaultForm( + id: string, + components = ['name', 'description'] + ): FormInterface { + if (this.formIds.indexOf(id) === -1) { + this.formIds.push(id); + + this._store.setJson('formIds', this.formIds); + } + + const form = { + id, + components: components.map((key, index) => { + const name = key.includes('.') ? key.split('.')[1] : 'Text'; + + return { + name, + key, + focused: !index, + fields: [ + { + name: 'Placeholder', + value: 'Enter your ' + key.split('.')[0] + }, + { + name: 'Label', + value: key.split('.')[0].capitalize() + } + ] + }; + }) + }; + + return form; + } + + /** Retrieves a form by its ID, initializing it if necessary */ + getForm(formId: string, form?: FormInterface): FormInterface { + if ( + form && + this.forms.map((c) => c.formId).indexOf(form?.formId) === -1 + ) { + this.forms.push(form); + } + + if (this.formIds.indexOf(formId) === -1) { + this.formIds.push(formId); + + this._store.setJson('formIds', this.formIds); + } + + form = form || this.forms.find((f) => f.formId === formId); + + form = form || this.getDefaultForm(formId); + + if (form) { + for (const component of form.components) { + component.root = true; + } + } + + const customForms = this._cfs.customforms.filter( + (f) => f.active && f.formId === formId + ); + + form.formId = formId; + + for (const customForm of customForms) { + form.title = form.title || customForm.name; + + form.class = form.class || customForm.class; + + for (const component of customForm.components) { + component.root = false; + + form.components.push(component); + } + } + + this.translateForm(form); + + return form; + } + + /** Shows a modal form with specified options */ + modal( + form: FormInterface | FormInterface[], + buttons: FormModalButton | FormModalButton[] = [], + submition: unknown = {}, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + change = (update: T): void => {}, + modalOptions: Modal = {} + ): Promise { + return new Promise((resolve) => { + this._modal.show({ + ...modalOptions, + component: ModalFormComponent, + class: 'forms_modal', + form, + buttons: Array.isArray(buttons) ? buttons : [buttons], + submition, + onClose: function () { + resolve(this.submition as T); + }, + submit: (update: T) => { + resolve(update); + }, + change: (update: T) => { + if (typeof change === 'function') { + change(update); + } + } + }); + }); + } + + /** Shows a modal with a unique component */ + modalUnique( + module: string, + field: string, + doc: T, + component: string = '', + onClose = (): void => {} + ): void { + this._modal.show({ + component: ModalUniqueComponent, + form: this.getDefaultForm('unique', [ + field + (component ? '.' + component : '') + ]), + module, + field, + doc, + class: 'forms_modal', + onClose + }); + } +} diff --git a/src/app/core/modules/form/interfaces/component.interface.ts b/src/app/core/modules/form/interfaces/component.interface.ts new file mode 100644 index 0000000..a31c7c2 --- /dev/null +++ b/src/app/core/modules/form/interfaces/component.interface.ts @@ -0,0 +1,30 @@ +export interface TemplateFieldInterface { + name: string; + value: unknown; + skipTranslation?: boolean; +} + +export interface TemplateComponentInterface { + name: string; + component: unknown; + fields?: string[]; + fieldComponent?: Record; +} + +export interface FormComponentInterface { + components?: FormComponentInterface[]; + // or + name?: string; // template name + key?: string; // submition location + root?: boolean; // if key should be applied to data or root document + focus?: () => void; // to set focus in components where we have focus functionality + focused?: boolean; // in case of focus functionality, we focus on init + hidden?: boolean; // if component should be hidden or shown + class?: string; // put class on component container + fields?: TemplateFieldInterface[]; // pass general info to component + valid?: () => boolean; // check if component is valid + required?: boolean; // set component requirement + disabled?: boolean; // set component disabled + // disabled?: boolean | (value: unknown) => boolean; + component?: unknown; // deprecated +} diff --git a/src/app/core/modules/form/interfaces/form.interface.ts b/src/app/core/modules/form/interfaces/form.interface.ts new file mode 100644 index 0000000..448fac1 --- /dev/null +++ b/src/app/core/modules/form/interfaces/form.interface.ts @@ -0,0 +1,12 @@ +import { FormComponentInterface } from './component.interface'; + +export interface FormInterface { + formId?: string; // developer id, usually name of where that form will be used + _id?: string; // mongodb id, will be null where form will be inside the code + components: FormComponentInterface[]; + appId?: string; + title?: string; + class?: string; + active?: boolean; + submited?: boolean; +} diff --git a/src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.html b/src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.html new file mode 100644 index 0000000..dc321c0 --- /dev/null +++ b/src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.html @@ -0,0 +1,13 @@ + diff --git a/src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.scss b/src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.ts b/src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.ts new file mode 100644 index 0000000..4548e25 --- /dev/null +++ b/src/app/core/modules/form/modals/modal-form/modal-form-button/modal-form-button.component.ts @@ -0,0 +1,25 @@ +import { + Component, + EventEmitter, + Input, + Output, + TemplateRef +} from '@angular/core'; +import { FormModalButton } from '../../../form.service'; + +@Component({ + selector: 'app-modal-form-button', + templateUrl: './modal-form-button.component.html', + styleUrls: ['./modal-form-button.component.scss'] +}) +export class ModalFormButtonComponent { + @Input() button: FormModalButton; + + @Input() buttonRef: TemplateRef; + + @Output() clicked = new EventEmitter(); + + clickedd() { + console.log('clicked'); + } +} diff --git a/src/app/core/modules/form/modals/modal-form/modal-form.component.html b/src/app/core/modules/form/modals/modal-form/modal-form.component.html new file mode 100644 index 0000000..b1ba574 --- /dev/null +++ b/src/app/core/modules/form/modals/modal-form/modal-form.component.html @@ -0,0 +1,18 @@ + + +
+ + {{button.label}} + +
diff --git a/src/app/core/modules/form/modals/modal-form/modal-form.component.scss b/src/app/core/modules/form/modals/modal-form/modal-form.component.scss new file mode 100644 index 0000000..a98479c --- /dev/null +++ b/src/app/core/modules/form/modals/modal-form/modal-form.component.scss @@ -0,0 +1,9 @@ +.btn-action { + padding: 30px 0; + padding-bottom: 0; + + .w-btn { + width: 100%; + display: block; + } +} diff --git a/src/app/core/modules/form/modals/modal-form/modal-form.component.ts b/src/app/core/modules/form/modals/modal-form/modal-form.component.ts new file mode 100644 index 0000000..826f9e7 --- /dev/null +++ b/src/app/core/modules/form/modals/modal-form/modal-form.component.ts @@ -0,0 +1,30 @@ +import { Component } from '@angular/core'; +import { FormModalButton } from '../../form.service'; +import { FormInterface } from '../../interfaces/form.interface'; +import { CoreService } from 'wacom'; + +@Component({ + templateUrl: './modal-form.component.html', + styleUrls: ['./modal-form.component.scss'] +}) +export class ModalFormComponent { + form: FormInterface; + + submition: Record; + + set(submition: Record): void { + this._core.copy(submition, this.submition); + + this._core.copy(submition['data'], this.submition['data']); + } + + close: () => void; + // eslint-disable-next-line + submit: (form: any) => void; + // eslint-disable-next-line + change: (form: any) => void; + + buttons: FormModalButton[]; + + constructor(private _core: CoreService) {} +} diff --git a/src/app/core/modules/form/modals/modal-unique/modal-unique.component.html b/src/app/core/modules/form/modals/modal-unique/modal-unique.component.html new file mode 100644 index 0000000..5d85430 --- /dev/null +++ b/src/app/core/modules/form/modals/modal-unique/modal-unique.component.html @@ -0,0 +1 @@ + diff --git a/src/app/core/modules/form/modals/modal-unique/modal-unique.component.scss b/src/app/core/modules/form/modals/modal-unique/modal-unique.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/modules/form/modals/modal-unique/modal-unique.component.ts b/src/app/core/modules/form/modals/modal-unique/modal-unique.component.ts new file mode 100644 index 0000000..0b2dca4 --- /dev/null +++ b/src/app/core/modules/form/modals/modal-unique/modal-unique.component.ts @@ -0,0 +1,34 @@ +import { Component } from '@angular/core'; +import { FormInterface } from '../../interfaces/form.interface'; +import { MongoService } from 'wacom'; + +@Component({ + selector: 'app-modal-unique', + templateUrl: './modal-unique.component.html', + styleUrls: ['./modal-unique.component.scss'] +}) +export class ModalUniqueComponent { + constructor(private _mongo: MongoService) {} + form: FormInterface; + module: string; + field: string; + // eslint-disable-next-line + doc: any; + get getDoc(): Record { + return this.doc as Record; + } + change(): void { + this._mongo.unique( + this.module, + this.doc, + { + name: this.field + }, + (resp: string) => { + if (this.doc[this.field] !== resp) { + this.doc[this.field] = resp; + } + } + ); + } +} diff --git a/src/app/core/modules/input/.gitignore b/src/app/core/modules/input/.gitignore new file mode 100644 index 0000000..bb6fa4d --- /dev/null +++ b/src/app/core/modules/input/.gitignore @@ -0,0 +1,104 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port \ No newline at end of file diff --git a/src/app/core/modules/input/LICENSE b/src/app/core/modules/input/LICENSE new file mode 100644 index 0000000..bae3c75 --- /dev/null +++ b/src/app/core/modules/input/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/app/core/modules/input/README.md b/src/app/core/modules/input/README.md new file mode 100644 index 0000000..cc8da81 --- /dev/null +++ b/src/app/core/modules/input/README.md @@ -0,0 +1,118 @@ +# Input Module + +The Input Module is a customizable Angular component designed to handle various types of input fields, including text, password, email, radio buttons, checkboxes, and more. This module provides an easy way to manage form inputs with built-in validation, error handling, and flexible event handling. + +## Features + +- Supports a wide range of input types including text, password, email, radio, checkbox, textarea, and more. +- Customizable validation and replacement logic. +- Emits events for value changes, form submissions, and blur events. +- Error handling with visual feedback. + +## Installation + +To install this module, use the following command: +```cmd +waw add ngx-input +``` +## Usage + +### Importing the Module + +First, import the `InputModule` into your Angular module: +```Typescript +import { InputModule } from '@your-namespace/input-module'; + +@NgModule({ + declarations: [...], + imports: [ + InputModule, + ... + ], + providers: [], + bootstrap: [...] +}) +export class AppModule { } +``` +### Basic Example + +Here's a basic example of how to use the input component in your Angular template: +```Typescript + +``` +### Handling Different Input Types + +The `InputComponent` supports a wide variety of input types: + +- `text` +- `password` +- `email` +- `radio` +- `checkbox` +- `textarea` +- `number` +- `url` +- `date` +- `time` +- `file` +- `color` +- And more... + +Example: +```Typescript + +``` +### Custom Validation and Replacement + +You can provide custom validation and replacement logic: +```Typescript + +``` + +## API + +### Inputs + +- **type** (`string`): The type of input. Supports all standard HTML input types. +- **value** (`string | number | boolean`): The current value of the input. +- **placeholder** (`string`): The placeholder text for the input. +- **disabled** (`boolean`): Whether the input is disabled. +- **focused** (`boolean`): Whether the input should be focused when initialized. +- **wClass** (`string`): Custom CSS classes for styling the input. +- **name** (`string`): The name attribute of the input. +- **label** (`string`): The label for the input. + +### Outputs + +- **wChange** (`EventEmitter`): Emits the new value whenever the input value changes. +- **wSubmit** (`EventEmitter`): Emits the value when the form is submitted (e.g., on pressing Enter). +- **wBlur** (`EventEmitter`): Emits when the input loses focus. + +## Customization + +You can customize the appearance and behavior of the input component using custom CSS and by passing custom validation or replacement functions. + +## Contributing + +Feel free to contribute to this project by opening issues or submitting pull requests. Make sure to follow the contribution guidelines. + +## License + +This project is licensed under the MIT License. diff --git a/src/app/core/modules/input/input.component.html b/src/app/core/modules/input/input.component.html new file mode 100644 index 0000000..1875b56 --- /dev/null +++ b/src/app/core/modules/input/input.component.html @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + diff --git a/src/app/core/modules/input/input.component.scss b/src/app/core/modules/input/input.component.scss new file mode 100644 index 0000000..e1b69f7 --- /dev/null +++ b/src/app/core/modules/input/input.component.scss @@ -0,0 +1,190 @@ +@import 'angular'; + +/* ===================================== + General Input Styles + These styles apply to all input fields + ===================================== */ +.w-forms { + position: relative; + padding: 10px 0; + display: block; + + &__title { + letter-spacing: 0; + line-height: 23px; + font-weight: 500; + font-size: 20px; + color: var(--c-text-primary); + display: flex; + justify-content: space-between; + align-items: center; + border-radius: var(--b-radius); + margin-bottom: 10px; /* Adjusted margin */ + } + + /* Input and Textarea shared styling */ + &__field, + .w-forms__textarea { + background-color: transparent; + border: 1px solid var(--c-border); + border-radius: var(--b-radius); + color: var(--c-text-secondary); + font-size: calc(#{var(--fs)} - 2px); + line-height: calc(#{var(--fs)} + 4px); + transition: var(--transition); + width: 100%; /* Ensure input fields take full width of the container */ + display: block; + letter-spacing: var(--letter-spacing); + padding: 8px 12px; /* Adjusted padding for better visual alignment */ + + /* Ensure compatibility across browsers */ + appearance: textfield; + -webkit-appearance: textfield; /* For WebKit-based browsers */ + -moz-appearance: textfield; /* For Mozilla-based browsers */ + + &::placeholder { + color: var(--c-placeholder); + transition: var(--transition); + } + + &:focus { + transition: var(--transition); + border-color: var(--c-primary); + outline: none; /* Remove default outline for better visual focus */ + } + + &:disabled { + background-color: var(--c-grey); + border-color: var(--c-grey); + color: var(--c-grey); + cursor: default; + opacity: 0.6; + } + + &[type='time'] { + -webkit-appearance: textfield; + -moz-appearance: textfield; + appearance: textfield; + } + } + + /* Hidden checkbox input, used in custom styled checkboxes */ + &__checkbox { + display: none; + + &:checked ~ .checkbox::before { + opacity: 1; + } + } +} + +/* Error Styling */ +input.error, textarea.error { + border: 1px solid red; /* Red border to indicate validation error */ +} + +/* Error message display */ +.error-message { + color: red; /* Red text for error messages */ + font-size: 12px; /* Slightly smaller text size for error messages */ + margin-top: 4px; /* Spacing above the error message */ +} + +/* ===================================== + Radio Button Styles + ===================================== */ +.check-label { + display: flex; + column-gap: 5px; + cursor: pointer; + + /* Custom radio button checkbox styling */ + .checkbox { + position: relative; + width: 18px; + height: 18px; + display: inline-block; + border-radius: 4px; + transform: scale(1); + border: 1px solid var(--c-border); + transition: var(--transition); + box-shadow: 0 1px 1px var(--c-shadow); + + &::before { + position: absolute; + left: 50%; + top: 50%; + transition: var(--transition); + opacity: 0; + transform: translate(-50%, -65%) rotate(45deg); + height: 11px; + width: 7px; + display: block; + content: ''; + border-bottom: 2px solid var(--c-primary); + border-right: 2px solid var(--c-primary); + } + } +} + +/* ===================================== + Checkbox Styles + ===================================== */ +.container-box { + position: relative; + padding-left: 35px; + margin-bottom: 12px; + cursor: pointer; + font-size: 22px; + user-select: none; + + /* Hidden checkbox input, used in custom styled checkboxes */ + input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; + } + + /* Custom checkbox styling */ + .checkmark { + position: absolute; + top: 0; + left: 0; + height: 32px; + width: 32px; + background-color: #12677a6e; + border-radius: 50%; + transition: all 0.3s; + + &:after, + &:before { + content: ''; + position: absolute; + display: none; + } + + &:after { + left: 10px; + top: 47%; + width: 8px; + height: 14px; + border: solid white; + border-width: 0 3px 3px 0; + transform: rotate(45deg) translate(-50%, -50%); + } + } + + &:hover input ~ .checkmark { + background-color: #0f353d60; + } + + input:checked ~ .checkmark { + background-color: var(--c-primary); + + &:after { + display: block; + } + } +} diff --git a/src/app/core/modules/input/input.component.ts b/src/app/core/modules/input/input.component.ts new file mode 100644 index 0000000..91aaeb6 --- /dev/null +++ b/src/app/core/modules/input/input.component.ts @@ -0,0 +1,207 @@ +import { + Component, + Input, + Output, + EventEmitter, + OnInit, + ElementRef, + ViewChild, + OnChanges, + SimpleChanges +} from '@angular/core'; +import { CoreService } from 'wacom'; + +/** + * InputComponent is a customizable input component that supports various types of inputs, + * including text, radio buttons, checkboxes, and textareas. It also provides validation, + * custom value replacement, and event handling for changes, submissions, and blur events. + */ +@Component({ + selector: 'winput', + templateUrl: './input.component.html', + styleUrls: ['./input.component.scss'] +}) +export class InputComponent implements OnInit, OnChanges { + /** + * The value of the input field. + */ + @Input() value: string | number | boolean = ''; + + /** + * A function to replace the input value before emitting changes. + * This allows custom transformations of the input value. + */ + @Input() replace: ( + value: string | number | boolean + ) => string | number | boolean; + + /** + * A function to validate the input value. The default implementation checks for a truthy value. + */ + @Input() valid: (value: string | number | boolean) => boolean = ( + value: string | number | boolean + ) => !!value; + + /** + * A list of items used for radio buttons or other list-based inputs. + */ + @Input() items: string[] = []; + + /** + * The placeholder text for the input field. + */ + @Input() placeholder = ''; + + /** + * Whether the input field is disabled. + */ + @Input() disabled = false; + + /** + * Whether the input field should be focused when the component initializes. + */ + @Input() focused = false; + + /** + * Custom CSS classes for styling the input field. + */ + @Input() wClass: string; + + /** + * The name attribute of the input field. + */ + @Input() name = 'name'; + + /** + * The type of input. + */ + @Input() type: + | 'text' + | 'password' + | 'email' + | 'radio' + | 'checkbox' + | 'textarea' + | 'search' + | 'tel' + | 'url' + | 'number' + | 'range' + | 'color' + | 'date' + | 'month' + | 'week' + | 'time' + | 'datetime' + | 'datetime-local' = 'text'; + + /** + * The label for the input field. + */ + @Input() label = ''; + + /** + * The label for the input field. + */ + @Input() setFocus: { + focus: () => void; + }; + + /** + * Event emitted when the input value changes. + */ + @Output() wChange = new EventEmitter(); + + /** + * Event emitted when the form is submitted. + */ + @Output() wSubmit = new EventEmitter(); + + /** + * Event emitted when the input field loses focus. + */ + @Output() wBlur = new EventEmitter(); + + /** + * Reference to the input element in the template. + */ + @ViewChild('inputEl') inputEl: ElementRef; + + /** + * Error state of the input field, set to true if validation fails. + */ + error = false; + + constructor(private _core: CoreService) {} + + /** + * Initializes the component. Focuses the input field if the focused input is true. + */ + ngOnInit(): void { + if (this.focused) { + this.focus(); + } + + if (this.setFocus) { + this.setFocus.focus = this.focus.bind(this); + } + } + + /** + * Detect changes. + */ + ngOnChanges(changes: SimpleChanges): void { + console.log(changes); + + if (changes['disabled']) { + this.disabled = changes['disabled'].currentValue; + } + } + + /** + * Focuses the input field. + */ + focus(): void { + setTimeout(() => { + this.inputEl.nativeElement.focus(); + }, 100); + } + + /** + * Handles the change event for the input field. + * Applies the replace function if provided, and emits the new value. + */ + onChange(): void { + this._core.afterWhile( + 'winput', + (): void => { + this.value = + typeof this.replace === 'function' + ? this.replace(this.value) + : this.value; + + this.wChange.emit(this.value); + }, + 100 + ); + } + + /** + * Handles the submit event for the input field. + * Validates the input value before emitting the submit event. + */ + onSubmit(): void { + if (this.valid(this.value)) { + this.wSubmit.emit(this.value); + } else { + this.error = true; + } + } + + /** + * Sets the disabled state of the input field. + */ + setDisabled(disabled: boolean): void { + this.disabled = disabled; + } +} diff --git a/src/app/core/modules/input/input.module.ts b/src/app/core/modules/input/input.module.ts new file mode 100644 index 0000000..ade953b --- /dev/null +++ b/src/app/core/modules/input/input.module.ts @@ -0,0 +1,12 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { InputComponent } from './input.component'; + +@NgModule({ + imports: [FormsModule, CommonModule], + declarations: [InputComponent], + providers: [], + exports: [InputComponent] +}) +export class InputModule {} diff --git a/src/app/core/modules/input/module.json b/src/app/core/modules/input/module.json new file mode 100644 index 0000000..367bd4f --- /dev/null +++ b/src/app/core/modules/input/module.json @@ -0,0 +1,3 @@ +{ + "repo": "git@github.com:WebArtWork/ngx-input.git" +} diff --git a/src/app/core/modules/list/.gitignore b/src/app/core/modules/list/.gitignore new file mode 100644 index 0000000..6704566 --- /dev/null +++ b/src/app/core/modules/list/.gitignore @@ -0,0 +1,104 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/src/app/core/modules/list/LICENSE b/src/app/core/modules/list/LICENSE new file mode 100644 index 0000000..1125219 --- /dev/null +++ b/src/app/core/modules/list/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app/core/modules/list/README.md b/src/app/core/modules/list/README.md new file mode 100644 index 0000000..6733cf9 --- /dev/null +++ b/src/app/core/modules/list/README.md @@ -0,0 +1,103 @@ +# Ngx List Component + +The `ngx-list` component is an Angular component designed for displaying a list of items with advanced features like infinite scrolling, pull to refresh, and loading more items on demand. + +## Features + +- Infinite scrolling to load more items as the user scrolls. +- Pull to refresh functionality. +- Load more items with a button click. +- Flexible and customizable layout. +- Adjustable step for loading more items. + +## Installation + +To install the module, use the following command: +```cmd +waw add ngx-list +``` +## Usage + +### Importing the Module + +First, import the `ListModule` into your Angular module: +```Typescript +import { ListModule } from '@your-namespace/ngx-list'; + +@NgModule({ + declarations: [...], + imports: [ + ListModule, + ... + ], + providers: [], + bootstrap: [...] +}) +export class AppModule { } +``` +### Basic Example + +Here’s a basic example of how to use the `ngx-list` component: +```Typescript + + +
+ {{ item.name }} +
+
+
+``` +### Pull to Refresh + +The `ngx-list` component automatically supports pull to refresh. Simply swipe down at the top of the list to refresh the content. + +### Load More Button + +When there are more items to load, a "Load More" button will appear at the bottom of the list: +```Typescript + + +
+ {{ item.name }} +
+
+
+``` +### Inputs + +- **items** (`any[]`): The array of items to be displayed in the list. +- **limit** (`number`): The initial limit on the number of items to display (default: 100). +- **step** (`number`): The number of items to load each time more items are requested (default: 100). + +### Methods + +- **loadMore()**: Manually loads more items into the list. +- **refresh()**: Refreshes the list by resetting the limit and optionally reloading the items. + +### SCSS Customization + +The component supports CSS variables for easy customization. Below are some of the customizable variables: + +- `--refresh-bg`: Background color for the pull-to-refresh message (default: `#f0f0f0`). +- `--refresh-color`: Text color for the pull-to-refresh message (default: `#666`). +- `--load-more-bg`: Background color for the load-more button (default: `#007bff`). +- `--load-more-bg-hover`: Background color for the load-more button on hover (default: `#0056b3`). + +### Example of Custom CSS Variables + +You can customize the styles using CSS variables in your global styles or component-specific styles: +```css +:root { + --refresh-bg: #e0e0e0; + --refresh-color: #444; + --load-more-bg: #28a745; + --load-more-bg-hover: #218838; +} +``` +## Contributing + +Feel free to contribute to this project by opening issues or submitting pull requests. Make sure to follow the contribution guidelines. + +## License + +This project is licensed under the MIT License. diff --git a/src/app/core/modules/list/list.component.html b/src/app/core/modules/list/list.component.html new file mode 100644 index 0000000..08e1dc0 --- /dev/null +++ b/src/app/core/modules/list/list.component.html @@ -0,0 +1,15 @@ +
+
+ Pull to refresh... +
+ +
+ +
+ + +
diff --git a/src/app/core/modules/list/list.component.scss b/src/app/core/modules/list/list.component.scss new file mode 100644 index 0000000..ebf7c35 --- /dev/null +++ b/src/app/core/modules/list/list.component.scss @@ -0,0 +1,32 @@ +.scroll-box { + position: relative; + max-height: 400px; + overflow-y: auto; + padding: 10px; + + .pull-to-refresh { + text-align: center; + padding: 10px; + background-color: var(--refresh-bg, #f0f0f0); + color: var(--refresh-color, #666); + font-size: 14px; + } +} + +.load-more { + display: block; + width: 100%; + padding: 10px 0; + background-color: var(--load-more-bg, #007bff); + color: #fff; + border: none; + border-radius: 4px; + text-align: center; + cursor: pointer; + margin-top: 10px; + transition: background-color 0.3s ease; + + &:hover { + background-color: var(--load-more-bg-hover, #0056b3); + } +} diff --git a/src/app/core/modules/list/list.component.ts b/src/app/core/modules/list/list.component.ts new file mode 100644 index 0000000..3bf257c --- /dev/null +++ b/src/app/core/modules/list/list.component.ts @@ -0,0 +1,122 @@ +import { + Component, + ContentChild, + ElementRef, + Input, + ViewChild, + HostListener, + OnInit +} from '@angular/core'; +import { ItemDirective } from './list.directive'; + +/** + * The ListComponent is responsible for displaying a list of items with features + * like infinite scroll, pull to refresh, and loading more items on button click. + */ +@Component({ + selector: 'wlist', + templateUrl: './list.component.html', + styleUrls: ['./list.component.scss'] +}) +export class ListComponent implements OnInit { + @ContentChild(ItemDirective, { static: false }) action: any; + + @ViewChild('container') container: ElementRef; + + /** + * The array of items to be displayed in the list. + */ + @Input() items: any[] = []; + + /** + * The initial limit on the number of items to display. + */ + @Input() limit = 100; + + /** + * The number of items to load each time more items are requested. + */ + @Input() step = 100; + + /** + * Indicates whether the user is pulling to refresh. + */ + isPulling = false; + + /** + * Indicates whether more items can be loaded. + */ + get canLoadMore(): boolean { + return this.limit < this.items.length; + } + + private _itemHeight: number; + private _devide = 0.5; + + ngOnInit(): void { + // Initialize if needed + } + + /** + * Handles the scroll event for infinite scrolling. + */ + onScroll($event: Event): void { + if (!this.container) return; + + const ele = this.container.nativeElement; + + if (!this._itemHeight && ele.children.length) { + this._itemHeight = ele.children[0].clientHeight; + } + + if (!this._itemHeight) return; + + if ( + ele.scrollTop > this._itemHeight * this.limit * this._devide && + this.limit < this.items.length + ) { + this.loadMore(); + + if (this._devide < 0.8) { + this._devide += 0.2; + } + } + } + + /** + * Loads more items into the view. + */ + loadMore(): void { + this.limit += this.step; + } + + /** + * Handles the "pull to refresh" functionality. + */ + @HostListener('window:touchmove', ['$event']) + onTouchMove($event: TouchEvent): void { + const ele = this.container.nativeElement; + + if (ele.scrollTop === 0 && $event.touches[0].clientY > 50) { + this.isPulling = true; + } else { + this.isPulling = false; + } + } + + @HostListener('window:touchend') + onTouchEnd(): void { + if (this.isPulling) { + this.refresh(); + this.isPulling = false; + } + } + + /** + * Refreshes the list by reloading items. + */ + refresh(): void { + this.limit = this.step; + // Optionally, add logic to refresh the list from the backend + } +} diff --git a/src/app/core/modules/list/list.directive.ts b/src/app/core/modules/list/list.directive.ts new file mode 100644 index 0000000..523ddeb --- /dev/null +++ b/src/app/core/modules/list/list.directive.ts @@ -0,0 +1,8 @@ +import { Directive, TemplateRef } from '@angular/core'; + +@Directive({ + selector: 'ng-template[item]' +}) +export class ItemDirective { + constructor(public template: TemplateRef) {} +} diff --git a/src/app/core/modules/list/list.module.ts b/src/app/core/modules/list/list.module.ts new file mode 100644 index 0000000..a4b0175 --- /dev/null +++ b/src/app/core/modules/list/list.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { CoreModule } from 'src/app/core/core.module'; +import { ListComponent } from './list.component'; +import { ItemDirective } from './list.directive'; + +@NgModule({ + imports: [CoreModule], + declarations: [ItemDirective, ListComponent], + exports: [ItemDirective, ListComponent], + providers: [] +}) +export class ListModule {} diff --git a/src/app/core/modules/list/module.json b/src/app/core/modules/list/module.json new file mode 100644 index 0000000..ca39c25 --- /dev/null +++ b/src/app/core/modules/list/module.json @@ -0,0 +1,3 @@ +{ + "repo": "git@github.com:WebArtWork/ngx-list.git" +} diff --git a/src/app/core/modules/select/.gitignore b/src/app/core/modules/select/.gitignore new file mode 100644 index 0000000..6704566 --- /dev/null +++ b/src/app/core/modules/select/.gitignore @@ -0,0 +1,104 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/src/app/core/modules/select/LICENSE b/src/app/core/modules/select/LICENSE new file mode 100644 index 0000000..1125219 --- /dev/null +++ b/src/app/core/modules/select/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app/core/modules/select/README.md b/src/app/core/modules/select/README.md new file mode 100644 index 0000000..fa8863e --- /dev/null +++ b/src/app/core/modules/select/README.md @@ -0,0 +1,121 @@ +# Ngx Select Component + +The `ngx-select` component is an Angular component designed to provide a customizable select dropdown, supporting features like multiple selections, search, and custom templates for both the view and items. + +## Features + +- Single and multiple item selection. +- Customizable via templates for header and items. +- Optional search functionality. +- Clearable selection. +- Easy styling with CSS variables. + +## Installation + +To install the module, use the following command: +```cmd +waw add ngx-select +``` +## Usage + +### Importing the Module + +First, import the `SelectModule` into your Angular module: +```Typescript +import { SelectModule } from '@your-namespace/ngx-select'; + +@NgModule({ + declarations: [...], + imports: [ + SelectModule, + ... + ], + providers: [], + bootstrap: [...] +}) +export class AppModule { } +``` +### Basic Example + +Here’s a basic example of how to use the `ngx-select` component: +```Typescript + + +``` +### Custom Templates + +You can use custom templates for the view and items: +```Typescript + + + +
Custom View Here
+
+ + +
{{ item.name }}
+
+
+``` +### Inputs + +- **placeholder** (`string`): Placeholder text for the select input. +- **items** (`any[]`): List of items to display in the dropdown. +- **disabled** (`boolean`): Whether the select input is disabled. +- **clearable** (`boolean`): Whether the select input is clearable. +- **name** (`string`): The name of the property to display in the dropdown items. +- **value** (`string`): The property used as the value for each item. +- **multiple** (`boolean`): Whether multiple items can be selected. +- **label** (`string`): The label for the select input. +- **searchable** (`boolean`): Whether the dropdown is searchable. +- **searchableBy** (`string`): The property by which to search items. +- **select** (`any`): The selected value(s). +- **view** (`TemplateRef`): Custom template for the view (header) of the select input. +- **item** (`TemplateRef`): Custom template for each item in the dropdown. +- **search** (`TemplateRef`): Custom template for the search input. + +### Outputs + +- **modelChange** (`EventEmitter`): Event emitted when the selected values change. + +### SCSS Customization + +The component supports CSS variables for easy customization. Below are some of the customizable variables: + +- `--c-sky`: Default color for the select border when active (default: `#3498db`). +- `--c-text`: Default text color (default: `#333333`). +- `--c-border`: Default border color (default: `#e5e5e5`). +- `--c-shadow`: Default shadow color (default: `#f3f3f3`). +- `--c-white`: Default background color (default: `#ffffff`). + +### Example of Custom CSS Variables + +You can customize the styles using CSS variables in your global styles or component-specific styles: +```css +:root { + --c-sky: #3498db; + --c-text: #333; + --c-border: #e5e5e5; + --c-shadow: #f3f3f3; + --c-white: #ffffff; +} +``` +## Contributing + +Feel free to contribute to this project by opening issues or submitting pull requests. Make sure to follow the contribution guidelines. + +## License + +This project is licensed under the MIT License. diff --git a/src/app/core/modules/select/module.json b/src/app/core/modules/select/module.json new file mode 100644 index 0000000..b2ebf30 --- /dev/null +++ b/src/app/core/modules/select/module.json @@ -0,0 +1,3 @@ +{ + "repo" : "git@github.com:WebArtWork/ngx-select.git" +} diff --git a/src/app/core/modules/select/select.component.html b/src/app/core/modules/select/select.component.html new file mode 100644 index 0000000..46b29b8 --- /dev/null +++ b/src/app/core/modules/select/select.component.html @@ -0,0 +1,165 @@ +
+ +
{{ label }}
+ + +
+ +
+ + + + + + + + + + + + + + + +
+
+
{{ placeholder }}
+ + , + {{ _items[id][name] }} + close + + +
+
+ {{ _selected || placeholder }} +
+
+
+
+ + +
+ close +
+ + +
+ + + +
+ + +
+ +
+ + + + +
+ + + + + +
+
+ {{ item[name] }} +
+
+
+
+
+
diff --git a/src/app/core/modules/select/select.component.scss b/src/app/core/modules/select/select.component.scss new file mode 100644 index 0000000..c7348f0 --- /dev/null +++ b/src/app/core/modules/select/select.component.scss @@ -0,0 +1,236 @@ +:host { + display: block; +} + +// waw-select styles +.w-select { + width: 100%; + &__label { + margin-bottom: 5px; + } + &__body { + position: relative; + cursor: pointer; + display: flex; + min-height: 50px; + height: 50px; + align-items: center; + border: 2px solid var(--c-text-primary); + border-radius: 12px; + transition: var(--transition); + //background: var(--c-bg-secondary); + &._active { + border-color: var(--c-primary); + } + } + &__header { + padding-left: 15px; + display: flex; + align-items: center; + width: 100%; + overflow: hidden; + white-space: nowrap; + padding: 14px 10px 14px 40px; + position: relative; + svg { + position: absolute; + left: 10px; + top: 50%; + transform: translateY(-50%); + path{ + fill:var(--c-primary); + } + } + } + &__text { + margin-right: 10px; + flex-grow: 1; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + .text-overflow { + overflow: hidden; + text-overflow: ellipsis; + word-break: keep-all; + color: var(--c-text-primary); + } + } + &__arrow { + margin-right: 15px; + transition: var(--transition); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + svg{ + width: 12px; + height: 12px; + path{ + fill: var(--c-text-primary); + } + } + &._active { + transform: rotate(180deg); + } + } + .item { + padding: 10px; + transition: var(--transition); + border-bottom: 1px solid var(--c-text-primary); + &:hover { + background: var(--c-shadow); + border-bottom: 1px solid var(--c-primary); + color: var(--c-primary); + } + } + &__popup { + z-index: 9; + width: 100%; + left: 0; + position: absolute; + top: calc(100% + 10px); + background: var(--c-white); + box-shadow: 0px 0px 4px var(--c-border); + border-radius: 10px; + border: 2px solid var(--c-primary); + background: var(--c-bg-secondary); + color: var(--c-text-primary); + padding-bottom: 15px; + padding-top: 15px; + &._search { + padding-top: 60px; + } + .popup-block { + max-height: 180px; + overflow-y: auto; + padding: 0 15px; + margin-right: 10px; + &__empty-search { + padding: 15px; + text-align: center; + color: var(--c-text-primary); + } + } + } + &__search { + top: 10px; + position: absolute; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + left: 0; + padding: 0 15px; + .search-input { + outline: none; + width: 100%; + cursor: pointer; + display: flex; + padding: 10px; + padding-right: 30px; + align-items: center; + border: 1px solid var(--c-border); + border-radius: 10px; + transition: var(--transition); + } + .search-icon { + position: absolute; + top: 50%; + right: 25px; + transform: translateY(-50%); + } + } + // scroll styles + *::-webkit-scrollbar { + width: 5px; + height: 5px; + background-color: var(--c-white); + } + * ::-webkit-scrollbar-thumb { + border-radius: 0; + background-color: var(--c-border); + } + + // checkbox styles + .checkbox { + &__body { + display: inline-flex; + user-select: none; + cursor: pointer; + padding: 6px 8px; + color: var(--c-text); + border-radius: 6px; + overflow: hidden; + transition: var(--transition); + &:not(:last-child) { + margin-right: 6px; + } + &:hover { + background: rgba(var(--c-sky), 0.09); + } + &:hover .checkbox__svg { + border-color: var(--c-sky); + } + } + &__input { + display: none; + &:checked + .checkbox__body .checkbox__svg { + background: var(--c-sky); + border-color: var(--c-sky); + animation: wave 0.4s ease; + } + &:checked + .checkbox__body .checkbox__svg svg { + stroke-dashoffset: 0; + } + } + &__svg { + position: relative; + min-width: 18px; + min-height: 18px; + width: 18px; + height: 18px; + display: inline-block; + border-radius: 4px; + transform: scale(1); + border: 1px solid var(--c-border); + transition: var(--transition); + box-shadow: 0 1px 1px var(--c-shadow); + } + &__svg svg { + position: absolute; + top: 3px; + left: 2px; + fill: none; + stroke: var(--c-white); + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; + stroke-dasharray: 16px; + stroke-dashoffset: 16px; + transition: all 0.3s ease; + transition-delay: 0.1s; + transform: translate3d(0, 0, 0); + } + &__text { + padding-left: 8px; + line-height: 18px; + text-overflow: ellipsis; + overflow: hidden; + } + &__svg-icon { + position: absolute; + width: 0; + height: 0; + pointer-events: none; + user-select: none; + } + @keyframes wave { + 50% { + transform: scale(0.9); + } + } + } +} +.selected { + font-weight: bold; +} \ No newline at end of file diff --git a/src/app/core/modules/select/select.component.ts b/src/app/core/modules/select/select.component.ts new file mode 100644 index 0000000..98dcfac --- /dev/null +++ b/src/app/core/modules/select/select.component.ts @@ -0,0 +1,165 @@ +import { + Component, + ElementRef, + Input, + TemplateRef, + ViewChild, + Output, + EventEmitter, + OnInit, + OnChanges, + SimpleChanges +} from '@angular/core'; + +/** + * The SelectComponent is a customizable select dropdown component that supports + * single or multiple selections, search, and custom templates for both the view + * and items. + */ +@Component({ + selector: 'wselect', + templateUrl: './select.component.html', + styleUrls: ['./select.component.scss'] +}) +export class SelectComponent implements OnInit, OnChanges { + /** Placeholder text for the select input. */ + @Input() placeholder = ''; + + /** List of items to display in the dropdown. */ + @Input() items: any = []; + + _items: any = {}; + + /** Whether the select input is disabled. */ + @Input() disabled = false; + + /** Whether the select input is clearable. */ + @Input() clearable = false; + + /** Clears the selected values. */ + clear(): void { + if (this.multiple) { + this._values = []; + + this.modelChange.emit(this._values); + } else { + this._selected = ''; + + this.modelChange.emit(''); + } + } + + /** The name of the property to display in the dropdown items. */ + @Input() name = 'name'; + + /** The property used as the value for each item. */ + @Input() value = '_id'; + + /** Whether multiple items can be selected. */ + @Input() multiple = false; + + /** The label for the select input. */ + @Input() label = ''; + + /** Whether the dropdown is searchable. */ + @Input() searchable = false; + + /** The property by which to search items. */ + @Input() searchableBy = 'name'; + + /** Event emitted when the selected values change. */ + @Output() modelChange = new EventEmitter(); + + _values: any = []; + + _names: any = []; + + _selected: string; + + selectShow: any; + + /** The selected value(s). */ + @Input() select: any; + + /** Custom template for the view (header) of the select input. */ + @Input('view') t_view: TemplateRef; + + /** Custom template for each item in the dropdown. */ + @Input('item') t_item: TemplateRef; + + /** Custom template for the search input. */ + @Input('search') t_search: TemplateRef; + + search = ''; + + @ViewChild('e_search', { static: false }) e_search: ElementRef; + + ngOnInit(): void { + for (let i = 0; i < this.items.length; i++) { + if (typeof this.items[i] === 'string') { + this.items[i] = { + name: this.items[i] + }; + this.items[i][this.value] = this.items[i].name; + } + this._items[this.items[i][this.value]] = this.items[i]; + } + + if (this.multiple) { + this._values = this.select || []; + } else { + this._selected = this._items[this.select] + ? this._items[this.select][this.name] + : this.select; + } + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['select'] && !changes['select'].firstChange) { + this.ngOnInit(); + } + } + + /** Handles click events on items. */ + item_onclick(item: any): void { + if (this.multiple) { + if (this._values.indexOf(item[this.value]) !== -1) { + this._values.splice(this._values.indexOf(item[this.value]), 1); + } else { + this._values.push(item[this.value]); + } + + if (this._names.indexOf(item[this.name]) !== -1) { + this._names.splice(this._names.indexOf(item[this.name]), 1); + } else { + this._names.push(item[this.name]); + } + + this._selected = + this._names.length == 0 + ? this.placeholder + : this._names.join(', '); + + this.modelChange.emit(this._values); + } else { + this._selected = item[this.name]; + + this.selectShow = false; + + this.modelChange.emit(item[this.value]); + } + } + + /** Focuses the search input when the dropdown is opened. */ + focus_search(): void { + this.search = ''; + + if (!this.searchable || this.t_search) return; + + if (this.e_search) { + this.e_search.nativeElement.focus(); + } else { + setTimeout(this.focus_search.bind(this), 100); + } + } +} diff --git a/src/app/core/modules/select/select.module.ts b/src/app/core/modules/select/select.module.ts new file mode 100644 index 0000000..db24cc8 --- /dev/null +++ b/src/app/core/modules/select/select.module.ts @@ -0,0 +1,13 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { WacomModule } from 'wacom'; +import { SelectComponent } from './select.component'; + +@NgModule({ + imports: [FormsModule, CommonModule, WacomModule], + declarations: [SelectComponent], + providers: [], + exports: [SelectComponent] +}) +export class SelectModule {} diff --git a/src/app/core/modules/table/README.md b/src/app/core/modules/table/README.md new file mode 100644 index 0000000..35f0b17 --- /dev/null +++ b/src/app/core/modules/table/README.md @@ -0,0 +1,77 @@ +# ngx-table + +`ngx-table` is an Angular component for creating customizable and responsive tables with features like sorting, pagination, search, and action buttons. + +## Installation + +To install the module, run: +```cmd +waw add ngx-table +``` +## Usage + +### Basic Usage + +To use `ngx-table`, first import the module in your Angular application: +```Typescript +import { TableModule } from 'ngx-table'; + +@NgModule({ + imports: [TableModule], +}) +export class AppModule {} +``` +### Component Inputs + +- `title`: The title of the table. +- `columns`: Array of column definitions with properties `title` and `field`. +- `rows`: Array of data rows to display in the table. +- `config`: Configuration object for the table with options like `perPage`, `pageSizeOptions`, `searchable`, etc. + +### Example +```Typescript + +``` +### Configuration + +- `pageSizeOptions`: Array of numbers for items per page options. +- `perPage`: Number of items to show per page (-1 for all). +- `page`: Current page number. +- `searchable`: Boolean, whether to enable search functionality. +- `create`: Function to execute when the "Add New" button is clicked. + +### Custom Templates + +`ngx-table` allows you to use custom templates for cells and actions: +```Typescript + + {{ row.email }} + + + + + + + +
+
+ +
+
+ + +
+
+
+``` + +### Styling + +Customize the appearance of the table using the available CSS variables. + +## License + +MIT License. See LICENSE file for details. diff --git a/src/app/core/modules/table/module.json b/src/app/core/modules/table/module.json new file mode 100644 index 0000000..c0805da --- /dev/null +++ b/src/app/core/modules/table/module.json @@ -0,0 +1,6 @@ +{ + "repo" : "git@github.com:WebArtWork/ngx-table.git", + "modules": { + "button": "*" + } +} diff --git a/src/app/core/modules/table/per-page.pipe.ts b/src/app/core/modules/table/per-page.pipe.ts new file mode 100644 index 0000000..8a94b17 --- /dev/null +++ b/src/app/core/modules/table/per-page.pipe.ts @@ -0,0 +1,49 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'perPage' +}) +export class PerPagePipe implements PipeTransform { + /** + * Transforms an array of data by paginating and sorting it according to the provided configuration. + * @param arr - The array of data to be paginated and sorted. + * @param config - The configuration object containing pagination and sorting settings. + * @param sort - The sorting object specifying the column to sort by and the direction. + * @param reload - An optional parameter to force reloading of the data (not used here). + * @returns The paginated and sorted array. + */ + transform(arr: any[], config: any, sort: any, reload?: string): any[] { + // If the input is not an array, return an empty array + if (!Array.isArray(arr)) return []; + + // If perPage is set to -1, return the entire array (no pagination) + if (config.perPage === -1) return arr; + + // Clone the array to avoid mutating the original data + arr = arr.slice(); + + // Add a sequential number (num) to each item for easy reference + for (let i = 0; i < arr.length; i++) { + arr[i].num = i + 1; + } + + // Sort the array if a sorting direction is provided + if (sort.direction) { + arr.sort((a: any, b: any) => { + if (a[sort.title] < b[sort.title]) { + return sort.direction == 'desc' ? 1 : -1; + } + if (a[sort.title] > b[sort.title]) { + return sort.direction == 'desc' ? -1 : 1; + } + return 0; + }); + } + + // Paginate the array by slicing it according to the current page and items per page + return arr.slice( + (config.page - 1) * config.perPage, + config.page * config.perPage + ); + } +} diff --git a/src/app/core/modules/table/table.component.html b/src/app/core/modules/table/table.component.html new file mode 100644 index 0000000..ae93c4e --- /dev/null +++ b/src/app/core/modules/table/table.component.html @@ -0,0 +1,341 @@ +
+
+ +

{{ title }}

+ + + +
+ + search + +
+ + + + + + + {{ button.icon }} + + {{ button.text }} + + + + + + + + Add new + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Showing items per page
+
+
+ {{ config.perPage === -1 ? 'All' : config.perPage }} +
+
+
+
+ {{ pageSize }} +
+
+
+
+ All +
+
+
+
+
+ Page {{ config.page }} +
+
+ {{ ((config.page - 1) * config.perPage) + 1 }} - {{ + config.page * config.perPage > rows?.length && + rows?.length || config.page * config.perPage }} + of + {{ (rows | search: searching_text: (config.searchBy || + 'title'))?.length }} +
+
+ + + + + +
No. +
+ {{ column.title }} + + keyboard_backspace + +
+
+ + + + Actions + +
{{ row.num }} + {{ row[column.field] }} + + + +
+ + + + + + {{ button.icon }} + + + + {{ button.icon }} + + + + + {{ button.icon }} + + + + + {{ button.icon }} + + + + + {{ button.icon }} + + + + + + + + + edit + + + delete_outline + +
+
+
diff --git a/src/app/core/modules/table/table.component.scss b/src/app/core/modules/table/table.component.scss new file mode 100644 index 0000000..bfe829b --- /dev/null +++ b/src/app/core/modules/table/table.component.scss @@ -0,0 +1,475 @@ +@import 'angular'; + +.wtable { + background: var(--c-bg-secondary); + box-shadow: var(--c-shadow); + border-radius: 10px; + padding-bottom: 70px; + max-width: 100%; + height: auto; + margin: 0px auto; + position: relative; + + @media (max-width: 991px) { + padding-left: 10px; + padding-right: 10px; + } + + @media screen and (max-width: 599px) { + padding-bottom: 20px; + } + + .table { + border-collapse: collapse; + margin: 0; + padding: 0; + width: 100%; + table-layout: auto; + + &-plus-btn { + cursor: pointer; + font-size: 16px; + font-weight: 500; + border: 0; + display: flex; + justify-content: center; + align-items: center; + min-width: 140px; + height: 45px; + border-radius: 4px; + padding: 5px 12px; + background-color: var(--c-primary); + color: var(--c-primary); + border: 1px solid var(--c-primary); + &:hover { + box-shadow: 0 0 3px 0px var(--c-primary); + background-color: var(--c-primary); + //color: var(--c-bg-secondary); + } + span { + margin-left: 5px; + @media screen and (max-width: 599px) { + display: none; + } + } + @media screen and (max-width: 599px) { + position: absolute; + right: 15px; + min-width: 45px; + top: 15px; + } + } + + // search + &-search { + position: relative; + display: flex; + flex-grow: 1; + margin: 0 30px; + &--active { + .table-search__input { + opacity: 1; + } + } + + &__input { + width: 100%; + height: 45px; + border-radius: 4px; + padding: 0 10px; + color: inherit; + background: var(--c-bg-secondary); + border: 1px solid var(--c-primary); + + &:focus { + border: 2px solid var(--c-primary); + } + } + + &__icon { + width: 40px; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + z-index: 4; + cursor: pointer; + } + + &__icon-mobile { + display: none; + margin-left: auto; + margin-right: 130px; + } + + @media (max-width: 599px) { + display: none; + + &.table-search--active { + display: block; + position: absolute; + margin: 0; + width: 100%; + z-index: 2; + } + + &.table-search--active + .table-plus-btn { + display: none; + } + + &.table-search--active + .w-forms__title { + display: none; + } + + &__icon-mobile { + display: inherit; + } + } + } + + .table-header__sort { + position: relative; + cursor: pointer; + .icon-arrow { + transform: rotate(90deg); + font-size: var(--fs); + position: absolute; + top: 3px; + cursor: pointer; + } + } + + th { + position: relative; + padding: 0 16px; + height: 48px; + text-align: left; + font-weight: 500; + font-size: calc(var(--fs) - 2px); + font-size: var(--fs); + line-height: calc(var(--fs) + 8px); + letter-spacing: var(--letter-spacing); + text-transform: capitalize; + color: var(--c-text-primary); + border-bottom: 1px solid var(--c-border); + overflow: hidden; + text-overflow: ellipsis; + .icon-arrow { + opacity: 0; + transition: 0.3s all ease-in-out; + } + &:hover { + .icon-arrow { + opacity: 1; + transition: 0.3s all ease-in-out; + } + } + .table-header__sort._sortActiveDown { + .icon-arrow { + transform: rotate(-90deg); + opacity: 1; + } + } + .table-header__sort._sortActiveUp { + .icon-arrow { + opacity: 1; + } + } + @media all and (max-width: 991.9px) { + display: none; + text-align: left; + } + &:last-child { + width: 140px; + } + } + + td { + cursor: pointer; + padding: 5px 16px; + height: 60px; + text-align: left; + vertical-align: middle; + font-size: calc(var(--fs) - 2px); + line-height: calc(var(--fs) + 8px); + letter-spacing: var(--letter-spacing); + color: var(--c-text-primary); + word-break: break-word; + display: table-cell; + border-bottom: 1px solid var(--c-border); + @media all and (max-width: 991.9px) { + display: flex; + align-items: center; + justify-content: space-between; + column-gap: 5px; + border-bottom: 0; + border: 2px solid var(--c-border); + height: auto; + min-height: 60px; + } + &:before { + content: attr(data-label); + word-break: keep-all; + display: inline-block; + font-weight: 500; + font-size: var(--fs); + line-height: calc(var(--fs) + 8px); + letter-spacing: var(--letter-spacing); + text-transform: capitalize; + color: var(--c-text-primary); + text-overflow: ellipsis; + @media (min-width: 992px) { + display: none; + } + } + } + + tr { + &:last-child { + td { + border-bottom: none; + @media (max-width: 991.9px) { + border-bottom: 2px solid var(--c-border); + } + } + } + td { + &:last-child { + border-right: none; + @media (max-width: 992px) { + border-right: 2px solid var(--c-border); + } + } + &:first-child { + @media (max-width: 992px) { + margin-top: 20px; + } + } + } + th { + &:last-child { + border-right: none; + } + } + } + + .table__actions { + display: flex; + gap: 6px; + + a { + i { + color: var(--c-text-primary); + } + } + } + + .table-body { + &__last-td { + @media (max-width: 991.9px) { + margin-bottom: 20px; + border-bottom: 3px solid var(--c-border); + } + + i { + font-size: 22px; + width: 22px; + &:hover { + color: var(--c-primary); + } + } + } + } + + &-footer { + height: 65px; + display: flex; + gap: 120px; + position: absolute; + width: 100%; + left: 0; + bottom: 0; + padding: 0 8px 0 15px; + align-items: center; + justify-content: space-between; + @media screen and (max-width: 599px) { + height: 90px; + padding: 10px 20px; + flex-direction: column; + position: static; + gap: 20px; + } + + &__pagination { + display: flex; + align-items: center; + position: relative; + bottom: 15px; + + @media (max-width: 599px) { + bottom: 0; + left: 5px; + } + } + + &__arrow { + border: 0; + background: none; + width: 30px; + height: 30px; + margin-right: 30px; + cursor: pointer; + + .chevron { + position: relative; + display: block; + min-width: 22px; + min-height: 22px; + border: 2px solid transparent; + border-radius: 100px; + &::before { + position: absolute; + width: 2px; + height: 90%; + background-color: var(--c-grey); + mix-blend-mode: overlay; + top: 8%; + } + &::after { + content: ''; + display: block; + box-sizing: border-box; + position: absolute; + width: 10px; + height: 10px; + border-bottom: 2px solid var(--c-grey); + border-right: 2px solid var(--c-grey); + mix-blend-mode: overlay; + transform: rotate(135deg); + left: 2px; + top: 2px; + } + } + + &:disabled { + i::after { + border-color: #9f9f9f; + } + i::before { + background: #9f9f9f; + } + } + + &._start { + .chevron { + position: relative; + left: 1px; + } + + .chevron::after { + left: 8px; + top: 4px; + } + .chevron::before { + display: block; + left: 2px; + content: ''; + } + } + &._left { + .chevron { + position: relative; + left: 4px; + } + + .chevron::after { + top: 4px; + } + } + &._right { + .chevron::after { + transform: rotate(315deg); + top: 4px; + } + } + &._end { + .chevron { + position: relative; + left: 2px; + } + + .chevron::after { + left: -3px; + top: 4px; + transform: rotate(315deg); + } + .chevron::before { + display: block; + left: 11px; + content: ''; + } + } + } + + .item-page { + font-size: 12px; + color: #9f9f9f; + letter-spacing: 1px; + display: flex; + align-items: center; + + &__dropdown { + position: relative; + margin: 0 10px; + font-weight: bold; + .caption { + background-color: transparent; + padding: 11px 24px; + border-radius: 4px; + border: 1px solid var(--c-border); + cursor: pointer; + &:hover { + background-color: var(--c-primary); + color: var(--c-bg-secondary); + } + } + .list { + position: absolute; + background-color: var(--c-bg-secondary); + width: 100%; + bottom: 100%; + flex-direction: column; + border-radius: 4px 4px 0 0; + display: none; + z-index: 999; + .item { + > div { + padding: 11px 20px; + cursor: pointer; + text-align: center; + } + &:hover { + background-color: var(--c-primary); + color: var(--c-bg-secondary); + } + } + .item.selected { + font-weight: bold; + } + } + &.open { + .caption { + border-radius: 0 0 4px 4px; + } + .list { + display: flex; + flex-direction: column-reverse; + border: 1px solid var(--c-border); + border-bottom: 0; + } + } + } + } + } + } +} diff --git a/src/app/core/modules/table/table.component.ts b/src/app/core/modules/table/table.component.ts new file mode 100644 index 0000000..3ddc258 --- /dev/null +++ b/src/app/core/modules/table/table.component.ts @@ -0,0 +1,275 @@ +import { + Component, + Input, + ContentChildren, + OnInit, + Output, + QueryList, + AfterContentInit, + EventEmitter, + ContentChild +} from '@angular/core'; +import { + CellDirective, + SortDirective, + ActionsDirective, + CustomEditDirective +} from './table.directive'; +import { Router } from '@angular/router'; +import { StoreService } from 'wacom'; + +/** + * TableComponent is a reusable component for displaying data in a table format with + * features like sorting, pagination, search, and custom action buttons. + */ +@Component({ + selector: 'wtable', + templateUrl: './table.component.html', + styleUrls: ['./table.component.scss'] +}) +export class TableComponent implements OnInit, AfterContentInit { + constructor(private _router: Router, private _store: StoreService) {} + + /** A unique ID for the table based on the current route. */ + tableId = + 'table_' + + this._router.url + .split('/') + .filter((p) => p && p.length !== 24) + .join('/'); + + /** Configuration object for the table. */ + @Input() config: any = {}; + + /** List of columns to display in the table. */ + @Input() columns: any = []; + + /** List of rows (data) to display in the table. */ + @Input() rows: any = []; + + /** The value field used as the key for each row. */ + @Input() value = '_id'; + + /** Title of the table. */ + @Input() title = ''; + + /** Directives for custom cell templates. */ + @ContentChildren(CellDirective) cell: QueryList; + + /** Directives for sortable columns. */ + @ContentChildren(SortDirective) sortHeaders: QueryList; + + /** Directive for custom action buttons. */ + @ContentChild(ActionsDirective, { static: false }) action: any; + + /** Directive for custom edit form. */ + @ContentChild(CustomEditDirective, { static: false }) editForm: any; + + /** Current timestamp to force table refresh. */ + now = Date.now(); + + /** Whether the search input is visible. */ + searchShow = false; + + /** Text entered in the search input. */ + searching_text = ''; + + /** Filter for search functionality. */ + filter_filter = ''; + + /** Event emitted when a search is performed. */ + @Output() onSearch = new EventEmitter(); + + private _search_timeout: any; + + /** Custom cell templates keyed by column field. */ + custom_cell: any = {}; + + /** Object containing the sort state for each column. */ + sort_type: any = {}; + + /** Object containing the sortable state for each column. */ + sortable: any = {}; + + ngOnInit(): void { + this.default_config(); + + // Initialize columns + for (let i = 0; i < this.columns.length; i++) { + if (typeof this.columns[i] === 'string') { + this.columns[i] = { + title: this.columns[i], + field: this.columns[i] + }; + } + } + + // Restore the perPage value from the store if available + this._store.get(this.tableId + 'perPage', (perPage) => { + if (perPage) { + this.changePerPage(Number(perPage)); + } + }); + } + + /** Sets the default configuration for the table if not provided. */ + default_config(): void { + if (!this.config.pageSizeOptions) { + this.config.pageSizeOptions = [1, 10, 20, 50]; + } + + if (!this.config.perPage) { + this.config.perPage = -1; + } + + if (!this.config.page) { + this.config.page = 1; + } + + if (!this.config.searchable) { + this.config.searchable = false; + } + + if (typeof this.config.allDocs !== 'boolean') { + this.config.allDocs = true; + } + } + + ngAfterContentInit(): void { + // Initialize sortable headers + for (let i = 0; i < this.sortHeaders.toArray().length; i++) { + this.sortable[this.sortHeaders.toArray()[i].cell] = true; + } + + // Initialize custom cells + for (let i = 0; i < this.cell.toArray().length; i++) { + const cell = this.cell.toArray()[i]; + this.custom_cell[cell.cell] = cell.template; + } + + // Refresh the table periodically + const interval = setInterval(() => { + this.refresh(); + }, 1000); + setTimeout(() => { + clearInterval(interval); + }, 20000); + } + + /** Refreshes the table by updating the current timestamp. */ + refresh() { + this.now = Date.now(); + } + + /** Handles search input changes with a delay. */ + searching() { + setTimeout(() => { + if (!this.config.globalSearch) { + this.filter_filter = this.searching_text; + } + }, 100); + clearTimeout(this._search_timeout); + this._search_timeout = setTimeout(this.searching.bind(this), 2000); + } + + /** Performs a search and emits the search event. */ + search() { + clearTimeout(this._search_timeout); + setTimeout(() => { + if (!this.config.globalSearch) { + this.filter_filter = this.searching_text; + } + + this.refresh(); + }, 100); + this.onSearch.emit(this.searching_text); + } + + /** Whether the page size dropdown is open. */ + select_page_size = false; + + /** Handles the next page action. */ + next(): void { + if ( + typeof this.config.paginate === 'function' || + this.config.page * this.config.perPage < this.rows.length + ) { + this.config.page += 1; + } + + if (typeof this.config.paginate === 'function') { + this.config.paginate(this.config.page); + } + + this.refresh(); + } + + /** Handles the previous page action. */ + previous(): void { + if (this.config.page > 1) { + this.config.page -= 1; + + if (typeof this.config.paginate === 'function') { + this.config.paginate(this.config.page); + } + + this.refresh(); + } + } + + /** Changes the number of items per page. */ + changePerPage(row: any): void { + this.config.perPage = row; + + if (typeof this.config.setPerPage === 'function') { + this.config.setPerPage(this.config.perPage); + } + + this.config.page = 1; + + if (typeof this.config.paginate === 'function') { + this.config.paginate(this.config.page); + } + + this._store.set(this.tableId + 'perPage', row.toString()); + + if ((this.config.page - 1) * this.config.perPage > this.rows.length) { + this.lastPage(); + } + + this.select_page_size = false; + + this.refresh(); + } + + /** Goes to the last page of the table. */ + lastPage(): void { + this.config.page = Math.ceil(this.rows.length / this.config.perPage); + } + + /** Checks if the current page is the last page. */ + isLast(): boolean { + return ( + this.rows && + this.config.page == + Math.ceil(this.rows.length / this.config.perPage) + ); + } + + /** Sorts the table by the specified column. */ + sort(column: any): void { + if (this.sort_type.title != column.title) { + this.sort_type = {}; + } + + if (this.sortable[column.field]) { + this.sort_type = { + title: column.field, + direction: + (typeof this.sort_type.direction != 'string' && 'asc') || + (this.sort_type.direction == 'asc' && 'desc') || + undefined + }; + } + } +} diff --git a/src/app/core/modules/table/table.directive.ts b/src/app/core/modules/table/table.directive.ts new file mode 100644 index 0000000..83f7f1f --- /dev/null +++ b/src/app/core/modules/table/table.directive.ts @@ -0,0 +1,57 @@ +import { Directive, TemplateRef, Input } from '@angular/core'; + +/** + * CellDirective + * + * This directive is used to define a custom template for a specific cell in the table. + * The `cell` input property is used to identify which column the template corresponds to. + */ +@Directive({ + selector: 'ng-template[cell]' +}) +export class CellDirective { + @Input() cell: any; + + constructor(public template: TemplateRef) {} +} + +/** + * SortDirective + * + * The `SortDirective` is used to enable sorting for a particular column in the table. + * The `cell` input property corresponds to the column that should be sortable. + */ +@Directive({ + selector: 'ng-template[sort]' +}) +export class SortDirective { + @Input() cell: any; + + constructor(public template: TemplateRef) {} +} + +/** + * ActionsDirective + * + * The `ActionsDirective` allows you to define a custom template for the actions column in the table. + * This can include buttons or links for editing, deleting, or performing other actions on a row. + */ +@Directive({ + selector: 'ng-template[actions]' +}) +export class ActionsDirective { + constructor(public template: TemplateRef) {} +} + +/** + * CustomEditDirective + * + * The `CustomEditDirective` is used to create a custom form for editing or creating entries within the table. + * This directive enables the flexibility to design your own form layout and functionality. + */ +@Directive({ + selector: 'ng-template[customEdit]' +}) +export class CustomEditDirective { + constructor(public template: TemplateRef) {} +} diff --git a/src/app/core/modules/table/table.module.ts b/src/app/core/modules/table/table.module.ts new file mode 100644 index 0000000..ac1243a --- /dev/null +++ b/src/app/core/modules/table/table.module.ts @@ -0,0 +1,45 @@ +import { TableComponent } from './table.component'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { NgModule } from '@angular/core'; +import { WacomModule } from 'wacom'; +import { + ActionsDirective, + CellDirective, + CustomEditDirective, + SortDirective +} from './table.directive'; +import { ButtonModule } from '../button/button.module'; +import { RouterModule } from '@angular/router'; +import { InputModule } from '../input/input.module'; +import { PerPagePipe } from './per-page.pipe'; +import { FormModule } from '../form/form.module'; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + WacomModule, + FormModule, + ButtonModule, + RouterModule, + InputModule + ], + declarations: [ + TableComponent, + CellDirective, + SortDirective, + ActionsDirective, + CustomEditDirective, + PerPagePipe + ], + providers: [], + exports: [ + TableComponent, + CellDirective, + SortDirective, + ActionsDirective, + CustomEditDirective + ] +}) +export class TableModule {} diff --git a/src/app/core/modules/translate/.gitignore b/src/app/core/modules/translate/.gitignore new file mode 100644 index 0000000..6704566 --- /dev/null +++ b/src/app/core/modules/translate/.gitignore @@ -0,0 +1,104 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/src/app/core/modules/translate/LICENSE b/src/app/core/modules/translate/LICENSE new file mode 100644 index 0000000..9598c2a --- /dev/null +++ b/src/app/core/modules/translate/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app/core/modules/translate/README.md b/src/app/core/modules/translate/README.md new file mode 100644 index 0000000..3233734 --- /dev/null +++ b/src/app/core/modules/translate/README.md @@ -0,0 +1,72 @@ +# ngx-translate + +`ngx-translate` is an Angular module designed to provide multilingual support through the use of pipes, directives, and a service for managing translations. + +## Installation + +To install the module, run: +```cmd +waw add ngx-translate +``` +## Usage + +### Importing the Module + +First, import the `TranslateModule` in your Angular application: +```Typescript +import { TranslateModule } from 'ngx-translate'; + +@NgModule({ + imports: [TranslateModule], +}) +export class AppModule {} +``` +### Using the Translate Pipe + +The `translate` pipe can be used in templates to translate keys into their corresponding language strings: +```Typescript +

{{ 'home.title' | translate }}

+``` +### Using the Translate Directive + +The `translate` directive automatically translates the inner content of an element: +```Typescript +

home.title

+``` +### Service: TranslateService + +The `TranslateService` provides methods for managing translations, setting languages, and retrieving translated strings. + +### Example Usage + +To translate a string programmatically, use the `TranslateService`: +```Typescript +import { TranslateService } from 'ngx-translate'; + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html' +}) +export class HomeComponent { + constructor(private translateService: TranslateService) {} + + getTranslatedText() { + return this.translateService.translate('home.title'); + } +} +``` +### Managing Languages + +You can set or switch the current language using the `TranslateService`: +```Typescript +this.translateService.set_language({ code: 'fr', name: 'French', origin: 'French' }); +``` +### Downloading Translations + +You can download all translations as a JSON file: +```Typescript +this.translateService.download_json(); +``` +## License + +MIT License. See LICENSE file for details. diff --git a/src/app/core/modules/translate/languages.ts b/src/app/core/modules/translate/languages.ts new file mode 100644 index 0000000..ab8538b --- /dev/null +++ b/src/app/core/modules/translate/languages.ts @@ -0,0 +1,682 @@ +export const languages = [ + { + name: 'Afrikaans', + origin: 'Afrikaans', + code: 'af' + }, + { + name: 'Albanian', + origin: 'shqiptare', + code: 'sq' + }, + { + name: 'Amharic', + origin: 'አማርኛ', + code: 'am' + }, + { + name: 'Arabic', + origin: 'عربي', + code: 'ar' + }, + { + name: 'Armenian', + origin: 'հայերեն', + code: 'hy' + }, + { + name: 'Assamese', + origin: 'অসমীয়া', + code: 'as' + }, + { + name: 'Aymara', + origin: 'Aymara', + code: 'ay' + }, + { + name: 'Azerbaijani', + origin: 'Azərbaycan', + code: 'az' + }, + { + name: 'Bambara', + origin: "U b'a don", + code: 'bm' + }, + { + name: 'Basque', + origin: 'euskara', + code: 'eu' + }, + { + name: 'Belarusian', + origin: 'беларускі', + code: 'be' + }, + { + name: 'Bengali', + origin: 'বাংলা', + code: 'bn' + }, + { + name: 'Bhojpuri', + origin: 'भोजपुरी', + code: 'bho' + }, + { + name: 'Bosnian', + origin: 'bosanski', + code: 'bs' + }, + { + name: 'Bulgarian', + origin: 'български', + code: 'bg' + }, + { + name: 'Catalan', + origin: 'català', + code: 'ca' + }, + { + name: 'Cebuano', + origin: 'Cebuano', + code: 'ceb' + }, + { + name: 'Chinese (Simplified)', + origin: '简体中文)', + code: 'zh-CN' + }, + { + name: 'Chinese (Traditional)', + origin: '中國傳統的)', + code: 'zh-TW' + }, + { + name: 'Corsican', + origin: 'Corsu', + code: 'co' + }, + { + name: 'Croatian', + origin: 'Hrvatski', + code: 'hr' + }, + { + name: 'Czech', + origin: 'čeština', + code: 'cs' + }, + { + name: 'Danish', + origin: 'dansk', + code: 'da' + }, + { + name: 'Dhivehi', + origin: 'ދިވެހި', + code: 'dv' + }, + { + name: 'Dogri', + origin: 'डोगरी', + code: 'doi' + }, + { + name: 'Dutch', + origin: 'Nederlands', + code: 'nl' + }, + { + name: 'English', + origin: 'English', + code: 'en' + }, + { + name: 'English (British)', + origin: 'English (British)', + code: 'en-GB' + }, + { + name: 'English (Australian)', + origin: 'English (Australian)', + code: 'en-AU' + }, + { + name: 'Esperanto', + origin: 'Esperanto', + code: 'eo' + }, + { + name: 'Estonian', + origin: 'eesti keel', + code: 'et' + }, + { + name: 'Ewe', + origin: 'Aŋgba', + code: 'ee' + }, + { + name: 'Filipino (Tagalog)', + origin: 'Filipino (Tagalog)', + code: 'fil' + }, + { + name: 'Finnish', + origin: 'Suomalainen', + code: 'fi' + }, + { + name: 'French', + origin: 'Français', + code: 'fr' + }, + { + name: 'Frisian', + origin: 'Frysk', + code: 'fy' + }, + { + name: 'Galician', + origin: 'galego', + code: 'gl' + }, + { + name: 'Georgian', + origin: 'ქართული', + code: 'ka' + }, + { + name: 'German', + origin: 'Deutsch', + code: 'de' + }, + { + name: 'Greek', + origin: 'Ελληνικά', + code: 'el' + }, + { + name: 'Guarani', + origin: 'guarani', + code: 'gn' + }, + { + name: 'Gujarati', + origin: 'ગુજરાતી', + code: 'gu' + }, + { + name: 'Haitian Creole', + origin: 'Kreyòl ayisyen', + code: 'ht' + }, + { + name: 'Hausa', + origin: 'Hausa', + code: 'ha' + }, + { + name: 'Hawaiian', + origin: 'ʻŌlelo Hawaiʻi', + code: 'haw' + }, + { + name: 'Hebrew', + origin: 'עִברִית', + code: 'he' + }, + { + name: 'Hindi', + origin: 'नहीं', + code: 'hi' + }, + { + name: 'Hmong', + origin: 'Hmong', + code: 'hmn' + }, + { + name: 'Hungarian', + origin: 'Magyar', + code: 'hu' + }, + { + name: 'Icelandic', + origin: 'íslenskur', + code: 'is' + }, + { + name: 'Igbo', + origin: 'Igbo', + code: 'ig' + }, + { + name: 'Ilocano', + origin: 'Ilocano', + code: 'ilo' + }, + { + name: 'Indonesian', + origin: 'bahasa Indonesia', + code: 'id' + }, + { + name: 'Irish', + origin: 'Gaeilge', + code: 'ga' + }, + { + name: 'Italian', + origin: 'Italiano', + code: 'it' + }, + { + name: 'Japanese', + origin: '日本', + code: 'ja' + }, + { + name: 'Javanese', + origin: 'basa jawa', + code: 'jv' + }, + { + name: 'Kannada', + origin: 'ಕನ್ನಡ', + code: 'kn' + }, + { + name: 'Kazakh', + origin: 'қазақ', + code: 'kk' + }, + { + name: 'Khmer', + origin: 'ខ្មែរ', + code: 'km' + }, + { + name: 'Kinyarwanda', + origin: 'Kinyarwanda', + code: 'rw' + }, + { + name: 'Konkani', + origin: 'कोंकणी', + code: 'gom' + }, + { + name: 'Korean', + origin: '한국인', + code: 'ko' + }, + { + name: 'Krio', + origin: 'Kryo we de na di wɔl', + code: 'kri' + }, + { + name: 'Kurdish', + origin: 'Kurdî', + code: 'ku' + }, + { + name: 'Kurdish (Sorani)', + origin: 'کوردی (سۆرانی)', + code: 'ckb' + }, + { + name: 'Kyrgyz', + origin: 'Кыргызча', + code: 'ky' + }, + { + name: 'Lao', + origin: 'ແຮງ​ງານ', + code: 'lo' + }, + { + name: 'Latin', + origin: 'Latinus', + code: 'la' + }, + { + name: 'Latvian', + origin: 'latviski', + code: 'lv' + }, + { + name: 'Lingala', + origin: 'Lingala', + code: 'ln' + }, + { + name: 'Lithuanian', + origin: 'lietuvių', + code: 'lt' + }, + { + name: 'Luganda', + origin: 'Luganda', + code: 'lg' + }, + { + name: 'Luxembourgish', + origin: 'lëtzebuergesch', + code: 'lb' + }, + { + name: 'Macedonian', + origin: 'македонски', + code: 'mk' + }, + { + name: 'Maithili', + origin: 'मैथिली', + code: 'mai' + }, + { + name: 'Malagasy', + origin: 'Malagasy', + code: 'mg' + }, + { + name: 'Malay', + origin: 'Melayu', + code: 'ms' + }, + { + name: 'Malayalam', + origin: 'മലയാളം', + code: 'ml' + }, + { + name: 'Maltese', + origin: 'Malti', + code: 'mt' + }, + { + name: 'Maori', + origin: 'Maori', + code: 'mi' + }, + { + name: 'Marathi', + origin: 'मराठी', + code: 'mr' + }, + { + name: 'Meiteilon (Manipuri)', + origin: 'ꯃꯦꯏꯇꯦꯏꯂꯣꯟ (ꯃꯅꯤꯄꯨꯔꯤ) ꯴.', + code: 'mni-Mtei' + }, + { + name: 'Mizo', + origin: 'Mizo', + code: 'lus' + }, + { + name: 'Mongolian', + origin: 'Монгол', + code: 'mn' + }, + { + name: 'Myanmar (Burmese)', + origin: 'မြန်မာ (ဗမာ)၊', + code: 'my' + }, + { + name: 'Nepali', + origin: 'नेपाली', + code: 'ne' + }, + { + name: 'Norwegian', + origin: 'norsk', + code: 'no' + }, + { + name: 'Nyanja (Chichewa)', + origin: 'Nyanja (Chichewa)', + code: 'ny' + }, + { + name: 'Odia (Oriya)', + origin: 'ଓଡିଆ (ଓଡିଆ)', + code: 'or' + }, + { + name: 'Oromo', + origin: 'Oromo', + code: 'om' + }, + { + name: 'Pashto', + origin: 'پښتو', + code: 'ps' + }, + { + name: 'Persian', + origin: 'فارسی', + code: 'fa' + }, + { + name: 'Polish', + origin: 'Polski', + code: 'pl' + }, + { + name: 'Portuguese (Portugal, Brazil)', + origin: 'Português (Portugal, Brasil)', + code: 'pt' + }, + { + name: 'Punjabi', + origin: 'ਪੰਜਾਬੀ', + code: 'pa' + }, + { + name: 'Quechua', + origin: 'Runasimi', + code: 'qu' + }, + { + name: 'Romanian', + origin: 'Română', + code: 'ro' + }, + { + name: 'Russian', + origin: 'Русский', + code: 'ru' + }, + { + name: 'Samoan', + origin: 'Samoa', + code: 'sm' + }, + { + name: 'Sanskrit', + origin: 'संस्कृत', + code: 'sa' + }, + { + name: 'Scots Gaelic', + origin: 'Gàidhlig na h-Alba', + code: 'gd' + }, + { + name: 'Sepedi', + origin: 'Sepedi', + code: 'nso' + }, + { + name: 'Serbian', + origin: 'Српски', + code: 'sr' + }, + { + name: 'Sesotho', + origin: 'Senyesemane', + code: 'st' + }, + { + name: 'Shona', + origin: 'Shona', + code: 'sn' + }, + { + name: 'Sindhi', + origin: 'سنڌي', + code: 'sd' + }, + { + name: 'Sinhala (Sinhalese)', + origin: 'සිංහල (සිංහල)', + code: 'si' + }, + { + name: 'Slovak', + origin: 'slovenský', + code: 'sk' + }, + { + name: 'Slovenian', + origin: 'Slovenščina', + code: 'sl' + }, + { + name: 'Somali', + origin: 'Somali', + code: 'so' + }, + { + name: 'Spanish', + origin: 'español', + code: 'es' + }, + { + name: 'Sundanese', + origin: 'Sundanese', + code: 'su' + }, + { + name: 'Swahili', + origin: 'kiswahili', + code: 'sw' + }, + { + name: 'Swedish', + origin: 'svenska', + code: 'sv' + }, + { + name: 'Tagalog (Filipino)', + origin: 'Tagalog (Filipino)', + code: 'tl' + }, + { + name: 'Tajik', + origin: 'тоҷикӣ', + code: 'tg' + }, + { + name: 'Tamil', + origin: 'தமிழ்', + code: 'ta' + }, + { + name: 'Tatar', + origin: 'Татар', + code: 'tt' + }, + { + name: 'Telugu', + origin: 'తెలుగు', + code: 'te' + }, + { + name: 'Thai', + origin: 'แบบไทย', + code: 'th' + }, + { + name: 'Tigrinya', + origin: 'ትግሪኛ', + code: 'ti' + }, + { + name: 'Tsonga', + origin: 'Tsonga', + code: 'ts' + }, + { + name: 'Turkish', + origin: 'Türk', + code: 'tr' + }, + { + name: 'Turkmen', + origin: 'Türkmenler', + code: 'tk' + }, + { + name: 'Twi (Akan)', + origin: 'Twi (Will) .', + code: 'ak' + }, + { + name: 'Ukrainian', + origin: 'українська', + code: 'uk' + }, + { + name: 'Urdu', + origin: 'اردو', + code: 'ur' + }, + { + name: 'Uyghur', + origin: 'ئۇيغۇر', + code: 'ug' + }, + { + name: 'Uzbek', + origin: "o'zbek", + code: 'uz' + }, + { + name: 'Vietnamese', + origin: 'Tiếng Việt', + code: 'vi' + }, + { + name: 'Welsh', + origin: 'Cymraeg', + code: 'cy' + }, + { + name: 'Xhosa', + origin: 'isiXhosa', + code: 'xh' + }, + { + name: 'Yiddish', + origin: 'יידיש', + code: 'yi' + }, + { + name: 'Yoruba', + origin: 'Yoruba', + code: 'yo' + }, + { + name: 'Zulu', + origin: 'Zulu', + code: 'zu' + } +]; diff --git a/src/app/core/modules/translate/module.json b/src/app/core/modules/translate/module.json new file mode 100644 index 0000000..d3352e1 --- /dev/null +++ b/src/app/core/modules/translate/module.json @@ -0,0 +1,3 @@ +{ + "repo": "git@github.com:WebArtWork/ngx-translate.git" +} diff --git a/src/app/core/modules/translate/pages/translates/translates.component.html b/src/app/core/modules/translate/pages/translates/translates.component.html new file mode 100644 index 0000000..aeabdb9 --- /dev/null +++ b/src/app/core/modules/translate/pages/translates/translates.component.html @@ -0,0 +1,70 @@ +
+
+
+
+ + +
+ +
+ + + translate + + + Common.Translate all + + + + translate + + + Common.Translate missed + + + +
+
+ + + + {{element?.slug?.split('.')[0]}} + + + {{element?.slug|translate:ts.now}} + + +
+
diff --git a/src/app/core/modules/translate/pages/translates/translates.component.scss b/src/app/core/modules/translate/pages/translates/translates.component.scss new file mode 100644 index 0000000..e3cdebe --- /dev/null +++ b/src/app/core/modules/translate/pages/translates/translates.component.scss @@ -0,0 +1,193 @@ +.translate__top-inner { + width: 100%; + max-width: 100vw; + display: flex; + background: var(--c-bg-secondary); + padding: 15px; + align-items: end; + flex-wrap: wrap; + gap: 20px; + justify-content: space-between; + border-radius: 10px; + margin: 0 auto; + position: relative; + @media screen and (max-width: 1250px) { + justify-content: center; + } + @media (max-width: 767px) { + flex-direction: column; + align-items: center; + + padding: 15px; + } + + &::before { + content: ''; + position: absolute; + + height: 100px; + width: 100%; + + background-color: var(--c-bg-secondary); + z-index: -1; + + left: 0; + right: 0; + + bottom: -50px; + } +} + +.translate__btn { + position: absolute; + top: -5px; + right: 25px; + font-size: 23px; +} + +.translate__dawn-jcon { + span.material-icons { + padding-right: 5px; + } +} + +.translate__buttons { + display: flex; + justify-content: center; + align-items: center; + + gap: 10px; + + @media (max-width: 575px) { + flex-direction: column; + + wbutton { + width: 100%; + } + } +} + +.translate__inner { + display: flex; + gap: 40px; + flex-wrap: wrap; + + @media (max-width: 575px) { + flex-direction: column; + align-items: center; + gap: 20px; + } +} +.formboxs_label { + width: 100%; + color: var(--c-text-primary); + position: relative; + display: flex; + justify-content: space-between; + padding-bottom: 10px; + padding-right: 52px; +} + +.translate__main-wrap { + justify-content: center; +} + +.translate__select { + min-width: 200px; + + max-width: 200px; + background: var(--c-grey); + padding: 5px; + border: 1px solid #7f8c8d; + border-radius: 5px; +} + +.translate__main-inner { + margin-top: 10px; + display: flex; + justify-content: flex-start; + flex-direction: column; + width: 100%; + max-width: 350px; + border-radius: 10px; + margin-top: 20px; + margin: 5px 15px 35px 15px; + padding: 10px; + height: fit-content; + background: var(--c-bg-secondary); + border: 2px solid var(--c-primary); + cursor: pointer; + + @media (max-width: 575px) { + margin: 0; + } +} +.title { + text-align: center; +} + +.input { + width: 100%; + margin-right: 10px; + border-radius: 5px; + + padding: 5px 10px; + border: 1px solid var(--c-text-primary); +} +.formboxs { + display: flex; + gap: 10px; + flex-direction: column; + align-items: flex-start; + +} +.formboxs_title { + color: var(--c-text-primary); + display: flex; + justify-content: center; + align-items: center; +} +.main__sub-inner { + margin: 20px; + display: flex; + flex-wrap: wrap; + + @media (max-width: 767px) { + margin: 20px 0; + } + + @media (max-width: 575px) { + gap: 20px; + } +} +.img-close { + width: 25px; + height: 25px; + border-radius: 50%; + position: absolute; + top: -6px; + right: -6px; + z-index: 2; + transition: all 0.3s; + cursor: pointer; +} +.img-close::before { + content: ''; + position: absolute; + left: 50%; + top: 50%; + width: 80%; + height: 2px; + transform: translate(-50%, -50%) rotate(45deg); + background: var(--c-text-primary); +} +.img-close::after { + content: ''; + position: absolute; + left: 50%; + top: 50%; + width: 80%; + height: 2px; + transform: translate(-50%, -50%) rotate(-45deg); + background: var(--c-text-primary); +} diff --git a/src/app/core/modules/translate/pages/translates/translates.component.ts b/src/app/core/modules/translate/pages/translates/translates.component.ts new file mode 100644 index 0000000..91cab75 --- /dev/null +++ b/src/app/core/modules/translate/pages/translates/translates.component.ts @@ -0,0 +1,185 @@ +import { Component } from '@angular/core'; +import { Language, TranslateService, Word } from '../../translate.service'; +import { FormInterface } from 'src/app/core/modules/form/interfaces/form.interface'; +import { FormService } from 'src/app/core/modules/form/form.service'; +import { HttpService } from 'wacom'; + +interface Translate { + translate: string; + slug: string; + lang: string; +} + +interface TranslateAll { + words: string; + translates: string; +} + +@Component({ + templateUrl: './translates.component.html', + styleUrls: ['./translates.component.scss'] +}) +export class TranslatesComponent { + columns = ['page', 'word', 'translation']; + form: FormInterface = this._form.getForm('translate', { + formId: 'translate', + title: 'Translate', + components: [ + { + name: 'Text', + key: 'translate', + focused: true, + fields: [ + { + name: 'Placeholder', + value: 'fill Translate' + }, + { + name: 'Label', + value: 'Translate' + }, + { + name: 'Textarea', + value: true + } + ] + } + ] + }); + formAll: FormInterface = this._form.getForm('translateAll', { + formId: 'translateAll', + title: 'Translate All', + components: [ + { + name: 'Text', + key: 'words', + fields: [ + { + name: 'Placeholder', + value: 'fill Translate' + }, + { + name: 'Label', + value: 'Translate' + }, + { + name: 'Textarea', + value: true + } + ] + }, + { + name: 'Text', + key: 'translates', + focused: true, + fields: [ + { + name: 'Placeholder', + value: 'fill Translate' + }, + { + name: 'Label', + value: 'Translate' + }, + { + name: 'Textarea', + value: true + } + ] + } + ] + }); + config = { + update: (doc: Translate) => { + this._form + .modal(this.form, [], { + translate: this.ts.translate(doc.slug) + }) + .then((updated: Translate) => { + this._http.post('/api/translate/create', { + appId: this.ts.appId, + slug: doc.slug, + lang: this.ts.language.code, + translate: updated.translate + }); + this.ts.translates[this.ts.language.code][doc.slug] = + updated.translate; + this.ts.reset(); + }); + } + }; + pages = [ + { + name: this.ts.translate('Common.All'), + _id: '' + } + ].concat( + this.ts.pages.map((p: string) => { + return { + name: p, + _id: p + }; + }) + ); + page = localStorage.getItem('page') || ''; + setPage(page: string) { + this.page = page; + localStorage.setItem('page', page); + } + + get rows(): Word[] { + return this.ts.words.filter((w) => { + return this.page && typeof w === 'object' + ? this.page === w.slug.split('.')[0] + : true; + }); + } + + constructor( + public ts: TranslateService, + private _form: FormService, + private _http: HttpService + ) {} + + translateAll(missed = false): void { + const rows = missed + ? this.rows.filter( + (r) => !this.ts.translates[this.ts.language.code][r.slug] + ) + : this.rows; + const words = JSON.stringify(rows.map((r) => r.word)); + const slugs = rows.map((r) => r.slug); + const translates = JSON.stringify( + rows.map((r) => this.ts.translate(r.slug)) + ); + this._form + .modal(this.formAll, [], { + words, + translates + }) + .then((updated: TranslateAll) => { + if (translates === updated.translates) { + return; + } + const translated = JSON.parse(updated.translates); + for (let i = 0; i < slugs.length; i++) { + this._http.post('/api/translate/create', { + appId: this.ts.appId, + slug: slugs[i], + lang: this.ts.language.code, + translate: translated[i] + }); + + this.ts.translates[this.ts.language.code][slugs[i]] = + translated[i]; + } + this.ts.reset(); + }); + } + + set_language(code: string) { + this.ts.set_language( + this.ts.languages.find((l) => l.code === code) as Language + ); + } +} diff --git a/src/app/core/modules/translate/pages/translates/translates.module.ts b/src/app/core/modules/translate/pages/translates/translates.module.ts new file mode 100644 index 0000000..5eb6edf --- /dev/null +++ b/src/app/core/modules/translate/pages/translates/translates.module.ts @@ -0,0 +1,33 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { TranslatesComponent } from './translates.component'; +import { WacomModule } from 'wacom'; +import { TranslateModule } from '../../translate.module'; +import { ButtonModule } from 'src/app/core/modules/button/button.module'; +import { TableModule } from 'src/app/core/modules/table/table.module'; +import { SelectModule } from 'src/app/core/modules/select/select.module'; + +const routes: Routes = [ + { + path: '', + component: TranslatesComponent + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + TranslateModule, + CommonModule, + ButtonModule, + FormsModule, + TableModule, + WacomModule, + SelectModule + ], + declarations: [TranslatesComponent], + providers: [] +}) +export class TranslatesModule {} diff --git a/src/app/core/modules/translate/translate.directive.ts b/src/app/core/modules/translate/translate.directive.ts new file mode 100644 index 0000000..3eafd2f --- /dev/null +++ b/src/app/core/modules/translate/translate.directive.ts @@ -0,0 +1,22 @@ +import { OnInit, Directive, ElementRef } from '@angular/core'; +import { TranslateService } from 'src/app/core/modules/translate/translate.service'; + +@Directive({ + selector: '[translate]' +}) +export class TranslateDirective implements OnInit { + constructor(public elementRef: ElementRef, private tr: TranslateService) { } + + /** + * On initialization, this directive replaces the innerHTML of the element + * with the translated version of the text. + */ + ngOnInit() { + this.elementRef.nativeElement.innerHTML = this.tr.translate( + this.elementRef.nativeElement.innerHTML, + (translate: string) => { + this.elementRef.nativeElement.innerHTML = translate; + } + ); + } +} diff --git a/src/app/core/modules/translate/translate.module.ts b/src/app/core/modules/translate/translate.module.ts new file mode 100644 index 0000000..f796177 --- /dev/null +++ b/src/app/core/modules/translate/translate.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { TranslateDirective } from './translate.directive'; +import { WacomModule } from 'wacom'; +import { TranslatePipe } from './translate.pipe'; + +@NgModule({ + imports: [CommonModule, FormsModule, WacomModule], + declarations: [TranslateDirective, TranslatePipe], + exports: [TranslateDirective, TranslatePipe], + providers: [] +}) +export class TranslateModule {} diff --git a/src/app/core/modules/translate/translate.pipe.ts b/src/app/core/modules/translate/translate.pipe.ts new file mode 100644 index 0000000..ae29c57 --- /dev/null +++ b/src/app/core/modules/translate/translate.pipe.ts @@ -0,0 +1,19 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { TranslateService } from './translate.service'; + +@Pipe({ + name: 'translate' +}) +export class TranslatePipe implements PipeTransform { + constructor(private _tr: TranslateService) { } + + /** + * Transforms the given slug into its corresponding translated string. + * @param slug - The translation key to be translated. + * @param refresh - An optional parameter to force the pipe to update (not used here). + * @returns The translated string. + */ + transform(slug: string, refresh?: number): string { + return this._tr.translate(slug); + } +} diff --git a/src/app/core/modules/translate/translate.service.ts b/src/app/core/modules/translate/translate.service.ts new file mode 100644 index 0000000..b075a68 --- /dev/null +++ b/src/app/core/modules/translate/translate.service.ts @@ -0,0 +1,323 @@ +import { Injectable } from '@angular/core'; +import { environment } from 'src/environments/environment'; +import { CoreService, HttpService, StoreService } from 'wacom'; +import { languages } from './languages'; + +export interface Language { + code: string; + name: string; + origin: string; +} + +export interface Word { + slug: string; + page: string; + word: string; + translate: string; + translate_id?: string; + _id?: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class TranslateService { + readonly allLanguages = languages; + readonly appId = (environment as unknown as { appId: string }).appId; + + constructor( + private store: StoreService, + private http: HttpService, + private _core: CoreService + ) { + this.store.getJson('translates', (translates) => { + if (translates) { + this.translates = translates || {}; + } + }); + + this._core.on('languages').subscribe((languages: Language[]) => { + this.languages = languages; + }); + + this.store.getJson('words', (words) => { + if (words) { + this.words = words; + } + }); + + this.store.getJson('language', (language: Language) => { + if (language) { + this.set_language(language); + } + }); + + this.http.get('/api/translate/get' + (this.appId ? '/' + this.appId : ''), (obj) => { + if (obj) { + this.translates = obj; + this.store.setJson('translates', this.translates); + } + }); + + this.http.get('/api/word/get' + (this.appId ? '/' + this.appId : ''), (arr) => { + if (arr) { + this.words = arr; + this.store.setJson('words', this.words); + for (let i = 0; i < arr.length; i++) { + if (this.pages.indexOf(arr[i].page) < 0) { + this.pages.push(arr[i].page); + } + } + this._wordsLoaded = true; + } + }); + } + + // Array of all words for translation + words: Word[] = []; + + // Array of pages for words + pages: string[] = []; + + /** + * Deletes a word and its associated translation from the backend and local state. + * @param word - The word object to delete. + */ + delete(word: Word) { + for (let i = this.words.length - 1; i >= 0; i--) { + if (this.words[i]._id == word._id) this.words.splice(i, 1); + } + + this.http.post('/api/word/delete' + (this.appId ? '/' + this.appId : ''), { + _id: word._id + }); + + this.http.post('/api/translate/delete' + (this.appId ? '/' + this.appId : ''), { + slug: word.slug + }); + } + + /* Translate Use */ + + // Array of supported languages + languages: Language[] = ( + environment as unknown as { languages: Language[] } + ).languages + ? (environment as unknown as { languages: Language[] }).languages + : [ + { + code: 'en', + name: 'English', + origin: 'English' + } + ]; + + // Currently selected language + language: Language = this.languages.length + ? this.languages[0] + : { + code: 'en', + name: 'English', + origin: 'English' + }; + + /** + * Sets the current language and updates the translations. + * @param language - The language object to set as current. + */ + set_language(language: Language) { + if (language) { + this.http.post('/api/translate/set', { + appId: this.appId, + language: language.code + }); + + this.language = language; + + this.reset(); + + this.store.setJson('language', language); + } + } + + /** + * Switches to the next available language. + */ + next_language() { + for (let i = 0; i < this.languages.length; i++) { + if (this.languages[i].code === this.language.code) { + if (this.languages.length - 1 === i) { + this.language = this.languages[0]; + } else { + this.language = this.languages[i + 1]; + } + break; + } + } + + this.store.setJson('language', this.language); + } + + // Dictionary of translations + translates: any = {}; + + resets: any = {}; + now = Date.now(); + + /** + * Resets all translations for the current language. + */ + reset() { + this.now = Date.now(); + for (const slug in this.resets) { + if (Array.isArray(this.resets[slug])) { + for (let i = 0; i < this.resets[slug].length; i++) { + if ( + this.translates[this.language.code] && + this.translates[this.language.code][slug] + ) { + this.resets[slug][i]( + this.translates[this.language.code][slug] + ); + } else { + this.resets[slug][i](this._slug2name(slug)); + } + } + } + } + } + + /** + * Translates a slug into its corresponding string for the current language. + * @param slug - The translation key. + * @param reset - Optional reset callback to handle dynamic updates. + * @returns The translated string. + */ + translate(slug: string, reset?: (translate: string) => void) { + if (!slug) return ''; + + if (slug.split('.').length < 2) return slug; + + if (!this.resets[slug]) this.resets[slug] = []; + + if (reset) { + this.resets[slug].push(reset); + } + + if (!this.translates[this.language.code]) { + this.translates[this.language.code] = {}; + } + + if (this.translates[this.language.code][slug]) { + return this.translates[this.language.code][slug]; + } + + if ( + this.words + .map((w) => w?.slug || '') + .filter((w) => !!w) + .indexOf(slug) < 0 + ) { + this.create_word(slug); + } + + return this._slug2name(slug); + } + + private _created: Record = {}; + private _wordsLoaded = false; + + /** + * Creates a new word in the backend and adds it to the list of words. + * @param slug - The translation key to create. + */ + create_word(slug: string) { + if (this._created[slug]) { + return; + } + + if (this._wordsLoaded) { + this._created[slug] = true; + + this.http.post( + '/api/word/create', + { + appId: this.appId, + slug: slug, + word: this._slug2name(slug), + page: slug.split('.')[0], + lang: this.language.code + }, + (word) => { + if (word) { + this.words.push(word); + } + } + ); + } else { + setTimeout(() => { + this.create_word(slug); + }, 500); + } + } + + /** + * Updates an existing translation in the backend and triggers any associated reset callbacks. + * @param slug - The translation key. + * @param languageCode - The language code for the translation. + * @param translate - The translated string. + */ + update_translate(slug: string, languageCode: string, translate: string) { + this._core.afterWhile(this, () => { + this.http.post('/api/translate/create', { + appId: this.appId, + slug, + translate, + lang: languageCode + }); + + this.store.setJson('translates', this.translates); + + if ( + this.language.code === languageCode && + Array.isArray(this.resets[slug]) + ) { + for (let i = 0; i < this.resets[slug].length; i++) { + if (typeof this.resets[slug][i] === 'function') { + this.resets[slug][i](); + } + } + } + }); + } + + /** + * Downloads the translations as a JSON file. + */ + download_json() { + this.http.get('/api/translate/get_translates', (obj) => { + const dataStr = + 'data:text/json;charset=utf-8,' + + encodeURIComponent(JSON.stringify(this.translates)); + + const link = document.createElement('a'); + + link.href = dataStr; + + link.download = 'translate.json'; + + link.click(); + + link.remove(); + }); + } + + /** + * Converts a slug into a more human-readable name. + * @param slug - The slug to convert. + * @returns The human-readable name. + */ + private _slug2name(slug: string) { + return slug.substr(slug.indexOf('.') + 1); + } +} diff --git a/src/app/core/selectors/test/test-selector.component.html b/src/app/core/selectors/test/test-selector.component.html new file mode 100644 index 0000000..8a058b1 --- /dev/null +++ b/src/app/core/selectors/test/test-selector.component.html @@ -0,0 +1,5 @@ + diff --git a/src/app/core/selectors/test/test-selector.component.scss b/src/app/core/selectors/test/test-selector.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/selectors/test/test-selector.component.ts b/src/app/core/selectors/test/test-selector.component.ts new file mode 100644 index 0000000..9cb36d6 --- /dev/null +++ b/src/app/core/selectors/test/test-selector.component.ts @@ -0,0 +1,32 @@ +import { + Component, + EventEmitter, + Input, + OnChanges, + Output, + SimpleChanges +} from '@angular/core'; +import { TestService, Test } from 'src/app/core/services/test.service'; + +@Component({ + selector: 'test-selector', + templateUrl: './test-selector.component.html', + styleUrls: ['./test-selector.component.scss'] +}) +export class TestSelectorComponent implements OnChanges { + @Input() value: string; + + @Output() onChange = new EventEmitter(); + + get items(): Test[] { + return this._testService.tests; + } + + constructor(private _testService: TestService) {} + + ngOnChanges(changes: SimpleChanges): void { + if (changes['value'] && !changes['value'].firstChange) { + this.value = changes['value'].currentValue; + } + } +} diff --git a/src/app/core/services/test.service.ts b/src/app/core/services/test.service.ts new file mode 100644 index 0000000..73b438e --- /dev/null +++ b/src/app/core/services/test.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@angular/core'; +import { + AlertService, + CoreService, + HttpService, + StoreService, + CrudService, + CrudDocument, +} from 'wacom'; + +export interface Test extends CrudDocument { + name: string; + description: string; +} + +@Injectable({ + providedIn: 'root', +}) +export class TestService extends CrudService { + tests: Test[] = this.getDocs(); + + testsByAuthor: Record = {}; + + constructor( + _http: HttpService, + _store: StoreService, + _alert: AlertService, + _core: CoreService + ) { + super( + { + name: 'test' + }, + _http, + _store, + _alert, + _core + ); + + this.get(); + + this.filteredDocuments(this.testsByAuthor); + } +} diff --git a/src/app/core/theme/guest/guest.component.html b/src/app/core/theme/guest/guest.component.html new file mode 100644 index 0000000..90c6b64 --- /dev/null +++ b/src/app/core/theme/guest/guest.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/core/theme/guest/guest.component.scss b/src/app/core/theme/guest/guest.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/core/theme/guest/guest.component.ts b/src/app/core/theme/guest/guest.component.ts new file mode 100644 index 0000000..ec1f7eb --- /dev/null +++ b/src/app/core/theme/guest/guest.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'guest', + templateUrl: './guest.component.html', + styleUrls: ['./guest.component.scss'] +}) +export class GuestComponent {} diff --git a/src/app/core/theme/user/user.component.html b/src/app/core/theme/user/user.component.html new file mode 100644 index 0000000..8fd88e2 --- /dev/null +++ b/src/app/core/theme/user/user.component.html @@ -0,0 +1,95 @@ + diff --git a/src/app/core/theme/user/user.component.scss b/src/app/core/theme/user/user.component.scss new file mode 100644 index 0000000..4fce628 --- /dev/null +++ b/src/app/core/theme/user/user.component.scss @@ -0,0 +1,305 @@ +@import 'angular'; +@import '/src/scss/utils/vars'; +/* WRAPPER STYLE */ +.wrapper { + position: fixed; + width: 100%; + height: 100%; + overflow: hidden; + @include flexBox(flex, column, null, null, null); + background: var(--c-bg-primary); + transition: all 0.5s ease-in-out; + .main { + flex-grow: 1; + overflow-y: auto; + @include flexBox(flex, column, null, null, null); + position: relative; + // display: flex; + // flex-flow: row wrap; + max-width: 2000px; + margin: 0 auto; + width: 100%; + padding: 20px 270px 0 20px; + + transition: all 0.5s ease-in-out; + + @media screen and (max-width: 991px) { + padding: 20px; + } + @media screen and (max-width: 767px) { + padding: 10px; + } + // .fade { + // display: none; + // position: fixed; + // width: 100%; + // height: 100%; + // z-index: 9; + // background: rgba(0, 0, 0, 0.3); + // @media screen and (max-width: 991px) { + // display: block; + // } + // } + } +} + +/*.showTable { + padding: 20px !important; +}*/ + +hr { + border: none; + border-top: 2px solid var(--c-text-primary); + margin: 5px 0; +} + +/* NAV STYLE */ +.nav { + transition: all 0.5s ease-in-out; + background: var(--c-basic); + width: 100%; + box-shadow: 0 3px 5px -1px #0003, 0 6px 10px #00000024, 0 1px 18px #0000001f; + @include flexBox(flex, null, space-between, center, null); + min-height: 50px; + z-index: 100; + overflow: hidden; + &__ul { + z-index: 1; + margin-top: 0; + margin-bottom: 0; + padding: 0 20px; + transition: all 0.5s ease-in-out; + @include flexBox(flex, null, null, center, null); + width: 100%; + @media screen and (max-width: 767px) { + justify-content: end !important; + } + } + &__li { + display: inline-block; + &._burger { + width: 44px; + height: 34px; + } + &:last-child { + margin-left: auto; + } + &:not(:last-child) { + margin-right: 10px; + } + } + &__a { + cursor: pointer; + color: $c-white; + font-size: var(--fs) - 2px; + padding: 5px 10px; + border-radius: $b-radius; + transition: all 0.5s ease-in-out; + display: flex; + justify-content: center; + align-items: center; + position: relative; + &::before { + content: ''; + position: absolute; + width: 5px; + height: 5px; + background-color: $c-white; + bottom: -1px; + border-radius: $b-radius-img; + transform: translateY(15px); + opacity: 0; + @include bp-max(md) { + top: -3px; + } + } + &._activeLink { + &::before { + animation: navLinkAnimation 0.75s forwards; + } + @keyframes navLinkAnimation { + 0% { + opacity: 0; + transform: translateY(15px); + } + 100% { + opacity: 1; + transform: translateY(0); + } + } + } + .material-icons { + color: $c-white; + width: 24px; + } + } + &__toggle { + width: 100%; + height: 100%; + @include flexBox(flex, null, null, center, null); + position: relative; + order: 3; + cursor: pointer; + justify-content: center; + &-line, + &-line:before, + &-line:after { + cursor: pointer; + border-radius: 1px; + height: 2px; + width: 24px; + position: absolute; + display: block; + content: ''; + transition: all 0.5s ease-in-out; + background-color: transparent; + } + &-line:before { + top: -7px; + top: 0; + transform: rotate(45deg); + background: $c-white; + } + &-line:after { + bottom: -7px; + top: 0; + transform: rotate(-45deg); + background: $c-white; + } + @media screen and (max-width: 767px) { + .nav__toggle-line, + .nav__toggle-line:before, + .nav__toggle-line:after { + background: #fff; + } + &-line:before { + top: -7px; + transform: unset; + background: $c-white; + } + &-line:after { + top: 7px; + transform: unset; + background: $c-white; + } + } + &._active &-line { + background: $c-white; + + &:before, + &:after { + top: 0; + } + &:before { + transform: unset; + top: -7px; + } + &:after { + transform: unset; + top: 7px; + } + @media screen and (max-width: 767px) { + background: transparent; + + &:before { + transform: rotate(45deg); + top: -7px; + top: 0; + } + &:after { + transform: rotate(-45deg); + bottom: -7px; + top: 0; + } + } + } + } + &__burger { + margin: 0; + max-width: 250px; + width: 100%; + height: calc(100% - 50px); + transform: translateX(0) !important; + top: 50px; + position: fixed; + background-color: var(--c-bg-secondary); + right: 0; + transform: translateX(120%); + z-index: 10; + box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.03), + 0 6px 10px rgba(0, 0, 0, 0.24), + 0 1px 18px rgba(0, 0, 0, 0.31); + transition: all 0.5s ease-in-out; + @media screen and (max-width: 767px) { + transform: translateX(120%) !important; + } + @include flexBox(flex, column, null, null, null); + + + &._active { + transform: translateX(120%) !important; + z-index: 0; + @media screen and (max-width: 767px) { + transform: translateX(0) !important; + z-index: 10; + } + } + &-list { + flex-grow: 1; + height: 100%; + @include flexBox(flex, column, null, null, null); + overflow-y: auto; + padding: 20px; + .nav__burger-link { + color: var(--c-text-primary); + padding: 10px; + .avatar__img { + border-radius: 50%; + } + } + } + &-link { + @include flexBox(flex, null, null, center, null); + gap: 10px; + .material-icons { + color: var(--c-text-primary); + font-size: 30px; + } + } + &-user { + @include flexBox(flex, column, center, center, null); + color: var(--c-text-primary); + padding: 5px; + .name { + word-break: break-word; + } + .material-icons { + color: var(--c-text-primary); + font-size: calc($fs + 32px); + } + } + } + @include bp-max(md) { + order: 2; + &__ul { + justify-content: space-between; + } + &__li:last-child { + margin-left: 0; + } + &__burger { + top: 0; + } + } +} + +.theme-switch { + position: absolute; + right: 10px; + display: flex; + justify-content: flex-end; + margin-right: 10px; + .material-icons { + cursor: pointer; + } +} diff --git a/src/app/core/theme/user/user.component.ts b/src/app/core/theme/user/user.component.ts new file mode 100644 index 0000000..74f9e89 --- /dev/null +++ b/src/app/core/theme/user/user.component.ts @@ -0,0 +1,24 @@ +import { UserService } from 'src/app/modules/user/services/user.service'; +import { coreAnimation } from '../../animations/core.animations'; +import { environment } from 'src/environments/environment'; +import { Platform } from '@angular/cdk/platform'; +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-user', + templateUrl: './user.component.html', + styleUrls: ['./user.component.scss'], + animations: [coreAnimation] +}) +export class UserComponent { + readonly url = environment.url; + forceAvatarUrl = ''; + showSidebar = false; + hideSidebar(): void { + if (!this._platform.ANDROID && !this._platform.IOS) { + this.showSidebar = false; + } + } + + constructor(public us: UserService, private _platform: Platform) {} +} diff --git a/src/app/modules/customform/pages/customforms/customforms.component.html b/src/app/modules/customform/pages/customforms/customforms.component.html new file mode 100644 index 0000000..10bf6c4 --- /dev/null +++ b/src/app/modules/customform/pages/customforms/customforms.component.html @@ -0,0 +1,22 @@ + + + {{element.components?.length}} + + + + + diff --git a/src/app/modules/customform/pages/customforms/customforms.component.scss b/src/app/modules/customform/pages/customforms/customforms.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/modules/customform/pages/customforms/customforms.component.ts b/src/app/modules/customform/pages/customforms/customforms.component.ts new file mode 100644 index 0000000..1808f51 --- /dev/null +++ b/src/app/modules/customform/pages/customforms/customforms.component.ts @@ -0,0 +1,356 @@ +import { Component } from '@angular/core'; +import { FormService } from 'src/app/core/modules/form/form.service'; +import { + CustomformService, + Customform +} from '../../services/customform.service'; +import { AlertService } from 'wacom'; +import { TranslateService } from 'src/app/core/modules/translate/translate.service'; +import { FormInterface } from 'src/app/core/modules/form/interfaces/form.interface'; +import { FormComponentInterface } from 'src/app/core/modules/form/interfaces/component.interface'; + +@Component({ + templateUrl: './customforms.component.html', + styleUrls: ['./customforms.component.scss'] +}) +export class CustomformsComponent { + columns = ['formId', 'components', 'active']; + + form: FormInterface = this._form.getForm('form', { + formId: 'form', + title: 'Custom form', + components: [ + { + name: 'Text', + key: 'title', + focused: true, + fields: [ + { + name: 'Placeholder', + value: 'fill title' + }, + { + name: 'Label', + value: 'Title' + } + ] + }, + { + name: 'Select', + key: 'formId', + fields: [ + { + name: 'Placeholder', + value: 'Select form id' + }, + { + name: 'Label', + value: 'Form ID' + }, + { + name: 'Items', + value: this._form.formIds + } + ] + } + ] + }); + + components: FormComponentInterface[] = []; + formComponents: FormInterface = this._form.getForm('formComponents', { + formId: 'formComponents', + title: 'Custom components', + components: [ + { + components: this.components + }, + { + name: 'Select', + key: 'addComponent', + fields: [ + { + name: 'Placeholder', + value: 'Select form componnet' + }, + { + name: 'Label', + value: 'Form Component' + }, + { + name: 'Value', + value: 'name', + skipTranslation: true + }, + { + name: 'Items', + value: this._form.getTemplateComponentsNames() + } + ] + } + ] + }); + + config = { + create: (): void => { + this._form + .modal(this.form, { + label: 'Create', + click: (created: unknown, close: () => void) => { + this._cfs.create(created as Customform, { + callback: close.bind(this) + }); + } + }) + .then(this._cfs.create.bind(this)); + }, + update: (form: Customform): void => { + this._form + .modal( + this.form, + { + label: 'Update', + click: (updated: unknown, close: () => void) => { + this._cfs.update(updated as Customform, { + callback: close.bind(this) + }); + } + }, + form + ) + .then(this._cfs.update.bind(this)); + }, + delete: (form: Customform): void => { + this._alert.question({ + text: this._translate.translate( + 'Common.Are you sure you want to delete this user?' + ), + buttons: [ + { + text: this._translate.translate('Common.No') + }, + { + text: this._translate.translate('Common.Yes'), + callback: (): void => { + this._cfs.delete(form); + } + } + ] + }); + }, + buttons: [ + { + icon: 'text_fields', + click: (doc: Customform): void => { + console.log(this.formComponents); + + this.components.splice(0, this.components.length); + + const submition: Record = { + addComponent: 'Text' + }; + + doc.components = doc.components || []; + + for (let i = doc.components.length - 1; i >= 0; i--) { + const fields = this._form.getTemplateFields( + doc.components[i].name + ); + + doc.components[i].fields = doc.components[ + i + ].fields.filter((f) => fields.includes(f.name)); + + for (const name of fields) { + if ( + !doc.components[i].fields.find( + (f) => f.name === name + ) + ) { + doc.components[i].fields.push({ + value: '', + name + }); + } + } + + submition['key' + i] = doc.components[i].key as string; + + for (const field of doc.components[i].fields) { + submition[field.name + i] = field.value; + } + } + + const remove = (i: number): void => { + this.components.splice(i, 1); + + doc.components.splice(i, 1); + + this._cfs.updateAfterWhile(doc); + }; + + (doc.components || []).forEach((component) => { + this.components.push( + this._addCustomComponent( + component.name, + this.components.length, + remove + ) + ); + }); + + this._form + .modal( + this.formComponents, + { + label: 'Add component', + click: (): void => { + const component: string = submition[ + 'addComponent' + ] as string; + + this.components.push( + this._addCustomComponent( + component, + this.components.length, + remove + ) + ); + + doc.components.push({ + name: submition[ + 'addComponent' + ] as string, + fields: this._form + .getTemplateFields(component) + .map((name) => { + return { + value: '', + name + }; + }) + }); + } + }, + submition, + () => {}, + { size: 'big' } + ) + .then(() => { + for (let i = 0; i < doc.components.length; i++) { + doc.components[i].key = submition[ + 'key' + i + ] as string; + + for (const field of doc.components[i].fields) { + field.value = submition[ + field.name + i + ] as string; + } + } + + this._cfs.updateAfterWhile(doc); + }); + } + } + ] + }; + + get rows(): FormInterface[] { + return this._cfs.customforms; + } + + constructor( + private _translate: TranslateService, + private _cfs: CustomformService, + private _alert: AlertService, + private _form: FormService + ) {} + + private _addCustomComponent( + component: string, + index: number, + remove: (i: number) => void + ): FormComponentInterface { + const templateFields = this._form + .getTemplateFields(component) + .map((f) => { + return { + name: + this._form.getCustomTemplateFields(component)[f] || + 'Text', + key: f + index, + fields: [ + { + name: 'Placeholder', + value: 'fill ' + f + }, + { + name: 'Label', + value: + f.charAt(0).toUpperCase() + f.slice(1, f.length) + } + ] + }; + }); + + const components = [ + { + name: 'Text', + key: 'key' + index, + fields: [ + { + name: 'Placeholder', + value: 'fill key' + }, + { + name: 'Label', + value: 'Key' + } + ] + }, + ...templateFields, + { + name: 'Button', + fields: [ + { + name: 'Label', + value: 'Remove' + }, + { + name: 'Click', + value: (): void => { + remove(index); + } + } + ] + } + ]; + + return { + class: 'd-f mt10', + components + }; + } + + changeStatus(form: Customform): void { + setTimeout(() => { + if (form.active) { + for (const customForm of this._cfs.customforms) { + if ( + customForm._id === form._id || + customForm.formId !== form.formId + ) + continue; + + if (customForm.active) { + customForm.active = false; + + this._cfs.updateAfterWhile(customForm); + } + } + } + + this._cfs.updateAfterWhile(form); + }); + } +} diff --git a/src/app/modules/customform/pages/customforms/customforms.module.ts b/src/app/modules/customform/pages/customforms/customforms.module.ts new file mode 100644 index 0000000..a52cbc4 --- /dev/null +++ b/src/app/modules/customform/pages/customforms/customforms.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { CoreModule } from 'src/app/core/core.module'; +import { CustomformsComponent } from './customforms.component'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = [{ + path: '', + component: CustomformsComponent +}]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CoreModule + ], + declarations: [ + CustomformsComponent + ], + providers: [] + +}) + +export class CustomformsModule { } diff --git a/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.html b/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.html new file mode 100644 index 0000000..0ea9310 --- /dev/null +++ b/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.html @@ -0,0 +1,88 @@ +
+
+
+ +
+ +
+ +
+
+ +
+
+ +
+ + Add + +
+ +
+
+ {{component.name}} + +
+ +
+
+ remove +
+
+
+ +
+ + Create + + + + Update + +
+
diff --git a/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.scss b/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.scss new file mode 100644 index 0000000..7f56810 --- /dev/null +++ b/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.scss @@ -0,0 +1,153 @@ +.form{ + &__wrap{ + display: flex; + flex-flow: row wrap; + justify-content: center; + } + &__input{ + margin-right: 13px; + max-width: 350px; + width: 100%; + input{ + padding: 10px 20px 10px 20px; + border-radius: 15px; + border: 2px solid var(--c-primary); + height: 100%; + width: 100%; + } + } + &__row{ + margin-bottom: 15px; + flex: 0 0 100%; + display: flex; + justify-content: center; + &:last-child{ + margin-bottom: 0; + } + } + &__select{ + max-width: 350px; + width: 100%; + &--margin{ + margin-right: 13px; + } + select{ + padding: 10px 20px 10px 20px; + border-radius: 15px; + border: 2px solid var(--c-primary); + width: 100%; + } + } + &__btns{ + flex: 0 0 100%; + text-align: center; + } + &__btn{ + max-width: 715px; + width: 100%; + border-radius: 16px; + border: none; + background: var(--c-primary); + color: #fff; + cursor: pointer; + transition: all .3s; + height: 49px; + &:hover{ + background-color: #295c86; + } + &:disabled{ + color: #ffffff80; + background: #4a7ba4; + } + &--add{ + max-width: 350px; + } + } + &__add{ + flex: 0 0 33.333%; + max-width: 33.333%; + display: flex; + flex-flow: column wrap; + padding: 0 10px; + margin-bottom: 15px; + &-title{ + font-weight: 600; + color: var(--c-primary); + padding-bottom: 5px; + } + &-list{ + display: flex; + flex-flow: row wrap; + margin: 10px 0 20px 0; + flex: 0 0 100%; + max-width: 715px; + overflow-y: scroll; + max-height: 230px; + } + &-label{ + display: flex; + flex-flow: column wrap; + &:first-child{ + margin-bottom: 5px; + } + input{ + padding: 10px 20px 10px 20px; + border-radius: 8px; + border: 2px solid var(--c-primary); + width: 100%; + } + } + &-btn{ + padding-top: 10px; + button{ + width: 100%; + height: 42px; + border-radius: 8px; + border: none; + background: var(--c-primary); + color: #fff; + cursor: pointer; + transition: all .3s; + &:hover{ + background-color: #295c86; + } + } + } + } +} + +@media screen and (max-width: 991px) { + .form__add{ + flex: 0 0 50%; + max-width: 50%; + } +} +@media screen and (max-width: 767px) { + +} +@media screen and (max-width: 479px) { + .form__add { + flex: 0 0 100%; + max-width: 100%; + padding: 0; + } + .form__select select { + padding: 5px 20px 5px 20px; + } + .form__input input { + padding: 5px 20px 5px 20px; + } + .form__btn { + height: 39px; + padding: 11px 0; + } + .form__add-label input{ + padding: 8px 20px 8px 20px; + } + .form__add-label span{ + font-size: 14px; + } + .form__add-btn button { + height: 38px; + } +} diff --git a/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.ts b/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.ts new file mode 100644 index 0000000..ffc3f11 --- /dev/null +++ b/src/app/modules/customform/pages/customforms/mutate-form/mutate-form.component.ts @@ -0,0 +1,34 @@ +import { Component } from '@angular/core'; +import { FormService } from 'src/app/core/modules/form/form.service'; +import { FormInterface } from 'src/app/core/modules/form/interfaces/form.interface'; + +@Component({ + selector: 'app-mutate-form', + templateUrl: './mutate-form.component.html', + styleUrls: ['./mutate-form.component.scss'] +}) +export class MutateFormComponent { + close: () => void; + + form: FormInterface = this.fs.new(); + + addComponent = ''; + + addField() { + const component = this.fs.components.filter( + (c) => c.name === this.addComponent + )[0]; + + this.form.components.push({ + name: component.name, + fields: (component.fields||[]).map((f) => { + return { + name: f, + value: '' + }; + }) + }); + } + + constructor(public fs: FormService) {} +} diff --git a/src/app/modules/customform/services/customform.service.ts b/src/app/modules/customform/services/customform.service.ts new file mode 100644 index 0000000..ebd9686 --- /dev/null +++ b/src/app/modules/customform/services/customform.service.ts @@ -0,0 +1,71 @@ +import { Injectable } from '@angular/core'; +import { + AlertService, + CoreService, + HttpService, + StoreService, + CrudService, + CrudDocument +} from 'wacom'; + +export interface CustomformcomponnetfieldInterface { + name: string; + value: string; +} + +export interface CustomformcomponnetInterface { + name: string; + fields: CustomformcomponnetfieldInterface[]; + key?: string; + components?: CustomformcomponnetInterface[]; + root?: boolean; +} + +export interface Customform extends CrudDocument { + name: string; + class: string; + fields: CustomformcomponnetfieldInterface[]; + components: CustomformcomponnetInterface[]; + key?: string; + active?: boolean; + formId?: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class CustomformService extends CrudService { + customforms: Customform[] = []; + + constructor( + _http: HttpService, + _store: StoreService, + _alert: AlertService, + _core: CoreService + ) { + super( + { + name: 'form' + }, + _http, + _store, + _alert, + _core + ); + + this.get().subscribe((customforms: Customform[]) => + this.customforms.push(...customforms) + ); + + _core.on('customform_create').subscribe((customform: Customform) => { + this.customforms.push(customform); + }); + + _core.on('customform_delete').subscribe((customform: Customform) => { + this.customforms.splice( + this.customforms.findIndex((o) => o._id === customform._id), + 1 + ); + }); + } +} diff --git a/src/app/modules/user/LICENSE b/src/app/modules/user/LICENSE new file mode 100644 index 0000000..9598c2a --- /dev/null +++ b/src/app/modules/user/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Web Art Work + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app/modules/user/README.md b/src/app/modules/user/README.md new file mode 100644 index 0000000..3ec26c9 --- /dev/null +++ b/src/app/modules/user/README.md @@ -0,0 +1 @@ +# ngx-user diff --git a/src/app/modules/user/interfaces/user.interface.ts b/src/app/modules/user/interfaces/user.interface.ts new file mode 100644 index 0000000..2cf7a7e --- /dev/null +++ b/src/app/modules/user/interfaces/user.interface.ts @@ -0,0 +1,11 @@ +import { CrudDocument } from "wacom"; + +export interface User extends CrudDocument { + data: Record; + is: Record; + name: string; + phone: string; + bio: string; + email: string; + thumb: string; +} diff --git a/src/app/modules/user/module.json b/src/app/modules/user/module.json new file mode 100644 index 0000000..b2f6f81 --- /dev/null +++ b/src/app/modules/user/module.json @@ -0,0 +1,3 @@ +{ + "repo" : "git@github.com:WebArtWork/ngx-user.git" +} diff --git a/src/app/modules/user/pages/clients/clients.component.html b/src/app/modules/user/pages/clients/clients.component.html new file mode 100644 index 0000000..f468037 --- /dev/null +++ b/src/app/modules/user/pages/clients/clients.component.html @@ -0,0 +1,8 @@ + + + diff --git a/src/app/modules/user/pages/clients/clients.component.scss b/src/app/modules/user/pages/clients/clients.component.scss new file mode 100644 index 0000000..9d159c0 --- /dev/null +++ b/src/app/modules/user/pages/clients/clients.component.scss @@ -0,0 +1,73 @@ +@import 'angular'; +.w-table-user { + @include flexBox(flex, null, null, center, wrap); + &__img { + width: 30px; + height: 30px; + min-width: 30px; + min-height: 30px; + margin-right: 10px; + img { + width: 100%; + height: 100%; + border-radius: var(--b-radius-img); + } + @include bp-max(md) { + display: none; + } + } +} + +.w-table { + @include bp-max(md) { + .email, + .role { + display: none; + } + } + .checkbox { + height: 18px; + max-height: 18px; + display: block; + &__body { + padding: 2px; + } + } +} + +.users-field { + @include flexBox(flex, null, space-between, flex-end, null); + .w-btn { + margin: 10px; + } + .forms { + width: 100%; + } + + @include bp-max(xs) { + flex-direction: column; + align-items: center; + .w-btn { + margin-bottom: 20px; + width: 100%; + } + } +} + +.w-table__td.actions .material-icons { + transition: var(--transition); + &:hover { + color: var(--c-error); + } + & i + i { + margin-left: 15px; + } +} + +.users { + &__header { + @include text-default(0, 23px, 500, 20px, var(--c-text-primary)); + @include flexBox(flex, null, space-between, center, null); + border-radius: var(--b-radius); + } +} diff --git a/src/app/modules/user/pages/clients/clients.component.ts b/src/app/modules/user/pages/clients/clients.component.ts new file mode 100644 index 0000000..d61b0c7 --- /dev/null +++ b/src/app/modules/user/pages/clients/clients.component.ts @@ -0,0 +1,134 @@ +import { Component } from '@angular/core'; +import { FormService } from 'src/app/core/modules/form/form.service'; +import { FormInterface } from 'src/app/core/modules/form/interfaces/form.interface'; +import { TranslateService } from 'src/app/core/modules/translate/translate.service'; +import { AlertService, CoreService } from 'wacom'; +import { UserService } from '../../services/user.service'; +import { User } from '../../interfaces/user.interface'; + +@Component({ + templateUrl: './clients.component.html', + styleUrls: ['./clients.component.scss'] +}) +export class ClientsComponent { + columns = ['name', 'email']; + form: FormInterface = this._form.getForm('user', { + formId: 'user', + title: 'User', + components: [ + { + name: 'Text', + key: 'name', + focused: true, + fields: [ + { + name: 'Placeholder', + value: 'fill Client name' + }, + { + name: 'Label', + value: 'Name' + } + ] + }, + { + name: 'Email', + key: 'email', + fields: [ + { + name: 'Placeholder', + value: 'fill Client email' + }, + { + name: 'Label', + value: 'Email' + } + ] + } + ] + }); + users: User[] = []; + private _page = 1; + setUsers(page = this._page) { + this._page = page; + this._core.afterWhile( + this, + () => { + this._us.get({ page }).subscribe((users) => { + this.users.splice(0, this.users.length); + this.users.push(...users); + }); + }, + 250 + ); + } + config = { + paginate: this.setUsers.bind(this), + perPage: 20, + setPerPage: this._us.setPerPage.bind(this._us), + allDocs: false, + create: () => { + this._form + .modal(this.form, { + label: 'Create', + click: (created: unknown, close: () => void) => { + this._us.create(created as User, { + alert: this._translate.translate( + 'User.Client has been created' + ), + callback: () => { + this.setUsers(); + close(); + } + }); + } + }) + .then(this._us.create.bind(this)); + }, + update: (doc: User) => { + this._form.modal(this.form, [], doc).then((updated: User) => { + this._core.copy(updated, doc); + this._us.update(doc, { + alert: this._translate.translate( + 'User.Client has been updated' + ) + }); + }); + }, + delete: (user: User) => { + this._alert.question({ + text: this._translate.translate( + 'Common.Are you sure you want to delete this client?' + ), + buttons: [ + { + text: this._translate.translate('Common.No') + }, + { + text: this._translate.translate('Common.Yes'), + callback: () => { + this._us.delete(user, { + name: 'admin', + alert: this._translate.translate( + 'User.Client has been deleted' + ), + callback: () => { + this.setUsers(); + } + }); + } + } + ] + }); + } + }; + constructor( + private _translate: TranslateService, + private _us: UserService, + private _alert: AlertService, + private _core: CoreService, + private _form: FormService + ) { + this.setUsers(); + } +} diff --git a/src/app/modules/user/pages/clients/clients.module.ts b/src/app/modules/user/pages/clients/clients.module.ts new file mode 100644 index 0000000..3586d01 --- /dev/null +++ b/src/app/modules/user/pages/clients/clients.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { CoreModule } from 'src/app/core/core.module'; +import { ClientsComponent } from './clients.component'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = [{ + path: '', + component: ClientsComponent +}]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CoreModule + ], + declarations: [ + ClientsComponent + ], + providers: [] + +}) + +export class ClientsModule { } diff --git a/src/app/modules/user/pages/users/users.component.html b/src/app/modules/user/pages/users/users.component.html new file mode 100644 index 0000000..67fc96a --- /dev/null +++ b/src/app/modules/user/pages/users/users.component.html @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/app/modules/user/pages/users/users.component.scss b/src/app/modules/user/pages/users/users.component.scss new file mode 100644 index 0000000..9d159c0 --- /dev/null +++ b/src/app/modules/user/pages/users/users.component.scss @@ -0,0 +1,73 @@ +@import 'angular'; +.w-table-user { + @include flexBox(flex, null, null, center, wrap); + &__img { + width: 30px; + height: 30px; + min-width: 30px; + min-height: 30px; + margin-right: 10px; + img { + width: 100%; + height: 100%; + border-radius: var(--b-radius-img); + } + @include bp-max(md) { + display: none; + } + } +} + +.w-table { + @include bp-max(md) { + .email, + .role { + display: none; + } + } + .checkbox { + height: 18px; + max-height: 18px; + display: block; + &__body { + padding: 2px; + } + } +} + +.users-field { + @include flexBox(flex, null, space-between, flex-end, null); + .w-btn { + margin: 10px; + } + .forms { + width: 100%; + } + + @include bp-max(xs) { + flex-direction: column; + align-items: center; + .w-btn { + margin-bottom: 20px; + width: 100%; + } + } +} + +.w-table__td.actions .material-icons { + transition: var(--transition); + &:hover { + color: var(--c-error); + } + & i + i { + margin-left: 15px; + } +} + +.users { + &__header { + @include text-default(0, 23px, 500, 20px, var(--c-text-primary)); + @include flexBox(flex, null, space-between, center, null); + border-radius: var(--b-radius); + } +} diff --git a/src/app/modules/user/pages/users/users.component.ts b/src/app/modules/user/pages/users/users.component.ts new file mode 100644 index 0000000..51279e4 --- /dev/null +++ b/src/app/modules/user/pages/users/users.component.ts @@ -0,0 +1,91 @@ +import { Component } from '@angular/core'; +import { FormService } from 'src/app/core/modules/form/form.service'; +import { FormInterface } from 'src/app/core/modules/form/interfaces/form.interface'; +import { TranslateService } from 'src/app/core/modules/translate/translate.service'; +import { AlertService, CoreService } from 'wacom'; +import { User } from '../../interfaces/user.interface'; +import { UserService } from '../../services/user.service'; + +@Component({ + selector: 'app-users', + templateUrl: './users.component.html', + styleUrls: ['./users.component.scss'] +}) +export class UsersComponent { + form: FormInterface = this._form.getForm('user'); + + config = { + create: (): void => { + this._form + .modal(this.form, { + label: 'Create', + click: (created: unknown, close: () => void) => { + this._us.create(created as User, { + alert: 'User has been created', + callback: close.bind(this) + }); + } + }) + .then(this._us.create.bind(this)); + }, + update: (doc: User): void => { + this._form.modal(this.form, [], doc).then((updated: User) => { + this._core.copy(updated, doc); + + this._us.update(doc, { + alert: 'User has been updated' + }); + }); + }, + delete: (user: User): void => { + this._alert.question({ + text: this._translate.translate( + 'Common.Are you sure you want to delete this user?' + ), + buttons: [ + { + text: this._translate.translate('Common.No') + }, + { + text: this._translate.translate('Common.Yes'), + callback: (): void => { + this._us.delete(user, { + name: 'admin', + alert: 'User has been deleted', + callback: () => { + // this.setUsers(); + } + }); + } + } + ] + }); + } + }; + + columns = ['name', 'email']; + + get roles(): string[] { + return this._us.roles; + } + + get users(): User[] { + return this._us.users; + } + + constructor( + private _translate: TranslateService, + private _us: UserService, + private _form: FormService, + private _alert: AlertService, + private _core: CoreService + ) { + for (const role of this._us.roles) { + this.columns.push(role); + } + } + + update(user: User): void { + this._us.updateAdmin(user); + } +} diff --git a/src/app/modules/user/pages/users/users.module.ts b/src/app/modules/user/pages/users/users.module.ts new file mode 100644 index 0000000..077807f --- /dev/null +++ b/src/app/modules/user/pages/users/users.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { CoreModule } from 'src/app/core/core.module'; +import { UsersComponent } from './users.component'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = [ + { + path: '', + component: UsersComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes), CoreModule], + declarations: [UsersComponent], + providers: [] +}) +export class UsersModule {} diff --git a/src/app/modules/user/selectors/user/user-selector.component.html b/src/app/modules/user/selectors/user/user-selector.component.html new file mode 100644 index 0000000..a3a7ef0 --- /dev/null +++ b/src/app/modules/user/selectors/user/user-selector.component.html @@ -0,0 +1,5 @@ + diff --git a/src/app/modules/user/selectors/user/user-selector.component.scss b/src/app/modules/user/selectors/user/user-selector.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/modules/user/selectors/user/user-selector.component.ts b/src/app/modules/user/selectors/user/user-selector.component.ts new file mode 100644 index 0000000..4404880 --- /dev/null +++ b/src/app/modules/user/selectors/user/user-selector.component.ts @@ -0,0 +1,31 @@ +import { + Component, + EventEmitter, + Input, + OnChanges, + Output, + SimpleChanges +} from '@angular/core'; +import { SelectModule } from 'src/app/core/modules/select/select.module'; +import { UserService } from 'src/app/modules/user/services/user.service'; + +@Component({ + selector: 'user-selector', + templateUrl: './user-selector.component.html', + styleUrls: ['./user-selector.component.scss'], + standalone: true, + imports: [SelectModule] +}) +export class SelectUserComponent implements OnChanges { + @Input() value: string; + + @Output() onChange = new EventEmitter(); + + constructor(public us: UserService) {} + + ngOnChanges(changes: SimpleChanges): void { + if (changes['value'] && !changes['value'].firstChange) { + this.value = changes['value'].currentValue; + } + } +} diff --git a/src/app/modules/user/services/user.service.ts b/src/app/modules/user/services/user.service.ts new file mode 100644 index 0000000..cfc50ec --- /dev/null +++ b/src/app/modules/user/services/user.service.ts @@ -0,0 +1,169 @@ +import { Injectable } from '@angular/core'; +import { + AlertService, + CoreService, + HttpService, + StoreService, + CrudService +} from 'wacom'; +import { User } from '../interfaces/user.interface'; +import { Router } from '@angular/router'; +import { environment } from 'src/environments/environment'; + +@Injectable({ + providedIn: 'root' +}) +export class UserService extends CrudService { + roles = ( + (environment as unknown as { roles: string[] }).roles || [] + ).concat(['admin']); + + employees = (environment as unknown as { roles: string[] }).roles || []; + + mode = ''; + + users: User[] = this.getDocs(); + + user: User = localStorage.getItem('waw_user') + ? JSON.parse(localStorage.getItem('waw_user') as string) + : this.new(); + + constructor( + _http: HttpService, + _store: StoreService, + _alert: AlertService, + _core: CoreService, + private _router: Router + ) { + super( + { + name: 'user' + }, + _http, + _store, + _alert, + _core + ); + + this.store = _store; + + this.http = _http; + + this.alert = _alert; + + this.core = _core; + + if (this.http.header('token')) { + this.fetch({}, { name: 'me' }).subscribe(this.setUser.bind(this)); + + this.get(); + } + + this.store.get('mode', (mode) => { + if (mode) { + this.setMode(mode); + } + }); + } + + setMode(mode = ''): void { + if (mode) { + this.store.set('mode', mode); + + (document.body.parentNode as HTMLElement).classList.add(mode); + } else { + this.store.remove('mode'); + + (document.body.parentNode as HTMLElement).classList.remove('dark'); + } + + this.mode = mode; + } + + setUser(user: User): void { + this.user = user; + + localStorage.setItem('waw_user', JSON.stringify(user)); + + this.core.complete('us.user'); + } + + role(role: string): boolean { + return !!(this.user?.is || {})[role]; + } + + updateMe(): void { + this.setUser(this.user); + + this.update(this.user); + } + + updateMeAfterWhile(): void { + this.setUser(this.user); + + this.updateAfterWhile(this.user); + } + + changePassword(oldPass: string, newPass: string): void { + if (this._changingPassword) return; + + this._changingPassword = true; + + this.http.post( + '/api/user/changePassword', + { + newPass: newPass, + oldPass: oldPass + }, + (resp: boolean) => { + this._changingPassword = false; + + if (resp) { + this.alert.info({ + text: 'Successfully changed password' + }); + } else { + this.alert.error({ + text: 'Incorrect current password' + }); + } + } + ); + } + + logout(): void { + this.user = this.new(); + + localStorage.removeItem('waw_user'); + + this._router.navigateByUrl('/sign'); + + this.http.remove('token'); + + setTimeout(() => { + location.reload(); + }, 100); + } + + updateAdmin(user: User): void { + this.update(user, { + name: 'admin' + }); + } + + deleteAdmin(user: User): void { + this.delete(user, { + name: 'admin' + }); + } + + private _changingPassword = false; + + private http: HttpService; + + private store: StoreService; + + private alert: AlertService; + + private core: CoreService; +} diff --git a/src/app/pages/guest/sign/sign.component.html b/src/app/pages/guest/sign/sign.component.html new file mode 100644 index 0000000..b51f17c --- /dev/null +++ b/src/app/pages/guest/sign/sign.component.html @@ -0,0 +1,29 @@ +
+
+
+ +
+
+
+ + dark_mode + + + light_mode + + + +
+
+
+
diff --git a/src/app/pages/guest/sign/sign.component.scss b/src/app/pages/guest/sign/sign.component.scss new file mode 100644 index 0000000..9d5882d --- /dev/null +++ b/src/app/pages/guest/sign/sign.component.scss @@ -0,0 +1,217 @@ +@import 'angular'; +@import '/src/scss/utils/vars'; + +:host { + position: fixed; + width: 100%; + height: 100%; + overflow-y: auto; + display: flex; + flex-direction: column; +} + +.auth-wrapper { + @include flexBox(flex, null, center, center, null); + background: var(--c-bg-primary); + flex-grow: 1; + padding: 20px; + transition: all 0.3s; +} + +.auth { + max-width: 340px; + width: 100%; + padding: 30px; + border-radius: $b-radius-card; + box-shadow: 0px 0px 6px var(--c-shadow); + background: var(--c-bg-secondary); + display: flex; + flex-flow: row wrap; + position: relative; + + span { + position: absolute; + right: 25px; + top: 25px; + z-index: 9; + cursor: pointer; + } + + @include bp-max(sm) { + padding: 25px; + flex-flow: column wrap; + } + + &__title { + font-size: $fs + 8px; + font-weight: $ff-bold; + color: var(--c-text-primary); + text-align: center; + margin-bottom: 15px; + + @include bp-max(sm) { + font-size: $fs + 2px; + } + } + + &__btn { + text-align: center; + margin-top: 30px; + + .w-btn { + margin: 0; + width: 100%; + } + } + + &__wrap { + display: flex; + flex-flow: row wrap; + align-items: center; + max-width: 880px; + width: 100%; + + @include bp-max(sm) { + padding: 25px; + flex-flow: column wrap; + } + } + + &__img { + flex: 0 0 50%; + max-width: 50%; + display: flex; + position: relative; + padding-right: 40px; + + span { + left: 50%; + transform: translate(-78%); + position: absolute; + font-size: 320px; + position: absolute; + opacity: 0; + cursor: pointer; + + @include bp-max(sm) { + font-size: 70px; + transform: translate(-50%); + } + } + + img { + max-width: 260px; + width: 100%; + object-fit: cover; + } + + svg { + max-width: 260px; + width: 100%; + height: 100%; + } + + @include bp-max(sm) { + max-width: 60px; + margin: 0 auto; + flex: 0 0 100%; + padding: 0 0 30px 0; + + svg { + height: 100%; + width: 100%; + } + } + } + + &__form { + width: 95%; + flex: 0 0 50%; + max-width: 50%; + padding-left: 40px; + display: flex; + justify-content: flex-end; + + @include bp-max(sm) { + flex: 0 0 100%; + max-width: 100%; + justify-content: center; + padding: 0; + } + } + + @include bp-max(sm) { + .form__title { + font-size: $fs - 2px; + } + } +} + +wform { + flex: 1 0; + + @include bp-max(sm) { + flex: 0 0 100%; + padding: 0; + } +} + +.w-forms { + position: relative; + + &__level { + top: 5px; + right: 5px; + position: absolute; + display: inline-block; + color: var(--c-text-secondary); + // font-size: calc(#{$fs} - 6px); + font-size: 22px; + line-height: calc(#{$fs} + 4px); + letter-spacing: $letter-spacing; + transition: $transition; + + &._sky { + color: $c-info; + } + + &._orange { + color: $c-warn; + } + + &._green { + color: $c-success; + } + } + + &__input { + padding-right: 35px; + } + + &__input-block { + position: relative; + } + + &__toggle { + display: flex; + position: absolute; + right: 10px; + top: 50%; + color: var(--c-placeholder); + transform: translateY(-50%); + cursor: pointer; + + i { + font-size: 21px; + } + } + + .icon-visibility { + color: var(--c-primary); + } +} +@media screen and (max-width: 768px) { + .auth__img { + display: none; + } +} diff --git a/src/app/pages/guest/sign/sign.component.ts b/src/app/pages/guest/sign/sign.component.ts new file mode 100644 index 0000000..5b64e53 --- /dev/null +++ b/src/app/pages/guest/sign/sign.component.ts @@ -0,0 +1,199 @@ +import { Component } from '@angular/core'; +import { AlertService, HashService, HttpService, UiService } from 'wacom'; +import { Router } from '@angular/router'; +import { FormInterface } from 'src/app/core/modules/form/interfaces/form.interface'; +import { FormService } from 'src/app/core/modules/form/form.service'; +import { TranslateService } from 'src/app/core/modules/translate/translate.service'; +import { UserService } from 'src/app/modules/user/services/user.service'; +import { User } from 'src/app/modules/user/interfaces/user.interface'; + +interface RespStatus { + email: string; + pass: string; +} + +@Component({ + templateUrl: './sign.component.html', + styleUrls: ['./sign.component.scss'] +}) +export class SignComponent { + form: FormInterface = this._form.getForm('sign', { + formId: 'sign', + title: 'Sign In / Sign Up', + components: [ + { + name: 'Email', + key: 'email', + focused: true, + required: true, + fields: [ + { + name: 'Placeholder', + value: 'Enter your email' + }, + { + name: 'Label', + value: 'Email' + } + ] + }, + { + name: 'Password', + key: 'password', + required: true, + fields: [ + { + name: 'Placeholder', + value: 'Enter your password' + }, + { + name: 'Label', + value: 'Password' + } + ] + }, + { + name: 'Number', + key: 'resetPin', + fields: [ + { + name: 'Placeholder', + value: 'Enter code from email' + }, + { + name: 'Label', + value: 'code' + } + ], + hidden: true + }, + { + name: 'Button', + fields: [ + { + name: 'Label', + value: "Let's go" + }, + { + name: 'Submit', + value: true + }, + { + name: 'Click', + value: (): void => { + this.submit(); + } + } + ] + } + ] + }); + + user = { + email: 'demo@webart.work', + password: 'asdasdasdasd', + resetPin: null + }; + + constructor( + public us: UserService, + public ui: UiService, + private _alert: AlertService, + private _http: HttpService, + private _hash: HashService, + private _router: Router, + private _form: FormService, + private _translate: TranslateService + ) {} + + submit(): void { + if (!this.form.components[2].hidden && this.user.resetPin) { + this.save(); + } else if (!this.user.email) { + this._alert.error({ + text: this._translate.translate('Sign.Enter your email') + }); + } + + if (!this.ui.valid(this.user.email)) { + this._alert.error({ + text: this._translate.translate('Sign.Enter proper email') + }); + } else if (!this.user.password) { + this._alert.error({ + text: this._translate.translate('Sign.Enter your password') + }); + } else { + this._hash.set('email', this.user.email); + + this._http.post( + '/api/user/status', + this.user, + (resp: RespStatus) => { + if (resp.email && resp.pass) { + this.login(); + } else if (resp.email) { + this.reset(); + } else { + this.sign(); + } + } + ); + } + } + + login(): void { + this._http.post('/api/user/login', this.user, this._set.bind(this)); + } + + sign(): void { + this._http.post('/api/user/sign', this.user, this._set.bind(this)); + } + + reset(): void { + this._http.post('/api/user/request', this.user, () => { + this.form.components[2].hidden = false; + }); + + this._alert.info({ + text: 'Mail will sent to your email' + }); + } + + save(): void { + this._http.post('/api/user/change', this.user, (resp: boolean) => { + if (resp) { + this._alert.info({ + text: 'Password successfully changed' + }); + } else { + this._alert.error({ + text: 'Wrong Code' + }); + } + + this.login(); + }); + } + + private _set = (user: User): void => { + if (user) { + localStorage.setItem('waw_user', JSON.stringify(user)); + + this._http.set( + 'token', + (user as unknown as { token: string }).token + ); + + this.us.setUser(user); + + this.us.get(); + + this._router.navigateByUrl('/profile'); + } else { + this._alert.error({ + text: 'Something went wrong' + }); + } + }; +} diff --git a/src/app/pages/guest/sign/sign.module.ts b/src/app/pages/guest/sign/sign.module.ts new file mode 100644 index 0000000..fe7a3b8 --- /dev/null +++ b/src/app/pages/guest/sign/sign.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { CoreModule } from 'src/app/core/core.module'; +import { SignComponent } from './sign.component'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = [ + { + path: '', + component: SignComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes), CoreModule], + declarations: [SignComponent], + providers: [] +}) +export class SignModule {} diff --git a/src/app/pages/user/profile/profile.component.html b/src/app/pages/user/profile/profile.component.html new file mode 100644 index 0000000..9898da9 --- /dev/null +++ b/src/app/pages/user/profile/profile.component.html @@ -0,0 +1,48 @@ +
+ +
+
+
+ +
+
+
+
+ + + +
+
+
diff --git a/src/app/pages/user/profile/profile.component.scss b/src/app/pages/user/profile/profile.component.scss new file mode 100644 index 0000000..f2c51a3 --- /dev/null +++ b/src/app/pages/user/profile/profile.component.scss @@ -0,0 +1,104 @@ +@import 'angular'; +@import '/src/scss/utils/vars'; + +:host { + width: 100%; + + wcard { + width: 100%; + // padding: 20px 260px 0px 20px; + transition: all 0.3s; + display: block; + } +} + +/* PROFILE STYLE */ +.container { + padding: unset; +} + +.profile { + &__header { + z-index: 9; + top: 20px; + position: absolute; + right: 30px; + @include text-default(0, 23px, 500, 20px, var(--c-text-primary)); + @include flexBox(flex, null, space-between, center, null); + border-radius: $b-radius; + } + + &__footer { + margin-top: 20px; + @include flexBox(flex, null, space-between, center, wrap); + + @include bp-max(sm) { + flex-direction: column; + align-items: center; + + .profile__logout { + order: 2; + margin-top: 20px; + } + } + } + + &__logout { + .w-btn { + margin: 0; + @include flexBox(flex, null, space-between, center, null); + } + + .material-icons { + margin-right: 10px; + } + } +} + +.imgClass { + height: 52px; + width: 52px; +} + +/* AVATAR PHOTO STYLE */ +.avatar { + border-radius: $b-radius-img; + border: 1px solid var(--c-border); + position: relative; + margin: 0 auto; + padding: 3px; + + &._profile { + width: 60px; + height: 60px; + } + + &__img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: $b-radius-img; + } + + &__upload { + cursor: pointer; + position: absolute; + right: 0px; + bottom: 0px; + width: 24px; + height: 24px; + border-radius: $b-radius-img; + background: var(--c-primary); + @include flexBox(flex, null, center, center, null); + transition: $transition; + } + + &__icon { + color: $c-white; + font-size: $fs; + } +} + +.profile__password { + cursor: pointer; +} diff --git a/src/app/pages/user/profile/profile.component.ts b/src/app/pages/user/profile/profile.component.ts new file mode 100644 index 0000000..5865264 --- /dev/null +++ b/src/app/pages/user/profile/profile.component.ts @@ -0,0 +1,159 @@ +import { FormInterface } from 'src/app/core/modules/form/interfaces/form.interface'; +import { UserService } from 'src/app/modules/user/services/user.service'; +import { User } from 'src/app/modules/user/interfaces/user.interface'; +import { FormService } from 'src/app/core/modules/form/form.service'; +import { environment } from 'src/environments/environment'; +import { Component } from '@angular/core'; +import { CoreService } from 'wacom'; + +interface ChangePassword { + oldPass: string; + newPass: string; +} + +@Component({ + selector: 'app-profile', + templateUrl: './profile.component.html', + styleUrls: ['./profile.component.scss'] +}) +export class ProfileComponent { + readonly url = environment.url; + + constructor( + private _form: FormService, + private _core: CoreService, + public us: UserService + ) { + this._core.onComplete('us.user').then(() => { + const user = {}; + + this._core.copy(this.us.user, user); + + this.user = user; + }); + } + + // Update user profile + formProfile: FormInterface = this._form.getForm('profile', { + formId: 'profile', + title: 'Profile Settings', + components: [ + { + name: 'Text', + key: 'name', + focused: true, + fields: [ + { + name: 'Placeholder', + value: 'Enter your name' + }, + { + name: 'Label', + value: 'Name' + } + ] + }, + { + name: 'Text', + key: 'phone', + fields: [ + { + name: 'Placeholder', + value: 'Enter your phone' + }, + { + name: 'Label', + value: 'Phone' + } + ] + }, + { + name: 'Text', + key: 'bio', + fields: [ + { + name: 'Placeholder', + value: 'Enter your bio' + }, + { + name: 'Label', + value: 'Bio' + }, + { + name: 'Textarea', + value: true + } + ] + } + ] + }); + + user: Record; + + update(): void { + this._core.copy(this.user, this.us.user); + + this.us.updateMe(); + } + + // Update user password + formPassword: FormInterface = this._form.getForm('change password', { + formId: 'change password', + title: 'Change password', + components: [ + { + name: 'Password', + key: 'oldPass', + focused: true, + fields: [ + { + name: 'Placeholder', + value: 'Enter your old password' + }, + { + name: 'Label', + value: 'Old Password' + } + ] + }, + { + name: 'Password', + key: 'newPass', + fields: [ + { + name: 'Placeholder', + value: 'Enter your new password' + }, + { + name: 'Label', + value: 'New Password' + } + ] + } + ] + }); + + changePassword(): void { + this._form + .modal(this.formPassword, { + label: 'Change', + click: (submition: unknown, close: () => void) => { + this.us.changePassword( + (submition as ChangePassword).oldPass, + (submition as ChangePassword).newPass + ); + + close(); + } + }) + .then((submition: ChangePassword) => { + this.us.changePassword(submition.oldPass, submition.newPass); + }); + } + + updateThumb(thumb: string | string[]): void { + this.us.user.thumb = Array.isArray(thumb) ? thumb[0] : thumb; + + this.us.updateMe(); + } +} diff --git a/src/app/pages/user/profile/profile.module.ts b/src/app/pages/user/profile/profile.module.ts new file mode 100644 index 0000000..665a399 --- /dev/null +++ b/src/app/pages/user/profile/profile.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { CoreModule } from 'src/app/core/core.module'; +import { ProfileComponent } from './profile.component'; +import { Routes, RouterModule } from '@angular/router'; +import { FileModule } from 'src/app/core/modules/file/file.module'; + +const routes: Routes = [ + { + path: '', + component: ProfileComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes), CoreModule, FileModule], + declarations: [ProfileComponent], + providers: [] +}) +export class ProfileModule {} diff --git a/src/assets/default.png b/src/assets/default.png new file mode 100644 index 0000000000000000000000000000000000000000..f7382955ed6e0416cff0c0b78f708734764f4ba3 GIT binary patch literal 8297 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 WcZ@i?LyX}70000!RX~754N%(;AVfCIVb?3< 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 literal 0 HcmV?d00001 diff --git a/src/fonts/3.woff2 b/src/fonts/3.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..d7c16dcb1d5bdeeb0285afdced18a7439eeab647 GIT binary patch literal 51692 zcmV)UK(N1ePew8T0RR910LknC4*&oF0(_hR0LhF10RR9100000000000000000000 z0000#Mn+Uk92$Wx8^tIb&vpi20Eli82nvVHV1~0Y3y@3z0X7081ECTGAO(^F2gMm% zmL`$}mU8Xolld8d+XevDZudFEg|E=^F4FLz=hAS~SH{}a@>no6!r87M(Bpky$rY9ohJRR7P>YT# z>Ie6IOJnc^5fB0S5On0td|K9X%hIlDLiiYdnXb3##8P~l2;7&FJC@>|+MIJ{eS8l- zvvVn>l(Nz@y1a^GdET2FEz=ZF8{V*sfRI;gO|*xB7Cu_%1a5AFKVH=3EG_gFEs3MC zmVczK=RH`jq#)26BEXa@q`}p}a4|In*ypHDngXV#=2`ywc4<@5VC2`s)tqy#N$@3WN9CD3zkd6fYLy$LueBv9;q+B_8AGUr&!tY@flw2BAqkE>M7Vh!Q;uDFV z8+z}4k<$)Z`A-B8|9>Pe0dd?s5lciw*;*WN#YjIjU#R#xzW<1<(|tAb4E`0s6-ame z|8}1j1HO^}?gl~ytD0{0!WvT3Nu9g2Iq5h&Eoc8iAS6f#Bta4+qPspTIj5xcK+_Ej^;p{jdE!C`+2@wCU(Gc6%N z2(aZ{Iq;tj(t0lAJ({Zn#wlqZA~;1k2L;O!3=SE8a}W#9e}CWG+WXx1Q?W+@3SvMK zn`VqrfYXCEHCO|-*gte?mj)?)m^9ic*eQL&sU&(67t*#fC|GYK@hT89%;OKi+&V(K z1*sm}$X>FsylspPHdZiVzrq5{}oY9&oct zDW#Nxs#C;o2itbz(wddn&7Cd)&K8g|8KK0fll+9+`v3F*2`T^o4*v!h-}wIhVaGVNEK7zRtegp! z^c>RbP7^7mIM)AYt1!d4LnA>;|B;CCIu`DPnzT`x_j>=@NtS9!hMo*X`2Xkro6b-? z)-w+%!?W&PdwKe^m+*df{uFy6mS}>3S^u{*r91xfcTUaL+_)*F^v6d^g_|I~5Eyi~ zTHSgz`>(Ftbm!8V5;wGRm4jM=W-$yay&}J$z;u=zOliE~K-vi|olq8d{#(AY`}Wah zQr`x;0%gPT)d_w(dv5O}JK?!uZ5EN>d8sa2kvM|5K}|zTLr|5EGgKECMtr zq9Mq>|9$`Z|4Fi2t|+;xx?PpKvpai&B=>Ynn&j$)I-H>jznrLh4tqUa6`&tQ;rAfR-)b3&EVlU>Mx_ues{_gUkfRGUlu^YjU4) zR@84EiZBILXpqoByp0h$AuLPi9*R&Q38A-)bf^l_rVkQ2jV~l^3uA3#q6F(6+7wpp zwtnor-u5cux6@pXd%U=P?N{3F!`BDuRDj&AJmCT)bd*~7sjc^SrfOf+Oi%%VVs<_& zRE#1W9&-0UXC+h*0F$=1PM{?efP92+rk1vn2*`Hczbo99x+Rtx9~ZoQUsvQ(Ie~IZ zayH;z!F&10qlk!v?tH)AU&)Z^W45o@8>->$+`JUU*?3W zGrv$V8C%@g2(cc_d=G!~O)zQS+eWEUf+fLhVs!E+b~njpULY?+HYe#GsKpcrT7G2H z{_lV4*!12u8soq>8$ZE9u@EE5?6nq~F!s zkDB^m{Kt%l4&KsAZM1Rn5F%WRL}{`WDpR8giYC&zVx=Ak6HXj1fCv-HIDibxAxwA* zAi@Mm(G1H0h%ljyLsAHExbUbTgoKKL4M2nmMKdhN1Bfu8Xolr@NO)9iLULMWgaxDX zfW)Haa4eb0m#U36P96{x0bmQ|hUOp?O{8+m`Y2#ZVlNLy= z5P{Tt15tU7qL#ju8A6{{9yUH62EGKLgCjdVF($Db9`mr0dwQDM@oZ+HH-}szD=>(PL3+0d)2_ChUPp7?IMxgf+>KE%-M zsnkXNCNvjQj&CR#)K#hj&nt^SzK^IY~p0 z`0?ES{rX{CUl>_2tRP9VdRcA%qHcIuUM|*~EeInhPEa(%aQ3o+t@lfxoGJ^;7Al2iz5RxI+MlbiWEvi3mca( z6k4uOs?^%UcfsIYR$Kjd_$!me=5Tq^1j7Ju3V^c!E&#X;;2MCN0NfPd)&O?|xI4go z0qzIz5P(O4x`Ond?`x+krDS}9zKGxRe#pNE@c+{L!=4uncsjY|Dv|Y-juOX&flvUldU5F`{+ImdT8=Y=^ zY8WZ0YG?~FEr+KkltvB1< zFi!KbZu_|G6^C>z$KUkLUfo*8nQ-!<%NSvl!R1ak*-BTnx;3vmV%(IO^Ovr_>DIek z_Xan*=`C(;J3AcdfX;Q?@MhlJYdFU7PJGH!ALg=-cI@My=!#BpHK)FoLykJ(z}XjG ze#4s|ypHR=UpIcUN4$;Oz2iIourP!W@vr(dzv;6+^rav9nw$bCche1257GgY#B{!} z?7Lo@)4P+N`IR53kML5|L?Lau)j#QhoVwDb?2y85=u!~e-h+dhK`5NySuLRHG@t_z z#mT_Ft+=QIl+r2%#&sO0DX%jnT(>XNVCo+lyY+Fplg7_EFV%2xP0fc{8eo?o(h<{F zP2_ZUGQ(AZh&n9;m*&^kX-QQYG78{?fz+uXDKH~!Dz>~7-)Y6Q3er}Jea+bt*BPDK ziccu$-1w!4O;q3vKm?t^TI*zem{`8i6ew!*TPw(k60kd_k8D96hEz^E1xmzGO^A*U zHps35)zlVvw~piv{cJsMujQ8ZlsML2MAY4f(83Ocql4Unng^XdR zJ-UqLvC+XS*?MF|@9=^_Kgdco`&212css9O28&h(dimKyV35bP|#hLh@6Rsx+i6-5Jbirn8u}?Bp;TT`)5{91`hlflOm^ z2gj0`e5u-KTCoE-bHY=AHzK z5CHY+NFay12FS?nIFMo8dmueJ0?6Xd1j_Z^JWzN6n7W=lP)_>Kfplwm3L?~TKzc0W zt%+qz^7c?os28X~6tuwxEI||==@W*Z)NnIYqHkl905_*6YL{)=aPE%VRUPL5#aVB9 zfCu;P%;G+vOa${jRvD6`S&CG|J=-n-D@$j6-|JVN(lK_E1J ze6O#5e*_9@md^q9nsR^~CdY)6?jfH5@Lo>*|K-9rbLm~{ht)z6FdV`-m0p$$0;~)< z+eN)_=$Hs-&84SXrKzOOLw#5H{?XN~e8QWiKx{u!@eaHEmz?+xzz*9Z-~bkboc)JD zuqHaPN(Qq5zx`#AutNCWx}y9`VAGlu(Zbi(=xqeIw;?$#O?k8%))1B+vgksot-fMi zjhE;EYjDVIDTZwGZx4RW#$d&dGZ?XzIQS-sO~Js=ScrWufJ2gTBiq6g0S8zUiX5-& zd+U*dP@39w6SH-J}3dMO|J-U&D z<)n5lXuz-;@(-A&1Y_W#C>Z2SL@7vz^lPGSg#p$4fa~y7$#|@9{oToSRaD&(@LT z&Ieit<3z>o$|C$rHU=}OpqZeibPUiTGEh_&HiV!|U^+~QnH@5rN~X*-*|TDPBLUxZ z27m>ok>kWmfDn-qq{&sHMvD_s5Cg;_mqLmvt)j}lP)j4NbkI#-v4$CAk^~E_u)z-d z9d*_fcRcnoD3}3e30H(78fj^f!{6^4Wl&^uBrNcl%xJ@5PE60o>D7+DO#u`y|4uu9 zj*V-VtJrXCZEPp(r|o)2_C)qh4iv`~91Wa8yFY^q=DLO}gsYS5ocoA9Z_ORf-OzF2 zvFE3_S9p*-`}~Sb-|HBPk~$9{!&@KId!Lcn`$7CG(LP7@RQDZ-=ir^y-2svwg7g%? zXW(=21^5zt1-=H~fN#Nf;Ct``_!0aBeg?mQU%_wSckl=J6Z{4K2LFKn;{QwR$J0BE zij*1{2tgpdVE{rA2dul>A0k+U2)qatpF|kGbMFx5YpSLGoQ<;ARtF%4grC!v-boN* zb=k{P!qCtM*1tnA=~!$xR@o^+9da2f3T?=N?(;$cs8Row3mZ+?8L{IgK$rvsB^q=a zwP*)P6m&%{g_ZWPFVxdYCw&bu#xx79vBO`^y5VtPc-kE~TY2nVe%V+Ns!ne(F*P%{ zuxro01BZ?rJ8|mFxeJ$WUAcB+X=QC=>u&p47rv_@2H@RwgH4=xcnvcQ!5~H1hs4Y! z1#HUeCBpbvaNyAl6(dEiGTZ5wX)AUu5@LX^%jX^YP!%;a(#HCTHQWRwI%lN&ILy%^sPc~sCr*)^<-7twV2B{g z%ONT`gUdTo!8hZ>jhj+#erDTpvqu9~9C-<}anj_g&}4_rTC>l&Ws*$+MU}N`YH6aK zE*58`i4rXKZ88=~L~nK@_X7_fL_kPHOhQUVPC*HVP(fkTa2i@V1d^Ts#mL0W!pg=z z9S=Gfy!$@j6UoO=lO$V-Ivoa0BHD2x4ADU>@+hpNiazy?23qN;mw|>EXPWs|*krfE z&bsEl=Rv_tVT(XSBb&!ji&jix7nk@3m&hcBkmA&&E&UnKVz$zTW1#cp*jz0jN;+h0 zLd9w{!^94wts_cUOn`E{Ad$-C3SB*Y14AQY6H_yD3rkxoYa69Xt-L`gQ)R?zBe;`Ns<$7SI4o zK%1|_B#>8zL?DWBicd&&wWLd@oGQ8sYj=!}-RaHbI}ff%uK2F9tjeyAuWqdMt{t!I zte27Wk-(;~VW>fa2?oGR!NSl%L44_7ih8hh9EZB45BLGgAXbDmfT7D41$iDH*^@WV8@Z0 zWjE3&5FUt0c(UIt?9d&Z@<}yGm_!p3FIXb&Z6cCg;@J7jNUS0HMM9HR@X86%MzAWu znRbE}(gJ~jAWmX4U&$rm6KhZir3)k(go`>QwVJ2Iq_sE#=`Ar0w;-v}e!w7^4* z61AsZ(4fbJ6?;xRnhU}uoszR9OiC#!(ZY9PiX~HIpcE#P6gVS!$siSaDPx!HG!=p_ z$sE;Cq}5ubmAjBw4#w0wM_mWC^0nr?D$VrTB#maAhEXG8+G^UGx10}jmi32p%$ufN ze%Yrz+AUp+n?gm%Oy<%6!?Kv6y8hy4V$eYbsPg`pK1td;%oeV>7qt4E6^H&id|`!( z6emfBT*WHXY0;_Quu1dX88masww$rGnRQmGL(&q6K^>kC|6uU0^+q%sI*|vZ{y85Hsa&Hn}d;@Puh*JWXau}{HaQcVianU0VM~q4U$dv-3ftbcm9gZwn zwPD+y_JKPwn_f)fdDMlo(g-tROb&BG&km*#r48{Dq#HKy`MTO(<+|ERy)q0Jn>Odl zSpzwc=^**%zygEdApLG|b=UyS!k88I&T2-j3oAEfiDgb`^KZFyeFf@)aB@C-9ZF%# zspF(D;n;Ch=yA9Lc|$nZZ+hFAyYCrnb9721my%10unB66t+6+ua*3Y8-zK_Xp5*K_858No%Rn3Rz^r9Np`8Xd`TGg;Z+Q-ykm zL?dr;NW;RX=FC*XZiNIJg-WtQ11ol6kmf@ej!uSXQ%<1`1-EXUl2sz1GGhkxCUg}h$_hc@w<_Y^P&6oE+yIVtU8sTTSIDOr~*d>M&|j+cwwk;0V@3@;c1>8X~`HM&BVvrGj` zL6SXx!>)q|2*j zYVxL%5UP!kbXl!ZsaF0ZZwXU5=8^5UW>FwdGW*RcqYiWBizLl3DeQNtlsZ=`S2jsf zvv2D{g-HA}4Xy(rM@_|>SB|gZD^Q4VF%qT8R;WykCLPoA9Io+ysOpOAu8QvZ9;^9D zlkeI{gJ`X%&OmCDv=2B{HEmW?IrF4-08{0ZA*H@k;y4{~qgaO)HDAKYi4?1skRGbm zt3zJNzB*auM=*N@>#Dw8NUX?A<-e=E8LI*l=RDZIuxb8N z(YzV1S+M4skI6Y7$oZcMKa%Tw2G^(DCF^?pG~$u&faZxMXAMicq^p&X;b!U`2n%&9 zhb_RY6?kz|Nkdo6hsdzkQl<6U!kA7w2k^%pf%H!xPy_)Z!LXoU6c`b)h|wI$NYWB? z(6r{C{DUxsfMvf&SzZHn{xxcO&8AWZv${wTkG2sZuOJV)#{-&b2*ByjVX(8BaE1AHxP z;f27v*UwbWd1ChuzoV8GT5GSPA)$e`n6-ihRW0xCs)KU@AF?36wP9SJ-!0LueW-fH< zvP*b-ck3;$(wb}33n?tEYS^erZ%s7WZ`aglAfZLW#F0m!fS9y zh#9IZ4reAv_;72hYkzJ@gQhK8^&iQ7EySJ=Ytl3@OZZ=I=bhyyNnT^M{DNM|lIc}z zgcA=^@0UMPVfCqNsHIkIClGxqHEU?;dFqMq!w>IInyjKqs^~3wDyU>wx`;mP;;pe$ z)!Q!?jYP!qCMP1EuijiwXBmUPjfOqmV>gE{F=oV*JUrN!V*8Hlnny#}6KOqrPe&cI z(8BG$SAEF(CX_S*1{Lo+4_)fJ*iCfx-GcP`uvNkO*>(0qhi8p6^GBSU>%Jt+CJb z^0xYg(XP!|X`@{`R}llB$WjNLbprv4W;S%)$5!;N;Tow?Acol5_7_71bLzJ0ohFD0*kofeUVPqH_q^POUV#1CKUpSEx5ft0GW9Lz-*xuSP zmfW%8AWl5M=W*|)%MG!(+Y8qloi#TY!!V`{N+cDM8cBnsMbaVZkqk&iB-8k7Tp7&c z>iC-iJTwBznMVx`BzgOwHs39=%yMghDVZ=>2K%@+SO@oD8(f29TpyeiV6j++Oaxi7 zOFTx(()a6IIGE+?}cL-{F>c1kD^*#35XFvPyZ~y+S>K&L!!VhH70l|d~ z26%ws@~f$SW)n@n9OGUNc80sqlJTqA4N?_=Nl;}&&( zoprGBJBO$#s2Qo53#yxX?!C!h{l5D~b@tU0@C6Z6fFAaRtJzyfAY}f}ASbokgR`a>UG*;nid6VE)dJy92#(40@WWObY=$VDpj|xPwS^qP6d@r zFSTxN7FAR;n>oxaE&of`Qb#=vG}1&fEwsXb2@5tHxbWZuAwY--F%qQ6kfT5e41x;O zBac0y>Mzsd@8a1U77gnsjO*LN9Il-hI5B3=%L}CVU&9Ecb z@=T{acKg_$IPe8{jXED#a?F5Y{<4dA{8EF3KtbYzf+(RPi>2hP{@oI4GfHc2+F+A) z);sQmRd}b=3Twd%^U-IaB1DQ3E>;}CGbBm&&35E`h;tM~tH^>p@`3UIY%&DE*dG9^ zmjG7w0KE7&0AKruz{bx2*QEQVc;0AfJg%+(F%%=!Y8sVsF8sVHxPSV9zM(9s@UmI; zTz!w!D(mc@lw|a+gb!fVTxF>A2>S=!VF6q9HHx$zPkKj$(hQwH7-k!sGOcNCV>)6z z;b1AWtDp(AG3}(z75k>_AVHY0*qybt4MHC@$8x>M!{{SFI{XOwo~){XylNCUWTOwJ z@;)lW2XccJu0BwVf0{H6%pmcB?!IQ6){KGZ*%Fu~Se&yd=&Q(cng+;=649zR1^CC1 zyeE4Wp;GG&qsN|fA%``#%VrJ5z!ah`=jo3o#FOUgQdHlCT?S!!#)*U)af#Yg#Gt$j z3}l&wkIpXW>p5S8xPykgiOO3K@l6+CZ!QY+9*HWVNBGfCZYHp|YU?oT9?!h7Q*bDZ z&!JrlSx}*@W=(okk3<>~s)1;Dbt03(7GRz7$xA$k{2~iNR+R)(6j&{VhV|gIW=N(p z{7}l5!q#b}z~4eckFe$^`vsIOm1f0<4nx!nIJHC|8q+3={yu5KxkbAAD5`R zym)oSZG2AWL(se&V?cBbAcS!SV@!Z!a!XIch6PN32WTp;yx2n(`w}l__lwl%SX}1?GhmGNXoqYn@%v z6sSRCPa0i>Ne{DOcEV~hpSNh%13g_9Ji1)nPLOcR1Lj5sBm?dHl}kEyZLVtIBH+`N zjTz=>8QX9|j~W_3P)CWqYmWE06N_Bq_U0O~Jd{yiNm1ku%AQk<> zMFrK*GOe7~eX2pPOrj4Uc}3*p9_|(XLXCc+v3?8Q`#-KeXvF%LMwzY#Jz&$vatJI2 z1ep#Mv$4m{OwbGraHzB6nlHcnU4QdCTqzpnYxz=TOS09ye%<&BGwWg6BN-2MgX8>u zt|#nB_Bt+gS?Wi6xV+UTe~$}2e{L^pw9F+*sjWW?I0lk^u20wVyRXct#vyEV0hB?f z&`-X&^B4I3#ouGgQ`QT<C_Ih$*o5*!keeedrFJvd;PA|!Z1 zxz#=$$0Jk~a;#UF;dI1V{rXXE=UzvHe!ti64@aZ1u{V*>&eA7Hy|P3EB4g~Z#bA^p z#|KJyo(9vxiE4L_sba25M5*zfiDVHQ;Oo|rBA4}3WE2A_(%T_#$7(@9km5J=F9TtP zBd&F7l~7tHFvw75ntI$iK7}24oT=e%A8G_CTZacg%)qCX*KU0zhW4MfQ2G-&ep+u@Qg8L7=V(?xcOGhP3Hglb?5X@6>4*7pDt!h2n+9^Q z`UB~^AeX;^|CQ5@a+K?kR<3rnb=MRt&3U5@9J2a7ZPVjMjKWR*{!BCgpc$BjO zdVS3y)~YIY^OGrGWQR38kluI2i+jv8HBM#h+nYyef%4A4k>@q*L4z7>Mx?3C2`+XW zy@xy~sOv#pC613Z32AOZ2~f-mCGlu(r5W^x;&Po#A$0qGtmTg$f060%XV7U~H2P6VE( zY3Cr0RX7q}E}u68e2=NP=4B&L0B#r#>4kf*LW7+P*jtPZ$1dbY6WXkreSlR4jv2#OHm!r{kpZ&Y%r3D6LJ zd(GFX=*r|e#BF!e25?x43^ECM!SotSbpU>0Y|0`g!NgeP5ROUMG02=@7@>ED0ie*r zY4tQ5B)Z{f_)3Rs875u9q@1KcnEaO2E+Acx-jQ?#6yf_aXexsqr+dRw z$aF$YLt)*W7v;5?_kfX->kCQeWF7s6JCC)~>{p~UWUMUlO>-1$_Yh=E(8ywmFARYgRO!!Bzeep`goN+C6O228GyUlsVT0t~bY`CCt#KK$UL{UJHf zUiNXnK&_X3cqq*M?GO4k4GtFer^(SAgZecv9E#oFy2wlPPmU zd3crS%|Tc7c|hw-C*3)4^hTU{xO?RwZL|EPHeWp}T>CW9t5&Q#Z>U?}Gio%I@$k6~ z>FiHrkPX6ooPE)eBX)}QF2(%sz03fiKt);4p0I)%t8A2{3>x6q(GoPWR3c&+;-D?+j^eBx3`KP-cH3~YlmVk%Byx#22(`g{beyF z6zY_|bikmg``Q$s1~UDhu$HHt^TEE)14x8{&5&qYQ{I9h_o(Lfe?+;heIBKo2mNr( zz^>v1-LxrqtX(NyBs=>e&Drlq)W^;UNb_9WW7H1(iBKp?OXx78BYXA>GIaT@cdL{= zzA?~pQ})fHU4C}B-F+3T*+u1KkA!JQ{{zxT<@EMG<}oF8<=gy-+Hv^^Kxtvq(g&{% z-gI*GcJtfd->iPny6-qO1m^mCk2mN&LYlu=qoe57PU_JRYkn;d9^PBFE67mXV@j3d zap@HBG-FyY^ih{pNe}SPYE?EA>VqTvMZE@fS8Oh|@7x&#*1WA)wbZ|J!_K|_#iPyf zqt%PFL=POuY$tIlm@o9g?hVy-Pjun?Tei2^=L|MRZ|fsdzXT|XBB#NFcJVzGY6!Z7 z*;zEIcVdr7v{SiIycdL+Fvdgf-D^V^DH+Yywj-dT|~G4#S{orp*GpjpdhXc$||5as4L^4O)%2j zGUHjIV@5wa!fk2{F~^gzFEKuPdU8}#FXzg1%~to@gtkjJt7<`!P}QLC@`nDME^03z zy}^h_Xe}_SMwU`o{}Uxp!|>MN3JNO;ncY$VFP^o*d>Dm5Z3k%kW?93h4DZ`Xyb9o$ zrH|dz4z}&hESZev?IOF+ZJCgF17Jh|*i-j^ofS1b?54SE&zI=Tx9%RlZpM>!%0w(l3kX9}_`UNoQ0{cd4C68c>L%WI2 zw=e91TN$PcvHw3Fn7=(B#P1Tz-x+F>H~0wNC-JGX4YP#~=`OHAbHAub_~o`Gcaipp zcc2UoX@JJ?%kYl+vv+>q{B!H|M#pql1xi(p38LklbIc*~g~_}G$G2{+X4C7%V^Hou z`%WDE3<*4QULZ3$Qzn%5_@amcZ6KgY#vRaCtS4y06Si2n1x!c>=Iu{pO5w?f8WY+%FDnMManjH)B9x;(8WFAPZ087nkr> zffk0~iI_1B!Wd>sakK}iE%@Up)!@Odtnklm7%A5inooST zJQ&M_x?`y1j4Rpqg|1JZdWGm(lZABKb82uop(!@N!@Ct2fiX-e&=@*lv}Vvc@z!?_ z0-r(YU>O7loLU$wHx{52(l(M9{0CP67cr>WW<3jSCGc|_VPF-)88llfU5%`Vbl@Nm z%tWXsjXJ2_oHw|=f-uxdhB@TMGkb6Xp$^BQ+2jufgj(6)@EofLxy(Hi#Q37^#F5jU zg-T8&(P%VwIZ9t!;zHPZJgGX>>-pn^LXM#KbZKE&p|oli^wcCRQkT=sx5kfNihxD= zAf&#Rg~LP10f_)D-EXw5fIOI8y1$hE&Dbcs2H1?!;ly;*6YQN70k`oUyAH*6f4a)(2E&{6(DHo(n_EwOz4=2)o?w`s)n;nFU6n|Q{hA4l3_a69cA zZs;h|`<74)6G~>h<&DyZbTwImP+JAEADhAq{_;Fwu5gU+2t;cV+qo%mU|y3eNhxVl z*&)Qx(n!wTlDj_|$aT*3TyA$Hr=f>X6)Dg$pjNh-^_CZ3W^T0fhaLnqEeODL43`$S z=ZbfkTi7Y^MRhuK#l{B$|NjUg*N&*m&Lld!(BHP~jes0Q7!1#uGq?w>GB&+sUWLi zh1*Q~IN}PNYrbg*zIT@zDDYXx?31W4Mvu-0CjR{0(|KCLokCO9KehWWNB<;&Ic1@j zZW<@e309=>JLCMVZ^De*EF)sIbE{4n8rDCj(J}w~8mMNUgVGVL(B{oN8~e>plhEPj z)rlmxlE8?Ikgt75IYxl})=(b4y7|P9luy%~^gZ5wuAkw*^O-cfxm0(E5OR+|MIn*s zGiBP+jr>^G-N9(7Kq^JzBrBAH^Qm#=N63@jSY&#niVF4TD;YE>X#ts`BsgxGW|Z=K zbvKF2Jz^B6MaGK478l60;XAq&f|D`;WV0c@BLC!HtsHg1f+I!u@}I_jR@VV}Cz*}1 z&+o#031_I&vG@K6Wl`dDk@XrvrM$e_Kn6Q%Qmf4!knG0hNNV7S_ zW`{gqs1OIA%kaSZV`Q%QD^vu)(~yY6h|pe&Vhhj&t(@|RoC-$e^?#l(9Be0;K^o!v zBW=i9XxFweu>Z)IfcC0sJR?w73e^1%@#mQO=n^&n07``!=8R5gKitF7zp>Ts=)Y;$ zn2eS}_^cBCo^bIw#0E}kNH_#&97YgvJjO)w9@jGi8G*o;3xQCbx2={Xm+)_^4D=0J zGvzC7k1w&I<38^;5bxz}5Rb+d3_aJ{Fb1W}ll5kZ3KQ7tGTwk0B} zvAnuhxv|_e0nrbi?XG)}Jo8-5-paMJXTI*{-<~*XDdL-=qLfMCS_+UO&Mgz6hi^&Z z>ZL=i?4%-0n0#j?&jl;=oSsl^Y=S8Y91^A}Ryt*lxA=Qi`WwnQ!2+F=iWcbIWk?q| z51YPN#psMMkir;(hWP9KYn2sND1PXLzL~9r`aw@L^1KdeF{thSk{K8qHlZ$NyrFx8 zV1mV`TOMikq;SZ!E!9PnY9#JDymy?)$J?j?6T zTo3Jk_vRFIVB$~jD$>hvakhO~ukfLAeEfmUOF;)l?uqx=oC1ZD^$AsnT_&^J`cn`s z8+3T>{*tQ|?fM1}ka_#%|4mbo-h!LoI*@`Wc2-rpzQWt`&lq1v5ZwZtY@u#-e>LyG z(fQ%L_Zn8}A z`cQogU0_*k<2}pW6)w%*!*~_0wjWlGab1G6;3nE>>!>FduOd1M1NV7QR|X8GDv9DU zL3sDavTNDuJrrTSZOOYxGRr3^w&7aW7Ekohsk1al#I~q-zDRdc$I09iyH##f8;F~Z zejjo9N2cdO1!IGg_8&2Ykp>Bsp~|siK!0%*bMk;o=P23X1%e z7LQotw5AT_l0|h6=RC`-RTgzBe%4zS>8sljn`XKw{W8Y5b8_hq9xIY7!1=Ywu~6M# z8xB6ixuBY;zZT{BfS+et*u}$2 z6GBLo#-Bz}slqi0GnbV0W~t68k!3a&Omb|khhwG39U~pB+*Dlu;K97yzrGqqJb*9% z5VyJJ2(o1}r#uiU|NntYZK%MceBKnk^fX=r8KKZ}`z8(A)W7x^u~KYsJ-W1_l_OxW z-1sPFvy+6!&^pyn>gmF19jzJFi_{12u^OZ~B^nW<9N&zc454k0P$fjff^Sg{JB4e+ zE&JA1fynEj@tWK4y$-^0QV8=7;?%lntEt3yC`zr%G!jO`5&**dOLPSF*}+p)&+*mQ zywq4bPT2^cSBj|M2zAcP?x^8ti>5LyQAn+B*Hpf?%QiuYG}>yegT}`)_aZB%rzvcA zzVRv$sEzjXMGzz75UZ|=s}cxND;^WKen4pb#4!QzrVMwvc`_M;4qix#bd+o89Z=S=rpY_ruM`mb!J21%FZ58haSTv?VD*&tvM9Gf~Y_E}lt9 zgtEy=XcMWrbCZuNu%;FSr`wq|ENF(7HCJ4ws$C^7ZF3{HKCSEII;ftF0K2a<`8nppGacC>G1>83HuEZCIpu=)X0f|{wP3?(+w#1m*-R6UQ z1?M^BjMQEp@A&xYo41)b`a{D!&lWA`*RVUCD#OMe z*Z)Cl-079fY1Ui8PuObgy_g_xQM0WMHtgw8Kxs=23UfhHvRr6`NFI6Z(x=Mcuc&~A zZJ`^E<#j<@Q!N~MZmkv;+!kIgF1G%{E?47>*<5!|FYcV-60T?SVM;bw&MP9UBLeI0 z7KP&$-zFKK0MIf8FxIl~R?l}VNj3BydQ4pfxH9ijcuXVuVLhBUx`mw#gB&;`DP`gm ziy9lG!RXyq8m5USZ;fjqsnqap6E^D&Oqz2@DFD~WW|HJFZ(Bkv9XP$|Hjf-6!4m?) zm`s>#MP;xi$JK@))ya4{m+pbGGqtQuP6V%1;3?l*s`~heZq2X|vSqjeubK?wpnZ@Z zt@y!!?!-Cz>Q4K7Q8451212EJ_@%LCr3Y4C5TaLNyE#K@^$;qL7hdTVopY!vX5--n z=Lr;#c_0?CAe097(!3KpjImwUMu#*v&f6Jeo$@Uj$jsBK(c5h;mHQuvQ`k44!Ww&E zUKi(DhaUceg`xAKutm4mc|mZn`|kS4Wd1Qs&#=h?rLL;EzGDQ=P)m0%@lX^Or_c6l z$E`Js0rsua4!PAvmV~1Y{^#0s4vwOAHuY3YwB-`>VkrInm?yQ5Ka|tDa4a{xvD!kJ+(^0>%4%(+KyO3>bLQ*R zW;S)B72&8bB`4Eq{RxUL)_8Z%y z#wz9IwB%CXR#b4fn2!niJh}7OktVI}bfjW}f1T5w9{3rhX;J!(qv?XYDR32CyJ;X# ziyFakWee6q+c9YfN766py-S_^Pwtc<@tj`Xg)dJ4r=>=Mwif<>a4T<1lx=yDBDT1h z|M~26L$szmuo~Q~#~J0XdXDo&z|!1P2I+E|C4{rD1Ud6}wJg=GQ!72Tk`16q6L(`2B{Hksrl5D~UemsTO|g0>B!vdXY$0&A2&5993(ZHrpoF5TK_ zK|T+I0(Gh5BAW1;GJ>{1?0h2lxI5>s$*Xbgg4&_Hcte!emw`FNnN3@@gX4)*RIM?k zYGE#y@~EFOLrdnIcy%|-E9BY}lQ9e8%M6O08M2c_AEjjXlx2I|WuZza|11I!Rf++j zSL@2N!sAqshYJ*iW$O6JMJJBp@KlrDkXoba^}Tk^B)X8pTyCl3(5^P?4xuyh#~eFn zVk#t__KaIZMe^3)oFlE*`55^>(?a8S5J4(J@Y!+>Z~>iYQJ_;Y`_Ag{2t&k~U|(j! zVACU1#87u6UX_S=e^R~x72jIBF4F#8LQt+@lq$U5i*mm zA8bJ+lY3gay|nJ9|4F$c_ErZFQ~Utd0}E~ zh>M~aQJ~>ERgZu&Or?xuOb_`8Fu7RhtKkBxe*^`esnuZ7++;rnE6$R;KqbV_SM8N& zM}rLUizRgGs^;5tF=t*zpo8qg6^QM)e%QT_o>)(oT(QgHjy37wThMdmHB35)rJLbS zL3yOF+JdeQKzpoY%F7$$4v;)8x~0gxjD5x5NH-Z%n}29hZufUGlC2(9i%Lv3o>K7DjHKM93YV`AYA7Fec#=~(mhog> z;^j_`Zu`KCr(v?2Si*jVqQdPh7&z6HBCF}gMgmjzyi<uMJ8G9V7?jq*Z1g zMfz6Q%7UM5R+BQ|n^RxD^04MxkjU-Ee zl@MJsVtfu&l%9ZE5kGMTG=hPsyH$AJ>i@$0uYxumbutBm%n zAPQnCk&D2VDBY8{mq@8#sWuH8Q!t{a#<+NvXslZ|w@~2iqg2hfDRVt6Lxz75f{2yE zh9}F*DM=?HtrT3LV#@(zt+Uy1u-Ktu@Zd3UEeN{WTZQQwZKx#J= zUHY3%|1!m!`K+4?Ns4^+HBpV)Eb;4Cy;T@v-Mz)8s&*M)|K-qY91axhqNn4*&(pW< zP~K9kEBgLoTEu11l`rk7dekw@Shh_!X|T+6@qjQ7E6^v;UUA2>5$`o6n-K?_EsnnS zlUr2B?zyEK4Lh!wzTKz_D$MRw19jl`IUJ>;%f{osJ;@GY3!S0TjjO!PK!#+%i7xcihzUXBBTOIa9jSU41 zxOzX+(q@^>#CepYLRXDQkNx*l1gzPDq6_}^ToR>6<~&TYa6zBeXyCE_pW!coH8Y_y z8Y``cV9_*ZXuCcp)N=zhcjq8{Vi;kPnMGatrgKlbNoX&-_k?}3+kPF$CDSjxoCA*L zHDljOI+b!3ooT6zMsD%&hCBwPeu4)vs1$Z#VjvWkSGm+{2KzUWG2)E{e{8hzM!1t# z{<0E+B<^@}r(07H3#gAxTgO{_YfC|U6j9WkYUJ<=A850&(T&2&q=$;ql!ZDp)D71p zV4P!}w67h5b0Q%7R^bBViaz6QD1Qm;r(Oh0(=ZX7>vm?nawqd?*%0l-rXi-r+b-&I zMB9bz8I2_oa-HC~$59J%4wf96PUoU?Z&)rsSf0h3xx;-#$!VP;y1sQS0`bCRw#vv5 zcCS8#hSd1WX14XgBaMz0coGXpu^-;{CU>QrMY`|mo1Y5buuA~elTM#GdhgmX*^a|- z_+4@E=g(?7DP`NKIagtt&!BQx9t?a9tRGF3tH3`XK0?@5Zx5xJn%-a_42Vy8-L@GX z4Pg17Kd;vIQYCgZOs@?~x;_#&45nfoDSyYPc z91do`k^52!mhtJiWA#z0zv6kgQOd&dj-)K@7u|8MHzYip!a35>-X^u)UURojG)z?= zyjlC~6CLgK>#vlng>Z27-PNG`UW;zJT{DB$<;SZ~B?Yd~Z}!ZE4L=|1_#N&}=Fv}Q zd|QKI?B0zJRcL8Fy#a^%9%VfyZEW5w36-N8&q6N=vIjHP*ZIvvG2cJEvssT*CE@?M zKQa!#I{hjkdpAEelL+e>L9R~1bD_KcQ6wQ>hQp?vX~?M~J_hW+dn1|^R2~z;XtJosaGP6z05U@&^1f`+FNn_ke%Q=70GX{#L?QZzL&Z?0=Xj0d8q?Bx2`q3 z;ptbCteHjS*UYc}9H!0vS@d;#3jQR)7LyzApX~UzjuJl&+EE{vpy|t z{y)TZ_iqkbzF$YT@9*unE4%-ZFK1x*_fE|~Smm1YKn;WmAdG#^)c#D?+ue~t2;VnO zFp$GBO1Z$+>W+Y6WXV)9X_8^)0bixe1L5(%aP?c^_J1?wd2@sh!!T}Q*;mt!VJoFc zg)mVR;RrO?xw3F4;b*AHEo(e?G3#hXAEhLXeUqcT6ALN(bIn7@r`trwZD@5q$|9cdF zP6sBw^NBahJ@%@PcjHF5Ym5(nG7}P6+m>{yuc;qIOb8dEA~8e^t6YfJBvRYClhJ=n=pXl(cnQYtAq5 z=5Pp4t6X7cwU|`-v2<(YD)-H=ucnS@H~Z;B68C5jtlAS~S&dwc zWZQbY6`OLbHkEO>&Q-`&2)3=yTfUiVyBP=)uD&a~bDbYJ0n{An{~1i3X}N-@G;*C8g4F>Vr1@^l-m$FEgzh?mkB|{M7eNw69be7+y8YlJ zm~7gGwwQ(r)(r?kWhusDWc!M+J^r^mud ztwIKoh)kweK^L!3l3VaD zI)Jt-s*-4OaWYqEj*orJJ(?2eMQ@759|_x(qF_RRhptTeFQ2b;9HcUK2+88jB92b* znB)UDSYUDotVU#6Sr*}8ED?mwX(+4GS2u|aRUN{`TU&dorc0z3Y8tn-_V6<5O7Xs? zo{oLltR2F>mY;s=*n&rEc+FN0&&Xq?dS0-=l{pCI6jx zt7I)%U!z>ot}1)*A9%U`=BnZ9NGW%8vXKk^Tfy~x`!06{kv|2JKkw(Er4H_)C}m!s zxHj0EoqGW$;3{2&1XNu67^d(NGzDY>}Et%o-*J52qxsys6)Gr)dMYSgGs_e>8k_19B4*tf_y( zZXEow@k_%K_ES#du5X*ZH2~A8_tRe$UsujH?4j+Ufzu>4ewCH{*W-2p!1SzxxdrIC+C2M(eul=$Bg%bUwW-0YT1jj)!SuBddvCCu}myyL}QB00g20l8sKqC5nEj~)6 z;!CSABpTyiwkqx@%*`u8>_!HQX=HL7?*&dHbEuKUamlKZyG7Y>)%@4BR9=pquQmpn*o? z$V_S}KhLs2ryHfyHKTRuHuHQOAGQwEmoh0#;V>)){5z@Z<=2zBSaUexZVwB0AevJk z6A^<>kjr^S)xZ$$?A|Id^!8k(p%q%E!y34pk5<(HrS=u0e=XNz3m=S#iKJOd+aomS z%_wRx8-)2gif=8nw+JLBzs;JGglx_?N6+}jHZo~aM4Icb&fBU04NecN9=Y-JFN$}H zlUG)gz^w6ZG6z7EmlDaPV@f&|&3V-ebZ@>oEjivKje)_Qh^MYHOgdm(tKeIzdL1!J zr|Fk8q+2YDwfZGA8nvW3gT#y(Te%LUl5MA2Su8^<)2{UTB3kg#nK?>D4(Ra3lipQT zQRoY|f}OXSR}yG6R|YgD*iSBJ_qz8NpfIA3+?}oid$??14z9tSb@}GJ6}(3!;wY?B z2kPG8@HBJgJ@@gh$xVuhSpqWBstV;pg|>WypTqviW%`4=Z=EBoTRfI4(1%)4@NQSw zysP!Pu+L;8YfIgjmO`0%lw+(XkNxJCqE-pEJKEARQNzUwm#AmRJ8 z&rs)%;;l8ueERZdE2gVUPM1xB2)7sPmQ+obOjn;aJ8geD6F}}?SzFYv|hA{>R7s!h_ zVBE`@r<-rAIIgi<2yroMe7K>R`z!d5qhgB!xN-z65CcG&HY+lF&*|PXmJB>3lMQStHeB49 zUBw;Y@!H(U&k=;fYc@M*0P(8SP;mF7b(Ojte$gX z&jr%444bH02i{cp=4q=>&cw-1&v-m?Jr4QitjDLXN6B9Q)avP<urjX*ETJ-=L0Hkm(H2XDxK!eR@k z2n!4Lxy||J2f;jX(~R9o>(J@Zx}XaeBaRcpKPR6Tk<#`$=*w3s6$zNVT^o_(TS=<=VhDh@g@w$Q=dnx!JzCrY69Z_ay;utVj_jca?@Z{KbV zfH^XRhmuvLRRejyf3UZ|8eF_fh#`oOOO|8gvtPBXeAPuVLPk%&;)bgLTYl?-Z ziqxkrRs`c-{48?EPjxH7%l78)6#&mXaca~hrsB!Q!pQt(sUeQUmcjY%%@c(v0~{S#a>o-0?PLO|5r^cuP8KluJ64Wp9s2M{bva--5T*Pm06s z+O~N!2D2>$hx0kNZUY;Ohk}Q7h_M;Cv;MUwID)n(Lw2J2Lf|gUW&?+FDj2tS|3IrV z$H&|t)ZXuI>VS5R`1QE@!T7A!?<9m0!|L-8z?SGmoyrZv zb#;vrUF-V`9H>Q+fHDgeQ)7;q2}p??AOLiBsUgB`4x1n6`N34b1{*f@R|B-(qCoPlw7}M?E{T!JaVnK;C&gf~^bF=KV7N$Qp!hSHD*s6x;@Z$s9VH)riACuzaj z6DnvO5C(3wsHoTXcqV6;O`l&(x&pn}6tJKN;!7(<(e$JpaAvgaC9&ob!BkaUsE?wy zJA0jq7SVZwPc&Xp{_G!8IeZ+DYRl z_a*LDWMdRGYh+HPD3S&hJs}IbA)d5S7)|RMaJ1x5*Ptmnp#zEu?GIhWBIYpuXI+Gk z+O;y@ECnz7qia%lEoV(aS3d~Vag4G`Q3PB|muMIDNBO&bnQfH*R>!wNJuMW$?~?lK z37z&mF5)$+QurwuE#NIM2M{Fz!zslh>Hp;cLzKZ#fHZ^nZD7a^conu)jJ1lEtnVBYmh($jlPf^OAHhL(4Iu=D8&`EPx(ID9Z%ZAf-D4KQs zO08!>49h*6Ca=&ob}5LNHZJomkKFJm%fs?tfY(?t*kKu`0m^QME_vU28}@wr_y8Ud z=E)F<#bdixk9liC++O(&$W2=9KyZA2*1_;C1z+g!Xj_rrwJK{#Iyy#8OgI1*siHIb zDt%|U@3~WKFbAc?uN~zvm%uhUvqWXxe6Z>Z%{J2m%~~{dN_aH={Pzd2WT&G*=G2r_ zJ_@Z03|vA@@<-X0T}uk56sZbh;McQ|^x*TO)O>RRsOH-?!Pkx3ShU>|iG9yDmLRsB zNZBU#Qq3I4&F8(EsA6EbSMpFrr90f4EOH&truC%)0PKH3ibxg*Qj!w=Y^TmNy@Xpf zb6tqIB)K@C7MJ99xZ6uYi5Q~NXR`%E9m(R5mBY!McjH*hk!NKJ^8r0M2 zNP6&PTv9BLoA`W)&*k+d^v8^C#Y^_nU$&`y*$%un_zT#g(5dHc0hSx5gUerv{aSB2 zHPL|1UwHncx~gT8WwJTos5NMw5+px`!?mXxJnru`y;F8u=eFWDfdz_&KIPg}JY!v< zyj{XUd2!kZy=S|NjiWGZhwTF6)Z?z%vy(T%AsW1L`%ZMDNfzI33Pj`%RIQhw*MLDU zPggdeP6?y|WeifIV$r99IR~`Y{A2TXwMwqGa$o20P%$Se6S~42*w-1g$rRR&+GF*% zSb#+9RT`=0l9HQ@1^8*?UH?Xm!J_+Z0evv&RG9_;>lc6!(!vU1yjh@SNu;_lQGzt4 z2}>@w0k*)6ZO11FdP?Y6bLkM!@v3%+5IC~=|X?BQqafXy~VG-;f$ypVI=wtvyeQmi-=5hFUMX+q(vM4hoON}qrr z*KdY68Jn84*hn~VL`!1nwgp4&^G8-yf|1$u%TSulSW^CqeCVV#`E{s4iS0wN-AoG5 z?!FY--BoVlljshdIl6=D*h;Fs8={^$-4VmVS<;4A`; z#UoKb0UDC>b&crh24y-FHy1jz4yVC73>)~6Qm+u|FsVYT76HDp?-QE+T2y!1>j^}h zl_jEi&GpT#WBtY@(%?UMrABt^wJaQu4ToqYVK$7JrO>H0{q!%39;8aVBRSY5!hRPK z8pQ}?XK+mrIAy@MNdat^wS|vb5*p?;QN%&2+|h^_Nx8y`E49GgW@zQp z6<~-J|EDH(hW+c0;LCQ5lon!y<1rnBSVA4{rQ@`~81P&=x@>9I4G7 zKbVAqP_0viXq~746>b+8nEMma;6Q4!BR+2t9R=lgvkV6j^cjr75S1`t1M^Xkl(+30rKD;*638|st`9<6QaAJm860KRUiKQN!=mlH1Mh+4hCIZqyb zy)~ej$<}eFM28h+3cizONn|cA*DXz~mDV&C5W)e!Jj9cP&=8o=n@iN86om>Xl_CnK zkMXh^_()7BO_D}!c2HoRsKW*FTG(}-7u!QbSPnm zK@D4wF(9QfC=(k*kYRw0`m0 zZOu+ClNk=uhLqDYZhNN4FX3Z+wox!WSsu!C2I854=sS}A zgVa)5M|V2oo3zX|RYmk!2>!&^WR}zYPF$W!OI7+T=^smFNxdp9m8WoxJd={D zh?Mqa9icr*1Q6X{`HO;QlzjvFd|eXPgqGe=auNgf9Oh41s&UVh8?Vde5H5+IXyx(|r&YJTZZsmwS z#X?<(?tRvj$H3gVMfmGS{0vOFjnIQwp9%));q}0K=dU9PnGyHY>=d=bvCKz5c!;7M z842cdR>9!{PiEj~OefG7|NH;qg{^X?St@0l;2bdjZwWH1c?Z^CSj0>`og6x0ua=mf|uKaHa|! zy)Lgg6AsjNlePR5ga1EdE5i<&F8%9j&fq$Za+l5#TMk0Yl^VsI=2EXZZVP1Qwptn+ zI+@k;?~p)Y`pzP0HrJN1`PrYs@b_#VxHN|_!s`8Kwwq}Lw1+Q^EOk!dIU z*8C2jk-Lj3Fb=$1?gFcb#@9XRq{QJRd$KeTwKwf5v5wz{{JGO^#Z)LovIJ_G^VV-_X9693@t}0@lWT zdO?@w*50ZE3kD4wOZfL)d%2M>tP5P%Ucq`W0{P;piWbkMx^dP_@!Wc(R?DB2oCgYs z?%2sMX8|Acwr5a`&*w~qj!*<5nE@~(Badw@{raqmoc1b^?8XSer z{hCtgbgF)0R`7DKGNl91>E4O5*gk-;(MmjJr`D}I;i&t!m>YO+-y-aRjPyaWy6&5K z=o`0i&LJ^ZtdF)Jk$(R;=Rix4&CAqQbFClEVVx)eM?l3`c%VB}XzOobb2!o(P-qeo z?(6i4KT}xJe?sk<4VVqpWo6X{bD%!E4y){3&$$8a&qb^Bo%maivVQWKF{9yI^P^kE zse14cYiWgjc!FAK?yB>uBtJ@1y;+bLmr5pcUCA{i;z_NGly zXvH(X+~#i6d%1Rbn47)XKeyl8y3fn?gr`+4`BQqqtILlZ0`FMuS2$PXiVm;eYxjD+ znzo{%%Q%q>=@wrLV8-P?(@3DYzM$H2J(X`S_&)!a_~_3Eular9-!1+E-_RzldS1br z8ZgWXEX&DK_O)Ld6k-mnz4x=9=I#4W;;L*>aL-W15pqEJ*87da%WN;{kjl1S1{%}!JL*}6rfhB;rSqb7Z=x@ergocj zn?P-QrCUVx^~@hw_(Y_h$I-*BS&S4D95$t5wjp5cX@@Yq2|9%L@ebX80WMXth~b_v zGn@|_z2H`d}*1 z{nDq9Jcd@^$l{xMzQa@`r1L&4qQD3#o~EG$b$6D>|M53_%|Ly9e~s^}t$7C!*DL3O zVrREQgaf%U!>V!nQw>sbH-*Y#?$nthoN=S6Kt7BTIjCrMjC9yTPJ74^IizTIigen7 zPVjBmyR%#0&%K}9S~*h2=mE}0Z_mD+-Lf*bGPfb(KZ%o#e*aU49Qz2bKJx^|M2=f+p8Y)x;?||YgVtra)s}=G31LSq2rcU5ZA-Fkz^~Tjf#4l>E zijV@K$_;KR1tl$HG~UQu6AH;uEu#EVy@l65{VtHJ=;ZgF%N}^q$;%# zacIygXWz;ONbXCS#&dN3g`9@rlK4StzCc1PyPj&Xix5d5#zSL69U+x;tXehq()Zc>eZ#mdzm&`3^&5gL z4f3oTc7q$}fj+e*IV#R2;N#;1=kfHq3wbh5li0=Og>Z&mKXBTB_uyUPOY$9@Ci|5| zr}fI?fXi?x$nG-WINUNrr%U-LYbWs@4cJ&AJN1%#@12{$U=00x<0{}H*xp7m_peHD ztl8P$%t==XfxdtRB!I4MX{@Jh1)ISz+ZNb(FdesR0^m^to`IABI?1vM{>3uMW98Ix z0Z+3hgfy2y!zNZ+?ou)TO^=$6*A_vO2XjPi#AE+O{SgvE!Gwa)GGzG`Bf zJJPMKL7+~_u7vYJJtxj7`ZhFif`xAR!*TsAByLqQDUPVEq{0qR0D<6dZk9lee9Y{53TzF&>6uZ)3wrF{Tcr!YX<-c zReG_3idwgj9YTvdsoRXK=px&U^@B#Trmg|1U3{@Gg_}vCcHYBnd*dvdYHbPt zOwP?{@Fr|iR&1`&e9bPFQ*L#hu*+LD7r_r-=!Uu$2wu1pJi#UY=6?jY5fosCypMly zz6*Xo+Q+S__K^-qOaxrUEYK%+b}IB(2)ca32!5O5T@C66)Reqx(!08^YR&3?Wtw*x zjt_3vI)7QQbAY*~y)XVC>4#bL&C3=RW!1aQ`6E7u+`E=Usz#~doqYGjIXklM@d7qN z;Pi52qVGGE-mw`fW-UDopa1FoSLZ9Y3$(M#N`&98Gk*QAFF!jk+~(@Wm&nB5RmjN) zN6%j_-PoHZm#cEx2X~Qjf$&a#{^BC_wH=Fy#e2MTE^Kl3_`PmdkF)V;;1ti4tdtz~ z{vkVe{FwdJHW&A3Kueg(d3R~@PJQ|6BJ+Hb6%74n=uo)YnM`8G%)@IHUPq{(vm4`JG=M?*0d zW8G@VvjI#l`gKxu_PTd@?|v@7aY>}pzFLu39pX0klX-^nG8AZdUsYaT3!;HWrO8>C z`6hBmwifIReS_V6l{=X;egX`n?EYA%_mi-lS_8*x!M z)A7e=f0XjzYRah=sG&VM#WE_&Qt5NBq)mf~Q?t=m?%>3=0!4J(>>XOb6M1m=+!F!Y z>>#_qrtrh7=UICx;Z90#Gy0`5;e^$rF;4tZkXg?-(Qy*F96Ff_3H>(ZH{T8gFpFR-AX~fwbZA5YTZT3^-}T>iX#Kk1F}3 z$vm{HDOkz9*B&c&?&O=1(FY0hBH3eS<`rGtCWI6hHi4-r2X5JLoKK+H?67&4Y^{Ky zmcbeKFJwjd~Xbo57ZK>$$EUTqQH;rzg3oBfLhM_pckJeLZ}0;`*_3M~KUY^KoXarm?9; zqhavXZW|7oyn{DysP&6~*+Ptll|M=HpZY>58V5zBbuRUD@i+b^k5?`jzYpynEd#{l z)#t`!8rw&~Z=<>gKDWDkPpoh4EJ%cRXd_xtdp~wzDJ>OqbwTwb#be=(i0e+B_~q4$ z_cb)yx<*psy$3TD&PkOxJCPIIQx?sSYh{#Z*o*^;Q!1H+{t>B;%F?<@19xgbmDVW5 z5I15lwO@P=(8(Yfho2*RK>uDx^?59rCyNf4QFWHxw$7q}G;7Rn>b*eo5uT3wV=u#H z_O`bc_&btSlQ)KvE2Q*BXxf;sd7RnOr$9Q5=A!hg!Wtlx&KuySp|0t@?N2X25?8k4 zdU{|T)#BEOT!XCoOR!K<4O*upxhjTg)MDVyj|hXcg82vH0TJ7NXaJvKgL(M?aG`E% z=UszLwp!wBR8e{*V$mpd^D#Sw9%~q40%5MYiOL6Y+@gsITEnZ#6`TXNwPPz=R_POQ zgR;`@Y`#Uj-#qbil)gzS%bOsonNV6eN28Z8lCpM#1-jDN(4H1zN`}SJ0-=?;6L`Fc zrW3-caf0d20?*+j1nY8gn*jRQ<*L?yE_w)T*)qAYnfmstx341?Fi=|yp-5CA%HVoQ zE-pb^E;~>&5TjX(8Z8P4Yn`WV{Kv9e&4`(edXLRs;b<`Sim(*fp_e`mKV>24J{ovM zD9|cup0F^VR;x%QcWzx|=X8VH+FR!%C{>`&B7s3Z+8@4I+}ai08|kkQR08gq*YLUy z-O9xY%4)T6?GE+I(jqN=3j?ATd|hl+o4||_P5z-s>X4Ryh3gmsu}M^p8CGz+r^%dX z!ZUUvDH8OE7liEAa|>0+s|gv`6Q$B)&{whc@bP8|CH- zc1d&`1AaHh0(;ol$4e@?5vGC?X1l^BJ}E1#0Q&xu)s?$~U9S4)(lJb-*sOZMEN>!q zrmtq%@v@@4Y%Id$4qLfa`YgYKaM?#td_J(V6f~zhrd=O)m$?-^*LBeWS=g{5H{~@> zVq=+Nm|W3VuxFB?j`nb5LEgS?e>vtw9vC|#l5*` zsq3i?eu&~FvYZ3MSC^{aoDUV)lJi-s4lDoO?|ej*VPnwu7P@viI>~WL<4e74%!&p` z*a&ncHPL(hhJOVvn;ZZ-r8^fM{;8QDapY&DN&yG|+z-r;q*d<~PdYxy^ZJWGUfIJU zIdtUbL!3SIYl9BQxaN#Yq}`$^s-#cTU?lM>0d{kE;N%6YPhWA2rLd!+hc6M6tRi#q z8{mdix8g?Bhs|rGkRYLoQPAW}sa=ar)rdNAKfDK^$n%~!_g_yK7i`ayWR7f6_RzxN zgsHRG8u6?b+-BcJoJ#QbIKQNOP+hUFEJ{&&`v8Uv6qwQnktp_g)_FDH{bp(cq!17) z{R@|{6rP-uJ;RxtHqa%+B5tvB(tjp0wCufH0|%X+vhmIuLO0+`&x!9{0gIv*)u6%o+6V!9d1(?N=JybmdQ2%R9 zEE&XN?!II@clHaySi+c>BiYWqs5RFB>2==VvsAx;f!aIBbywr`S~JCaj>=oPDgMl~ znHDbQ5qvAk*YSWFO;M5cM70TpSCS!GS1ROOejJoO5y#{bos2KVvKBFQW_$Y78`>(1 zd@YzY6_>hJt4Z`cszP*3CY``V)~kA?;=@kpvQ>T42o|aO+}(Aa$@<-Z5qU*-;PBmH z!;Nbx)7jdu+4C4Bv7IhkACiBQ{)i{@?598zRKrcn$Jy4b5Tj zh|XfmpUq`OW1g}0aD@*FDZFDrF7!a_AnQRzD8ey}q65|v-i}@*sff<<5}mc@WMIU1pmM$V%m6zK(WDg8Hr@1wQc#Y=qv9AG@$nxyy9;(# zbj1}~4#0*O}NrG^Tw0Z+d5LHuV&AC|}cI_B8Rt4L>d_}-sqX5p19 zit?D*_yqqj<*juFRRgyO%i-sYmSpyn%rzS8{;nb~C#4G69*1%am4=#(m-Dn2pBscm z*3?*91%RWF0vi)``nY=-fs#zMeMDmy|DYeCi;VK%ojfcWv+C{v#D@LV>*1R|X3@O& znKV6(y3I^W^h6r6YgDraPAf`PU@vligDMm#z6}{Qw7Bt<5Y$%`uV>=yHs~fi11%kR zLxE{#pVgK%S889VIsTp`wzhkFpF>6rEp8lkQsr*9S*s1b8-yem#(rhYjMfvd{dgv_ zTWCr*mA#gf(F9E!6Le--WGTzmPC9{URi@7YlfB3G)lO@hu}mE-9~u;G%qYB<9$05+ zcH4NCK)NREY~wb;2*Z#CEKp_n4L;(0) zdmm|x^$$uq3JXI|oTa!4RKdnm;L-&~!UH7#I|ku^T7|4L!<_-8o9BCq;KX4hJqL8+ zg^AZfCgIFEqs#}C^2UT(cva`H%-89eY(@1QWzZv6Jz{ExfUR0< zgx=e8movAK(@-U(YtnzA%0#A8s8tq&TzZhOlZ2cE=w8g zyy^}SiOb0A!`zfCz3`u={Ti#gtU##4ZnR9^aA$$P&=n+o8lHqmJm18$VL(D9gBBf2 zO+??WeJpO_A!#Fv$#`wsc`9?%G|9}B#}i@<@$nx$w*mUg1|rW5TqXmn;uWdK7S3#T z074}-Iw~;Rz?zK)>fQHov<`)p;IYdzZ9eEpJC6e4%!U>X`Nofhv5Z4&mHq7IFJb)e zAs*>?C@cVa$zRZ<9^OfnAF}^7gb!cBr^AKo+6|l{OlCAi=T`4 zzzMMwH>oPj%1O9>yF*nj8i+)*(jhuP=Qqn%8 zb8&bGKXPav?YEwQ+iwJ$j1OpxUoZdH%1yW&;9PUmKras-z_@5}eFq$8%e@E=C5P3b zcX7NunpKTS+=VWe&FsntV^zry^iI8a<8ue)Oaa` zUS_&fro*L-tykTEMRb*Bq(SzXSuRqkN>+zLuak0~l zZzm2bJly%OvjY|3`I#UUzEYo6X&|05PHU&k7+W-Lw@xBEnUoH(`ZC}3Ft8$MTIV%gX=qbbsPZh-c@R3m#*g{aeb$#z}tN+R~?=r=eY&osJ)1xhKFpd z`M+$cusz~j4_;PJkvZ8|sBkijMm<6oo5!VA7qs7FD_gSzcC?joG^iH1zqvRk2Q{_m z=#%g=RUH`Tfn!N@dbK<{;~o+kWtyMt1IUR0;7XHSJTO}wY!-_--T*v_$2PG|-0fK` zK{X=88A;m6>~=u5-_|~ZU0WbC0>A)Xz6h=@$wnAh+oxa0&M+Q~YuV%Xx0t1}#w;PD zr8%$w%aWTg97-+X*$v>VYv6P3X)-kuq{sUrSr;NZ=%KE>k+Gv}!I6%;DB&s~CilR& z4!pRJ6`?EM#;5~a3-WWh!;rlj95%vp`1Xy)8eGccghT$AU`GZJbZ<6FEuaf!(B({#x0{_$Fzo; z!A`YphDzKzN;2sT+}cCWU-Q?mzJEh)SqCQjcgn7Ia1cq`Pyhs(Z?6o-!uxAC@s=|) zL)?QTufmx#LTAY)-Em6ar2A~&#Y1|ij#p8jJXK*Gh& zH&$Wjpr)!vL;l1}R8GKsz|7k5l%W8vt$6h~%@AwKSxk_g7u*E?G?L;5_k~gVtjs#? zytI>DwhDT_evW3>M`r3#Fts(RPL&BZ{iOcqpZN+{kJe(kx+U+Jq<`4L+!yltHg=LG zA(2FpZDuJeLUrn<^5}s@F`LYcWYz@P1R>CIh>*?}R$)upN{JLJ zVr-cO!SY$ix(C1q$D_;?d2%8>*iOyN{$!~mT^pWfZsN0tpz~MFd#Nn;lo4hUEO+Wm zb~~j`v@Ne~)WQIN68^8ic;4Gr);Boji?A4mC_NIr!VkySl~ginwJ+5liGW$oWX8klZR(cp)AwlL_b>(zq}ZUt3zq z32uWI;Fa;7Sg%q?;WDWXleX@==C&HNvRvN8-nJkj^iC{6yI@=$>F1kF{d{!_S8X~XfM0G)xRJ9Z+*p@JUp5D;bcCj)EEpik5UPt8tYK{K#C&@& ze7_~ySwLzPd2$^-Ip1{>7v)n0`rE=2eRBE@IQx;Bsu%k`&84LbPAx2Z^Q~B|Nd-&Q zYB6K~RX1>9BeCvaOtwp9)pZ#&=*#Z)mlW+?h)tI>CE8XowJnKigGeJuH*&Re(O6ET zXd2{$rc{>=T}NGq%_tR_eeIJc4P zTx<&>AgeYhG*7Xb%Gmx|>PsFytr$k^cIdvQ$sunL(jZOz(&H;Ddp3V6z*flZL{5 z14F4tFE4hF-tysK^B{ZT&@(X=ZGo+XYc;2cb^)#hlDXMjyI3x9j(sa#X2|QuCm#I-9EWoQ#eO>it!^bOP{RTR zNebAh&wd>JL{@ozOi;g8t)mi9WtIS?nZ7Cn+ zDFg5d%HN!mXKsU9&DkGi-wmR@sE;_`8JeA}Nm@=+;_pkBebUdmq-7aat}F>BJ6^Cy-cSEVUhSaCcgw1YZ-ii(GY?o;LZP5y|ws#pGqdIxQI(o|w z{s*N%y#gq61J)fITHCIS-<}?hT0K@v#o6Dgu5olqH|e7>eDF|D(b4DjmD4s_PN`eA zxtz$!tiwt@1VzU(dT=>S`{vo(rFx@nHC?UM%z_^5Ng3(1L8+bkPC?m1E1rb^Kh{Z4 z2L{-(9h<+dUAJN;7B@I77Q?fx=TYfaNL?OH{(&ZS$OZb!x;l*$jeEwym3<>>ow9(^ zrC&$rwEHj&a}btlM|0o$GI{$pY5g52krFNCeqKu~ zloY|R)}gCz}6BA$ik|_41DDaEzF?kp%O)iCsEmr2Nw-4!%I1MAdK*K zN-@%k+s4*sos6)K&^e9PSyVi#%JYww`M7b$e?63fEgK0&0J;{%I{L>aJvp0dJzCyWIr$TOy38D&v?DNYPIoziS}pD%tyNJUDN1{Gl{Ac8{u#<@fGBhBD;S)LM65k$$gF6L#9X2<{~0`_+r-w1kHd z!0CdIj|4ADC3J}#G|_1%m0L$zCIFE|?pYsT9>R&!wzW<8vXjl`(1-uhA@{p_&hS|G zH$jJR;Fil2y)AUzO1gO?Q(SpQ5QFREisa`Dh4}0(L{XP*LK$yVW zEoDLW*{}hjVa?#?7C+pzk`)g}OgZv#9oA4hi0rVWe?8`h5=ktiKXzYxKlXqRT|ih@ z?cCVp;R}MYk*?n4*eOgUReBoEOuUe;1@%l(Bn1XO!-#;MO+uGZ9S-l48^VX%hzBC3 zgsn`^k;f8Z^fLCXFjNNY{0ho_Xp2{fa750h6e531^l%JX*PF4}V@|V^HdK_bs_SZ+ zS_*v!&Zi2riIs&4P4X=`4O{09q{|j~;^sq1DCcNuz~n^_?l~-(510fPH6c%y3u^WO zbJkLEuD?IvM0BR2v2i**N+f(Srn|}mN9IV8yY4X0oIQ$|&uo4eaTc81sZG~2+8GTG zd|FPUzzzK7)zui)_YA+as&%5WQe=gqt0?#ep43^*#wikVY^m#Lm-6EA1nhxry`So+t~vJm zF@ykvg-y{DF3*8#x~VEA9(_^~Yfmln#)mOHwyY7&1a+Zjek`CGL!ABu|1bqpv=Jt8=qC1<01*JySsDW)4j6Z8c{W zdp!pZoUAnnFV)c_bU7TZ3l{W)rA=k9&lzWCg!n9&dcoqbo<$PD_kzb;8B`4y_?&{T z4-We1{3tDXrH>%rs^h01IfE^ALgM4+$$0$+bUvP5O1soMtzX;y-mvn6X7R zIT}%eMl3ZW3cWi@wf+j9M2&I#8_@>0gCRhsmi$VPI7m8W(|1z6ScTRVTG*?}`@%>g z+p>Jk<@l6BgE%b~9H!kz-69{^BTmE9T@@OQN}%Z_+DEsky(D;RqoYlqd;S-YddJhR zxL0PpC6+x-;>58^%f2BqxP3}yA^n_D=;>#skScKW2+Mc6-LVz?`k$Ee{`OQ_C_ra zioh3Y)goDpN5Ar?$sw&0SrQ%QBZsyD8GOwGQ8ihRqo`u&`8S@JQ_S4kLzIWLyd09; z4%;HKfk~wQ-}}?yp+?gR<05{qK5*8r+d(mV8s+6R$#qbrRgnHRizquL=on!{j*8yr zT}d=$S;3d&%%{uJM?A&kmJAQ9S%N8^Bn7Vyd&n}E7JyQTV03iJ==U3b(zjtrjE8A# z;SIs5oRjbk)N~1b&9NLo6#yL<==Cuu@WSA!2KqGB7t|OPyh2e@anG($v<`K#z^VRz zqP5ko-cbTwH9)1lSRU(r=H1vr$cg=PMv|cF#A4ef0H; z4v) ztOS;BY#dyby?8UxxMY`>S4I&p-;^WqDr|U>o1K z{nwcsJYdkp5%DmK7vS)*-~*`PNNs5N%#GWA3FChUDH4P>(L2SOwBe|Hss+p0r|o}{ zk5ctP?tL)EpvUb0uI5ARf_Sd*`a_(Z+6p~Y#c9?v_0SE{51%@0#1)a!(I8YtJ$94s zXwo$^ZzEUb47sd^y=Vf}Vjlg_FjnZ_G5*tO+wLs^DoQo$aYA1{+lHg(U*uTpO!)-w z8&dPob{V?BD#yZ}g4PezejMbUCl<0FGso-?jMDB=cz#Lf+82b2Y0vaARzJJ2_Dz1q zgm-p9#S{`{d>L)l8a$@yk?kRDAQ&iQ%WK0QuaH|2z`f!)+hA&q!F_qu=2GV%ca2J2 zV{P~IP5`%V#a()CmKs{qs8_OG5DIw!L{pwM3m@Zg^qrCBBb6BSdE^Gk`gCMS@a1=3 zja}bZh+W#+aO&_GtiJRxoj$CUe9wVHVe8)ir<~nfXypyNI{V%ehwv{-`bC>~#Zxl8 zJrS$qqukTr%eMh4CN_($X{-BjKLhO5d>JmI@=?pAj*k->wjaV#2p+ht+_hG2kSo)6 zXZZiiY*9xj(eRN*Sg-tL;c%HI25F~0kuiL@HvSk%q zsjjW72x+PS=f+eCTq&k?Qo}bl^$aA_F2iA7$LbF$A8Iz( zwDd==d%N!3Ou=f(R?s`=gJ?k{2riUOTqe4x#D}7lowp%wQHPm={MN7A}Qk!?Dv7E3bP=ln1nWTZZ2vx#LZN~G1 zej$STAht_bR5K zRDeFqsrvSeFkfVnCA^v-J=lGxBG90_1pHc-!dFNfoV9>sGO0%ym~hpubtoxL8ngn< zlESXf@~QLBTwqan3fK>4C~S2<$aB$k#28SPtIrQ@VCzkkKfn547!p?| zc0=8Jb9>WH9^8Sxw)kYv;ai~?p2OFruL0CF&l4uC&3|7Yve=Rj+lH7LcZA}*GhD92 z=NLh|Kyg-L^Ao~_wx4ys|U6u44fp)67al#UEsi>2h0nq!Q~3Jq|Gj0x3!2T2H6_)cK1~Bvgw#j(4J`2|uf zDb=Vt)XQE2lu5j`{W_-y&7N$w91oMMF+YserxCkyi99=?Ve3e4x+fUtqM#!|e++L9 zdoL!>RTm~4_$VF>3+pgVb?nRTyyA9Q7lxX<(a6EIefss=1Bt?(K`}RJxvwyM5uHsl z-E-sR<^-{lzX+iJW>5p0@euE`ZjMH|3wgCg(SlDbyz@KbjBPf*sV{0FZfZZZF*Jt* z$gGfIY1e2_&u-Vo??!uuBs}VY-_&_p9S#TyU5j@yIg8L>Jw#VTx}SQET2imsJa`=T zMMkQq&=WSUTI50YSre&17ul!UrT>WJxg?S_(y)1p*?-OyB_!~szjV+f@Zf8MKNqQlk|Q<&&?2nrHPAO(RrpsgQyxe z8H}v;%vT{o#k1hgCD2XzMWQg%b1gzo^M%P$0U^`}XzRhQ-=w)hsvR!$KS({1p7oo2 zNew3PN(dNGR12CF{kQ9{+InfXQ2&M8SDtR1seG-2xV4zg^G+1wL=4!%ppzJR4>A@3Wo%t8r!=y~>1JN}q1*t^|x&F-z4@ygm9u>JrsY@o_};~uIhQk zUoCV?+}zy(Enx;%NepDylUj7`yvgrN6U@|GarEF zRE>mrpFFTbxAejKoan*g847EHlMTRHaZUH2y@@D=WNUnsMPp|?C%#xbC9cJhag-Uf z+CCmj6dm?WC-kH<~6XbP(*12vAwthTT2ime$@k23d(a9O?i4;eRkK z5KoTm*`U*65yMLozwHZ4cAg`Iq2Qn3;g|%iq`x zVXw=AfN~)>D{N4=Qkr%uRBFqv(-?BgK3ll+EPtEtbWa+AMHS;Npl6P7CCWA2h*lm| zCOJihsHEPGb^!2i>;)xaQntL2-xe_bg@~K6v7%CSalzB5rij7_l`8LdJK?;?w|qKu zVifh_C+d*InEh%vWT%c&jT!cgNciYOPDl2#sqhyZok@Z?1xt=m7aoh)rK=B<)p^Sp zKL%QM^$~M9>gM?g19=f^V`CeEH)1B$;E8u|&7mLnBBs-RJIh&(NAb=6t^D z1y-4};zPwzI~Q+vK#P^Zof0)oRvx-GIzr$s6ZT5k;&kPVD_EX1Oi_V1N=J6eK1vYZ zL*FyhbreKL1t$4_myE({+;p^xn~2tmEWaWmAObEM%61O4ZE#9m7eiCHicTEq-(-18 z+P^S+dGh8tiPdupPNeLHeo*zbQ_i#!!gnG1j097hQi6f9<3=^mJ~yT&iin z>ua}2MpvhR!T0tH{%nf&v#ASc1bvB z@Vbvhdhn#9laJB}FJ9dZ=oP%<^+{n_HA6U{j0&DGl?intt0>6f0kNS-1dN_LG#GcF zUh)||>QKK(iUqsC~`N_Dv0C zch&kgxTaOVB06@ZKr0bP0?KnvV9U26x9E2`FeCG9iY-px>6C~NQ|SZPa0Mk7PrH41 zt@*WGO|;xV1l;?sCxL@vQM^E1tu#pRrywd@B^KGZ^cpKjIz(>lH83|i0qkPqhw_wgK0K%vRx+e%`5{2%$VnQUB1AdG%q#H?zk0YR! zlfq4GZb*2@e2}sSz}9mBD7@9sU~HKsndO<*24rd3nN!U%PRTUWu5M*DG;9>}45{a! zhLuET0clj)6bgBEEPo0`2yM)#AJRjcJKl#(04Pk0C$WqdwiY}k`j?~8E|qVXZBPG; zFL@4>YAd9_MT;>&oM|jESlg400J~|74lt%T=QEkytyQ7Y5}u*YzWVEBAsYv%;PFjzJ^rH5&W zW@fLsb~0w(-2oe~u9LZY%LRuhKjOd;F5g1;jivej_|OrZZRO5BP%jNTKoE59QZa=w z@D!YWb8iL_7csru(!^<6QGqN$$mM!TR<^0<7@M}ncC&OyQbF6#fyNLFuA*liV3c1T zL?uX%0=Uwk3^HmWo?LK>{SwFTW9sm~R)S7Cym1B6cwhqJ$TAESYGTe*sMKC`E)i9Wt2Ik*dy(6V|yC1uWbwqT-9s=u>(QDf7O=6WS*&IWz`#2O-ji} z0iD%<MRFUcm>eB26q#Yyzg(|zQO@fSD8r=*P zv>;%FrFd#psDKK%%O*fm$udCAA*`FJX`68oUn^K*jX-s3-F6KKqGxy$WCVH$^|0fA zwxuC{barVEnn7Q{+;bSCWhlD(Q3W~+R#TFE{hAAGi*Cv_+Moy+{!Wm74!U_YT$H_++au}7eAxB2~;}_;J4_XV~i%(lp<%Ni!@TAgFP)G? zv?~;CI$WN~%5^aWW9jEYed({@qZiM{;mcp|Ok~X5ywa^NeDllXBJ8q;@oXZVpMv1?4u zrx!hxks$L%*$A@ZD}0rX_#8ruXBto^`a4G|7eIKW+5-2Z8XOLcw#oCll`go^lWsGI z7qk<=k9GBf4@7^`Qlj>Nb=zC=x!$4gl}^|d3>L-J(n0OSKJkI(3bU&NnLcC?eq%lp%jhQ5-|?w5Z00_q zk60t)aX*BB+=!|@L)KERdnwC}*V#`1Y>z$%=)`lMcNHXQR0Otq=Npo^FKVr^_;8&) z8#GUHH1-^MtE}S>9+q|0;u;j~8#t{!g>4yVshHU;wW5zPAOocRWd$peS$5>Dcaz&w zP}?kTz?BKeB29cz$qkaQ!+E+)?i`S3oP)A(_KIZI;$4V*#`3Zyf#|=*x`>&cVnYWf zW8p2@5}ZGU#iw^DUP2f|cwB@fy9F4{2}-N}6Fl(vS3`>l_l{Jr^x^-J5lC&In0QEJ z<30|Bw98J@cfZR^c%x%wp&=?Xf|ydEC|T6MJcVXxiva3L;+7MicOU=HNPcd9a5UFD zwE@E6F2Rm1w8g@zQ>+4kDOe1MW`HfenUL9Fo$H6ux`6wpmH_ z+72)9b2w{gqz3IA;D&n}S<=3=ioGKD!#OCWNPmyxzuVQ2)H?}B`sZ2{GMj=vPJE{# zddmLZeH_p4zF=QNfFn11{WjO&hI8UNQC*BS13Nhs3~~JrGJ=RMo81ktHiF#azHB$x zTU`+^OJBWhE0I84n}3oJtLDS|MohDb7bw0W;N;C`LdV}!%2!{%ScJONN(0yXHoUdl zR;hc5;Kn^?)JG+c6sD4WC?vBD?&%NbRoCJ$5o!xsMU|iTaw^wJBHjeG-?`Ju3{69R zHK&qgsMwd?`&W#71zZL~>km}RmrtT{(%YPpW#U4g@Zg^x> zIdTp-mn5#rN&aX(z8exC071o6T#@BJ}Fo@BgiyotKr2!H#;@tGs_PtPqT=!^(`hV(V-9Nvu4~z1!h_aJ5Th z4(SKq18)pIdc{OKz4u4nmqqB%5OfzLG+ZdWNhhUv#-)R1(;*+k(ni3>`4?9A;Fe~C zvaKD!LElZh-Z{0lFb*H~YLJ`fS|-hN#qagi0nJR#xO5KCg(sU^Ho9ZIUgfqP8N7FQ zw(D)UMwutk__R${9uvcLKZ9Y!kZ&0}WBTNA+fxyJOlkZ%PW{a+%8H)Muv%lhaS>>+*yubiiO#C0A1#&3oTtLk}J{ z;1nv}V$`j@$-U|B26E}yx_{|#ll#J%IhC%yJ)`CH9{_zwFAun{Ak5R@+{W$k_oyhY zl}vwwB^1kcYl2%j03#TnVR}W$Cb^ORdxJHUkJ4E8XLkx?(JdvQ@GhB8+yIjCnlNF5 zJky|0jpsaUlDm@|vrqO7)|6(mAsCaFZf^%~!EFVeG^@j)-)VgfCwS@Z42|*YCirQ* z)Puh)1l!U+*w9F9%=8X_bvPQ<$)qqLeLB-WsKW#iuW$*5I*P@tpyQ>zvF=X-WKM+q z&DMba1gef91TP8ByM0kr^~Jn%aSvc^skA|LS*B=iCS_8}Rx>353T+kgW#;zLDM%$r z6tSKW$?k*ehp7Ss+TF~&K9Sh(apx6Uww^%NVM}|)8~&XL4k&X?T)Ellld3dKxG#_b zVMWzqulI{w=Cr=nBd`kP%ZF1Pt_kJE3747~>L$pa?DDB4@wntC9A^W8xSENV_B*1V z_-Dr@a8x=Ek66_gWhQNZl#Kr3Tk65p{w){mHc(1Ed=X8BWm$dmU2dKlA9hbA2LFMS zTD^KwM1oGJpI<+3yz|^iJ|(dw-VfH!`Q5D{TR(v;iA+*!^-2YbiJFUtwCSHqj9fx> zM@L@}lf{!_R7)4E#S&LCaMIr1?(bd{<-ct$>F;3kXq2Q&lIMH}?Z~6DPR+-JvTsYg z5j_PfO**)i_4^h^G9Joy`!Fa%3wr?Z^6rn5_u}W{b?G8J32Tn&F1#FBSK$6aqt^rP z=IHV9R`RTLO7yl-Rmrj}4RwthLFOq31LguO8`ET7b*LAR-0Er@dlZ3scLQ zoISRd#ak$jY{{Rosr!0;$xxq8KZJY%>`gf&Z z0kKn(>dZ9zzn7|~|B9IBb7{s4<*S$&#r%}Vq(8@Isiv^YsM>~y0-JSl_Lp1a9??pV zFwsf4ivWc~Z>Wqhq`qiuAlt)hS>R%>*Nm2g{INKT!%)x-h*az!`@{1LI96lhuKBFP za?Hh1la&UWz%Rim3=}TCp};XZ@neVT%YCjL#>fi2g-_EaO4k!qcXa#Ep=19TWqYKZhAjev-gCJJxRSjRbvX3s%+cTyV3s5uw(oP`Ep*4tB6)+ z6;o2%4>r{hG>cilbZf@xEAfiWKy6Kg&%vu{k=e&Y(xAs2^E+q$MlYDjK^V-@uI)#LV z@{?Nngn|<;ikF`ws<~|?X}I^k?#TvyH#g+rPuiat&BoTs-GqJt5>C?|Hk@1ZrfD{E!X_;2C7cF4_;Z13BMcq63j2`F7m1A)*WuO zwN0(xpn;Iei=lFhmTG+ApDbUZy}dVpBgr0#o{Sgl#AmNzy`$OUf7%+;??CA>6sW2A zVPk@8#62}V1w)<5CW(KPsvZ8ZRZp#ZaC3A3)b;g^@>=5E}uo!Zi>TP+KK zv-8u-O&u!XGG*T$bFlatUj3-$5#UezWpz`xMY=S7l0PvzOw*yKd(F$14*(zj3ujph zOtyWMccW#Wr`1}3>sw&#+LiVH0*UjlpCfwA3&14Xt9dW_Pk7m^W6ZuC6U+>J7IPd# zKmCnjORu>IO#CG0# zP{+V8_umFm;}1Gb|0vIVSK|Kv3w~+rwvV?jy9fVKd;}B~f3j+amher}6ZI+ocOkF8 z_RKe+^=-I!utaeez}M~zYDbplnPw*Hv%x<_ufP4yH)JDy(mzsZ;Q+Yq${d_ZFCw&wh9%L#f z0x^>5s9F(*oD#Vpv}jY)(~MXFi!iY3-^$6GfBTIi=w!& zuA-UQ)h|}mKtut|@4$k>&FvziG$?w$L_ijD=RvGIneA$&03m>F1XxwHg*fo8>K+e^VLF`n3U*QgHF;%8|y6v(%NQaOJX~quj?Eq4s}WmE3W+^QFCO>9Of*f7e!*Lazo;L@K%+{ z3eV(j9eR0F3pfzYUayW6V>956esIDX4ZSSXiW~Qx-Sz|!+y6<1e_tLBOZ(%7c)XG$ zgcQatG+CI!lkO_PM8b~o%Q!j!JiJJ^KjFX0|11+Pu4rlnF4KO-e3{K35DU8bS0IXE z5?7;s>UM0Fj0d6_3wrqc>|Zh~f-(YFoF%aAr+`4OG=G>OUnw>IVsYn z$NQ{{ON=#;npZFw(OO$Kg9RS^A_wDZ=c6n5eSh3_igUMx+|{Pl50hEFS{@cjB1#!Q z;1tz)X4jC7EGFgT$mLEJi)@{}vb1b^&BN|BYuqaT;1qpcK}R)wK8ka=2+oI8I0qE6 zIBa-UD10nIt}+&=JIC}dRTXrOiIQKJ&Bw`meUbPceje%lwh=JG&6!AFddIqz!a#L zzVkkmJFO)8vaN1Fx3TGSVG!&J6qYB9mA(W`ix-&@ambU!kQ^5;`H*68wwje9cZoq4 z$D)uPPzQJfU`L#uI1+^{L8>=7Cv{vSfhed0;UyP^3WfBT;YSiCeM+^qNG>Bjk%aUJ z;2g;l)DzMKMNAizCJzCJJlRhCEL`#-geGUJQYrEY8R+8WD5MAU7T4PYyAVMoudxH=;fW=|TJ;I35zYFKDHc53F_{g!F)(1y45QP^c-Mjn?!P%RZwW@fg>OGSVtVj zJ^bdg2=pFXM}giyMUX-h9gxD$6dHv1K`}-Lv`Hi{QDD}~%)v?x0G>v;h7LGMLPOyP zb6Ruaa|MO)6**JWlalihm+BGaBoP61%wwhUyr3kuuh0H#ES2=uX|Ck(+kSi3K1MUlz^6MJA`D`W4Vcp!x4y`X41=zX|6i#&seT+7$y zQb-hg+N!?HSHqGhGAUoS_!}@S{NGf~fWyJ=wtzC8snuVJNR4tXnmiy)l%IPAwWK7+ zQD2&4h9(l*<7g@idkbxsSB0>{AQ5QN3>oB5KnWGp(3p-eQr1vYgV`PLVq@xM*cU8v z(51A9#b6+=R}R`QB1*M^h!H-}MFZdf2^U>u8A6nvywnu{V?zCXfoWgLdBc`4%1UX0 zbr7>-M?ZkLj-7IOz{_?%DB{+2QA?>a7wgYnT+m2vz=Fnd9S$@x-A!mJ5Bi8(=Hk&a z=pZwC72RZO;~J*}kUx_@o4P4mlYtCWVYD)fHFy854CFlC2p+6=3-6(n`H zTOAUEy0-724)&O$7m7ZXU*;wT$@26rS|1#8ob{3q4cZ>>b;SpVBACW=@tpOcji^ol>_yF= zK_C!d?YjRP!=+!?!`7U)RjCwRwSTQ1eU3;?XAkVg$h&U>Vtsm=dzYGaWhs3eEJ;z| zW8&Zg_k$g7mg>p#h_XVkPrW(d zcps!IDwgf$0P)Ma!U*Jw-rfAMesMr1Bpe}P0$EaO@i7w;5v6x>fTtlHQYyr`=Vk<< z>SgJaAaX<|vlnC=<>QGJiz5@#X^GG*{|EPrqZ*>sWSVI3h(Wge2q|&Q0wWU-}7=*{@ibTX45>)0}tIMtwH*wcCC3>O%=(5^!8R@>^ zrrB@Rdi?~Dq(@u)#5h9o z8E?r?OZXrre-KZVBQjGfC5RZcIs%LYWK;CW$~ziCG{r#-!eic*DOrrZcLa!Rz=ga?Ml)Wu^F|u4MA9vWG7b3XF+T zRuBR3|4bmxgs^4}u|79THV_5mHWsyO#Ce&Lo7}wfb$AqX@Az?6cn*rZEajQ?h`K;t zP%VyQp%U)yM;5I*M`ndTYF^@2y&0L6HER%s+vWWwg6`MWS23JifEP;v%P_Nk4S^)D zy%TVi<{G_`x=H5LxFw?wY773RhT%9h3yVs>n7Y9;QP zR%1Y+FXRH9=8&4Jl*oh`xHlahDPu$ZiHq5mkeHHO2t_C(3S22QKj`0UJw~f;iN-m& zlxv}W44En5ZAP3lfSKI={X%nYnp+CsV`}IBt8b6|bcx73!Zo$r$O3l<+Y()3pi3%> zZJY#=Oq@*gJpghEfdu>5%*FAR$uW|)M6B__Ov!#YM}Po^sD@Xblo)R*{GEyxvGygO zzR8Q#i<-5qAq8OdH{{Y1!WW*W`*ifua;mx6FH6pTV?PhmUS4&qe@thilPB<%4crMq zq1a&L6n>t?=N3NMg547yq#G*>DDn(#dx!-F^YcFn8X=NLi02Jr2|_e}s5AhTiqR5Z z(DCNEBg7P=CKi|t3LNPR9Lq+_fWYEb!xuMHhXM>wJF2AvD~dQ?HJTNw3zD$n`Jyhy z3ICbfm}rbTnc?wIYk+(tX-)|$t$?{!VNNvSF@!OqKrR#AJ~BeYzhMXz7mHj%69R(s zxN3Ev3v5rR#`S#^%zgVjsmMeN%ZSAYf=|^Kp&k%Ie||R$Y+c|;Fv@)hP02CA18AZQ zjbq#i5}b?@wnc*Ny+woV6I;ULViAr2N|{NO^{@9ax0Gc<{SC)XxLrpi!3g4;Pzo@` z0BFpEBYoIJ19r8z!cWj74Ar{9&#y>&jR|~r)wcITjfIn0r0DSV`*y#t(AeUM(0*+)47dLC=b%pWEOf! zJ|qwTzpz0kxKdH-F4O^v<))zrnmvLwkIfdT_YnxNAQgFGUEjBUXWelXEIoZiJy|&R zWIv_TS7gA;E3rHnYNQ|1l4K%}U`r}ihRo;?8XprB zVmtr}j zj}h}^%>@)#TC>>JkJ@nKOJo9m-+Bk#@P}7PEUSV~Qyd+U$I&E6n^mqmV7W__>lTrN zxJ?SMT)-FdP5c<2z$3REsAxC4VFj=6Y1tu&QA@gzK9q_Hg*f`m(O$l;@(z#muNN}= z$64c(dF1yKx8b-9W6LHejprOgs_CHUt7k>6(P-@}W!}O8 zW_c4`a%c}N>m;PJ1a3nyc$|_Mg!iHu(E~Vkd=q(4df-;`I zw!QaHkMi~j+h@>pwszKZ`zJdouEEE5MViJ}JY;@>EAji0a9FsrjJ-rC!P|F0og(;! zFxqBetE*q}A^IkHhjtJ)l&nFza!A*Xd=^)FNtx7Od8wYZGKx%2Ew%t-{h(_|+VhHN zPAH|dkAgVRpZy&aV=`RrGunLm%kI}T$mo~(5vG_Ocb4aEac!MISLZaiL%4o>yMkZPE z4=vPlTCfv+70I#1oF(V>Bh5(v1}KXYyzQ`N?~#(U{8f>_Rx&MtsVM7n=g0cI3mDX^ zw1J|~UF)yrl^Y1@DPGAxfiE_brCin-(;(aC6xfj>Bozd$i~SIBxZhD$$Tf>E>l)H) z%?OoWjHJ2tg72|W;0sZXr!3RR+>94nLb9o0rT@MxT68&*YV^eL zWl?l%d9^KCE6eksDL5;!fYMk5D6tA?(=MM(#vQT65N3>Iu(5#)_--j{BO9Lam@=@0^e&mCUg>bUlsHdNd zFpZNP>MN^ZI5ygqk3g|SJ019m;+e1oPtw)7ws24FG@L8l%3fYAtt1MpTdKr%qEP+Js0X|O4 z0XP-Vl`CEm@p{!j)Ehua!-fOvm8>CbcwNUlEraGni3NtqYdL(t) zCFM1AhVgthM+s+qR>bG2t|FZ41B=ST>okRLP0 z`xI)wP_b-D?G(cdMg(HAvuHMR(#@5x1PEq~Nj{~MsDMe6a*sH&=|2#FvkpH21Uhpn z7>t>Xxz`Vdcw5Yq-BL;ojmu40#If!=MT|GW__e{5J(A4P=rDiJoHkE|T$<_5y2dS% zFJzUBYaJaq{{D%bi9kvbI>~(NP)EvW4Jka&X@i>o+xh?{K@y67?kj4)6r^qxd_Hn5 zP@J}MUJkhlFj3k53;3sX)8RON8@jUc2a~OKI06VJycbOY3@=P>_AMX{0BZE-4-gr9 z5W7KyA?=f&3Uqaynz;PelpW`Wlu}!NFrEh8?&;*RZgH^;g;R~&KHP8^MPx#RP!M0Vv1R7|zp^-%@coDbLv*LHyZXNn{>9yn>nl;!CZ zg7J%NgZ{O|jJ#mMNb8POC^1LP+Xv)XN!gHBE~iRM(!xH;@!PQ2vbl7;66rQcpK*I{ z%r?Shz3(pc5wH3`!m6&7!`^xxSr*;G&%I`uUa|9Y@p3iNr%`R}VY(#}Wj{^B5WMC> z%3Z%l&K%Tu+0ge9`(8=_@D6e0)GooOAvt zuLNvILOG`yS4Xn=B#LqdGz=nuyY)&lcj}NatX3O05?p}q5+6c=U{gajJ4gO;D>BNc zvBqi;lFPM-cUVYo+V#XDx1EhBeeCg&ylbYcAsrBIbuzWCu>yH29Xls=wYc-w*kHS^jl|T$e^E!SlcDSs9_^)Y}yvgj;*&a>^VsB&VL*^apuZ} z8+RK#c=6=zJs(w4`SIoNe_M7agqoCSpotdR=)nKIKNQgDp^vhQAqI=X6Nn@-r4z@W zMrQyfWU)D1UL@KNUmz5TB~qEZMN7X*m0F|K=?zAcxnfmCs|^4Ifgw;>M9Y5&q`y-2 zMjD;I7+KXa7JnHouNABRA~Y3>#1g4Y-nfPTO_?@h-h??{+o@gCNs=r@sx;{`WFp9tEk~|A`3e+L z-GJKT(tM%{m8w*$QEPSkMK@^F1OS4-5GV|eK%&qXEDlc~lE@SdoEZOZUMe$kCBV5L ziE9lumPcuH29s6jX-;uxOCbB}@yo;j0wfM^cA+NCLy=fgCcy7nsZwjSI=!N5x&bCy z!X`($f?sXm$qVwz8}ZHu)3P1c^Mg>F$T) zyF(}vBr&?w7>g2A6g?T}gWJT3<6603OcKnX)DgJ0*Yc|8qeVrGR^n)9ujY_ZJ_yDZpaLEavN#o-A= z^W&q_=nTMwEH;PBGdn+=P$ZT}Wpag5MOZW~jFAR8BQ46scM1psL!dA?0*OLnusA${ zNFr0HG&+OHVsp4WzCb7vOQbTnLa9<~v^u@PXfj*C&x?2V4!TEEGc*QGfAF@Bt{wym zgCqFQ%ku;xi2zM%$VlM0-{UhUmk~>(n8^~r@X=QK28Kq)CZ=ZQ7M29byMh292n>P3 ze2^XydIby?=Rl80P(V)&xM@uT@7EUyMPi9m*5SaI#(w3{=@nJe4KUFXHaY${0+;}0 z$il~nClEr(d zuQ-dm`vI(J_3^pLOTQREqIEMoM3xsB^Z2a#Q6n3`c{vAFb)bz=Wt@AgDw}dMK2S`Z zWnQ6`8B~=1I?$#;kyxZXi$xiEeGXlwMfVdM`XH-*+^7cCxT*g3_(ZUC|{nz9)4lQsGo;%fzUc(GMwCDLT*xd0Q_~0BM1W%W?o2H z=~6N5SJR$Vx8TjS2quY-?pCuZl+IMBaYYV!;|6t(3#D0v2?r5Xqevt+d38cHtk9L< zJ{5wjrTa>>(u|{}8189$w{#h7MVejD&gxtSyha*=#TPbesV+QdtEMoFUIU~+M`;Vr z40YuLIGl&^Xl%&LpoKe&9%Fr9plXOP7wIN4eAUYe(}|&UGmFF2bF*A_Q@l12?nQLA zC_>^%(5!~uZn#QNsy+fO-Jc#ttC^Tlj)P>m_d|`stHvUD`DyVPFHb-G81Qqna(Bmm zU&w3sHTCprIE*SvD=$-AwNOTP4dD^esUHFXH}w}`EZOj#Rx4jZ%BFq{pxNLM@X9@X z#D653ZX91CH~~t9&#gWJwEznkcSI{SkxN-n#m`OW3Z7e=w4$6Qa*jV} zbr6G{Zh)|m_a#}{@z>U_)11)lZ@#}@+SmR6=JShR@2{KQg};Bk7+@(Q>}lew_fBxv zc4@VfuXO7-mMytZSY4|eU8ydSH?IJW5j3iq=Rji0N~qW-fi-WIJsZgjLs^lc>YfN2 z-uZ&)@4WXIGuA{|Z7JHGwfd}Der7IH zBRnhGUx(whr*To10eRIZA_ag|OaSmXclpZXNo^x}V@ca^r) zd&~w$;01u9c9A{4VM22_U4k;X=P9!g<#O7!3xQe6nvz^P$=8;7K@Pz+2M=oTr%`v3 zFcgT2e%G-TziNt!yZKLP?qU;HyzKC)rK#${(-3*A0}6zyhi){ij4c-;SMDZIEIsr( z*H|MDK@nx?d5xj_tU9RzXW35Eizk+@^m3bP>~JhAVRz11<-G@R58!ZAZ!eMAeSpu* zx&vqFLmab~ZJrx>5;Bhw>$+8-3E8OE{?yVO$1KV$SEC#YQo2;mwnn&0r{${Bx+t-b z*qf2jE_C#+u%P88Lv&0+Od~kBh<%{odJJPl!K17$JRm{aL0l+PuGzB)6c2R^Xf8RJ zOe}{sYsG<|S<>yxxU_U*f)}oNkTM{^YfquxK9w12;@|xsCgkOQljQS=Rt9O%ZLI5(w`N7dKB^nn)o6tPEu! z>DADqb)+8o=$u(R#^9?Iv{S%F{z)?d~{ zF5k$!U>NN*Q8Y`D+knI3bnQHS-U=Gw44e_30rOs8s~C?Nql~Fm5IvqKkdr5s2rdBt z)SE49XJ9puji+R;D~1F44EL@~@X=HQgx`i{lSN}_rgG+n&w+C9`SN8cB@#UVp|g{_ zV;a-ud7l5Zr8(z;lCqcsAF$WgdKx{Vn^ytU>|eW_`^?sF?STzmXCf4+Wty6^K1vYhUm&TD17K+;m7#I83Ugo?xI9SR(^ zV}WDr?)KEC_k|ADv{Fyw%Q1$*v4m2luFjzMZ=YSJxK{L)695%a@B`Xpvn{sTX1g7j zh9cN#lg+l+YMbqLU>ZtbqfIt9%ZkPF#DypVtOEE8<_4wjt|%;4ac34vzSCit;Me{R zuR3V%DW;RD+IL@mF9q;1EdS1}bGR$wOh~jus0n~sLc-*={Ek6Y5Vy10q)7E2Kelh} z>}o474L2qaZHZ{bZ98?r13#ie*T0c1BjX2d=c#E~CfR`zHVZ literal 0 HcmV?d00001 diff --git a/src/fonts/4.woff2 b/src/fonts/4.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..fd7e21b3f56da135ed7b88ede8a2fb21186f106b GIT binary patch literal 51800 zcmZ6xW3Vth4>ovg+qP}nwr%S^wr$(CZQHhOW1sii*`3+VkK}5mN%Ny=Gim?Hi!lKJ z0{lml8UXPB2_PpD0Dy^?|6BJz{r{Kv#l%!(aj*jDut%tH=G?&y0K)AMA)vzA9YRw9 zq2px$0NH>@fD4d72teaq!ACH)b>Z3BJlFmS`8**_fO%RCDksv zZ(dX|05r|}+j09}HumVUfBybQt;f>a)``yaXTgP&6fGH>m3cl8SQ=Qy27n4^tO}`O zBF2_@#*P%w%uRunR3h=J{)v(Kog8A76oqzj0a};adm*gQEli0`0a` zsF`3u7!U|3P+=RBc|+AabFy-zt40%3TR-L8qfEN(o4&aUm;9= zc@vx8m6sy9s+s|F@9xgpcdrdXMl&XBjXg)iX6^zG zKNfEfo5os5V{F_CnQMddhVMj+ZV{BnOqp=dU>_ng>TKiEDNkNCt|IlAV zf7a0V#?_nu^yACwfPK3D5@jgFL!1zy)h^vjkcZOM+l9dYF2#RP9y-Uj?}cv#pMEePNyI$(!~;+Y=5T0k;#Gc(a;{p^+kW=;M+e`r6^015iq>#-fEZ5cBhVIY;vDr;g>i zU5v{9Rx&;xQl4`jSJyhW!Y2?ryg_=^qFjnp0&)G-^H<~!hl1gc*WYwr4fI}o(G|E- zm@Av_cltZO1zTw9RN9-7@c|Bj{4dx%PyjOo`uD4yz0UCpDI&#+7A))>ih~qUL>E|O zmsnt(hfXOmG@=`Pxe)+k9{sbF|BDZWouiE+vXC;f)N&IRPN(QUZ22E9%WfC{&rb0k zmo1h_855@;nNj^`M{~_Zu?`e9+QVOv{8*QL6h8P!DWMRI_wCZ~$7q!jqPs4cloi2V}u-&(ki?I?S_cXWc zyrOX>HK`LA-ioqrpr{Hiq^r99@n*ACu?b+F@ASm;=e>7&ZMKInni_-Be1v!}S%BFt z5js^l-v&=McT2MUKK%WyUAK62+`ZDyaC$xQ$$CWQTP4v>CUB}!eLW^xnw`>>brry8 z(+Wv3P#SiYRSK#3suL)I2mww^W>-#D=1xKp2E@3woGbliEN_5EY#dS--<7c*D$t5w zXZ$%?t;I!#n2--tC~2j%J^z#MY;4()qI8euaTi0S5scTCUkcO;P6Q=n5Ph750R|M? z*HZHjj>I<7sXwOrw?WxbWW=j2m5?*qsub(RbIVw=_tx3=gcs|@tzLe1_mSXBu=~n_ zCQ+j9z1zXB2$%b(|E11tE_W_>p5svfnIFw)G9>rI`ggE{f9BhJ&~~T+Y^<%Sd!V2y zAy8r^qn=$`lb|}A-0#-eweyM|LpaJ{AOrKYS3;W8adi)5Eecpa2!%~_L~qHmh#&KH z>tS-IchS2;?Y#5$Sl#fCI8Dc4RZ8wEqXRNU9U&*hPi-crt9pzZDw}3+JW}H-C9<2i z#^CwwlBSOp{Kr19D8?{9gn8PKJc=&TPO4U|=0pu9pFrfVS7mLboAl1(Bm+2z;OD{L z*N@(f-heYyIe;#eashyA&gAyK$KOsy_Jj{<8WkD%_59ju`|@ggs=phMD|)g5F94Y) zkmNr=GT{3O7a-tyMvQE_Fl0D_p?zwf=$Ur5{-1l?&2{d*JFhsJ%nRe!-bI8|1TbSA zb&LWi!f1#Cgu&~hf85iQXrz`@n|1>nXb=<}1Bk|B&d%%7KZf9o8S6>;MRyF(5T)q` zubF?eY1CH3{$>PHqDdEca`(PCo}LJ7o&HhZ-=qQ$Td#edrUpaydw9LGYO!I5xNo?Z zG-^;1mZqVb%C8cx6IRzWPHMFjf7k_qq)2sK1K_K@-Q+dESGK95mF+aHH zT{RP002{0r|EMx)lvYspe0)65x=i@zcTapj;Axs~1O~jU-1i9bp-80hNcEqLbw4Qa zn7Ma)TDeg&V*h^eows7|L9J%w@<`+hnbvs$uEt(-=flqeh932;9Zhox%5*K3U3|mI(zZP%<8iW?(SgyaFg*?SI@o`1#>ks^ z_V2Q0Nn3ihm07Q5?HTs1Sx2Xx9=4|1u<@swAd45k+GyA=ZQqL{5*~r&zu}ZLrTk%G z&|~bOMkC)d3mnq^w2S|GqL|7Gks@5eY~@QlH0k)T?pCj!h>4a|PwU4P4zqlE+y4xm zxvr$Yg^FoQVZKpHjj!t0e?W#WErfU4FdvavU`CnNZtb2Sy+UU)czb1{B1VuqaI*kp zGy#i;hKfZcwLLW%=Ou}tFLQ=RZBacjP>?KWD4>qs3Z>`Wws8Soni=AnakaTC#JG~z z$LkAww@#+&3}Lznz{D?$mCTi;fj}uG`SHVLY}GF4TF|)EV!c=m=ru=4M7{Q5El(LK z=%ULzZHZe4*hy0PeGfXy&u1_QcS-fiA?P)5as@~dC{?g>VDCYN5@b$JZx1Y=rJ1h< z)ne?(QzlR=6?c4#BpcK2?9)@x6;a7WZTP=wuiSp1I}h3wQ_&qT(*BfUR*6Eke^ zf)P>3DKZT?HDeA7S8iRrf(|rBDonf5hKeo(DGo_$HZA#U^GpH?JH&tc)=E7%XVpQ- zG3nyyQ6^NaV&v=@HhOv$n6w8exag%$q-b3O9Fo<<=tClj!p>V0NU~TWdZC!9l-s&0Jp*S1p(p!+;RGq0dhgLJUlxs=6n>V#wW^z6VM$4rJ_to@={5`iS6MBu+1VE?u;3Osn;6EHhG zSSyQoLyh@bk2q?NSWT6gW0u%>nOTmQIhmU{&Pr`P%`C#1xuu)H)a{+ zo*M1G{^M4f_N`q%{~K!kKfvy*bq*H_ZtWCEr;=@xcR_@UAUQ~@X{n6rMau<~!D^5a zS}os#D2G~Y@je6fqa4%pr#;(#Ztl*e_oIM|Y?%#X6e|>+PrCaBHb?@0QR0ra03auA5SS4Q*rtb~ zldE;21YdUN)oM`fO z{3&^TSYw$>T$YVp->i0AJjKP9$8jI;QpHnDENSGuoR~=2Q8RQDSN?)meu}ZNBFvl# z?8y%s8Ue=d^eNyuN1q~?)$->C+)1M%VXnWCgg={HBlGBgeRuAc)kXpsa^2vCnTZLsBsiNtOZUhP&$GnB3buS!a3GK0`FrkDv7ef7mCj)Tvd zw4U8rr!o^;$Q-e5G(WPStH{YVCY`N$-O*UIbrQ@dF6fCONehYu00~>0xxWL)gY)!C zFA0OnR-P|?#0fDiL(PUQs;p+-=lY&INjL{t69U`|#yM%fFReW(@&nnVh37Q*+S~&~ z=r=dv+)(F)ei`Y-`erTDD%*4 zo6uE^VB`cKlA$>Ik0Jhd?%)XoLy9ufi~)x;6hxapVQ7|b^+EI0jQvPPaX~n*&z_NI zfR+Ej=;@_#3D8=AqT5vqO=*gzwpP-bfNGvaPI;_F1FJw^Ayf?%Hw@mp`kfvuR?onN z+&Yj+)ivVqE_*7gs>-vzltS4rAi(iU2>!dbTWi3~*Fl@^)Xv;1zi$~o z8e*{2M&X-|95X;v=H~P+Rr@DV?!+DhV~r_)VPpF8$TF*+rRQtvIg?iO*PT`n6chJ# z;r<>w)&^8?UK^I{+YSnfda~rt+~NesnWrSXixES}>(*d&xqhZMspJ*GI+bowYZ(NRaZkYv>mP>T5im zhsna>4;sX*I#1THnl=~Eq~`Dy32K{@pEg$O`l{NHJTy_TJVbf#Y%TE2$wD_&Q~y0z zkORmi*7f1EIQQ&=TL4V+2WJ<@zVGH8a8nzGN9Ifai`(q@#f+ljA5Zdd}B+deq}_?iN_IXXaVuY2w5@O5YXJJ`>%kVjMx zeY2`f<)tqj6?ukrb#%v1RFq#}Y+z(~w123mVl0?hrN{I$j}_?^jd*tj#w$j)12>vF zv(}{inPgCPoqYlJwWpm4e|mDfakH;O#lHkh_oK4-vM;4&Hg{0Pvvi`)GsnGT-pf>y zH49)Lz&PMF3dG)*2g{d-cXe?B(*QMpOIj!RmY>G-%4OOpR{TH@$DascGYHT66KPethu}3ngQZ5u^d_t%dE}H$l`&i(fS5aKq znQ2wkl>4b|9>p8WaS%PF*Eoh)rt7pM+(rbyG)OZL!r%57PYS@*d~25*VD!ZM6%_4U z3K@2MIDYGJTyFa6&WB?ES0VQk+t8qSn}4+HSJBb-k#AQTKm%}t5Lnxd+xT9f{QvMhSw zTfIyYLGa9Ot<7<;2j~JRg##QDK)=DppD}&2ujbn-&}1PmZpppO@$C@n$S(u$5Q2l=f7s28&cIA2BNt(Z;cQu0pFBN|i6 zn{b$HH|Y3jE=<$bwE0?96jXg^U7KO*7wE*Zn_ocjqO`-df2E+|umK1$1R1jlaOKjr zj$Ra5hMc+yq#6sYIt{hle$gc{oGyO2{bPg&=r5pDEf>Np7D|mv2(7|J>FPZ6yXn1) zT1z*tD)U@hIrkOKbsB~U%XHn=@Dsu=hVXW`CyyjV2`d-kOmU7f{8>t=i8H2!=!(gW zGv+)?3&2^16S>@FjI=aVa4MW4=52(zVZ4&d(*@^~C0d$YO`LRjeSn3Djggg^ouQ?@ zsI9TJxy_+UCOb9**Z_nW0*yEXxw7fn#;%GiLQmWUlTAcdT!xx$mhSgzbj(m*IQ~#w z7lB_rj>*D-xblHryxAmzA1CwE!SIE)owaWGsy!iNE=1VPY+Kp4Pdl!--TuSbuY2A4Wjxh1*Z{3T=y4<>Nj(+}mYhr035R1qLFxie) zb2^<73#4Q04NIrgC}d#Cay?@*TJAQ^^zs+Zo`hOD0tQ?arTtri8y(hUJ`#yu_Z)L7 zYWvCzK5w=)0`4x?@M?@h-53t6HfFLyJW?GP9be%IH9-Srir~W>t35^7aW;w}<`j*J zE|d&iAlNBiYc2#UMpRXbc!X9A#ff9G5(o@~;`U{+_PaL>L<13Spw79rV4te4F~Lc+2|5}sBcMKV>3h)(@j%(;*CRueHM zCCMby;1FDdKp_PzO_kp(g#v;NQ}R`L%F*fdnSeowowuK`N0^nC5Mqphm#j|HFU`oa zXkR8b{S`Ui-!B*vjb4P7O14}ypTr7~W)^HGAjGt8mP8~CQKBFq%VYL{lCoQtk7Z0m zZBZslJG@QABTuA~Rtil4wd_c>yznIn4Io?@Ra_Au^{Z(wmf-DKm8`iaG1Ev(FHK}C zg-rvp^{`Dz#SCJ3vTw62bCdY`hb zxfNz(S_ZyFVpD=I3=0g0#w7DDp_ud(NpGSHpI(A$j9PEu`;p4vN&4*MpdscsvFpCk4qFd09$4tZ zum6udRcK9DUdo!SWVg9gx#CkGp6P<|wZrL*&D0gOI@{|p;`$_!M#fBQx3>#Y7*Xb8 zrkF>J;w)O#QYKIRdcomU>ABPC7_G#mWc)??Hgb|xnyv1-Dv-9YxfQc3PcWQEZ0rn7 z|Mmr`z+$gU{?_5h4c#tcpUm&}>DW`hBlYU#5?x4gLU2VQSfrez;1IE7k(_GK7zxiY z4ZO{2#AhpLZz7&kJ66Xd=J?!zkrS(~T9Aksy8C2w%C|C^;?=1GiYwB)xmrhkm*FVn zlSe(f(RsC6T>ki08hxiTZu z$Ou3!cR&Itb&&xf@%$~YN>oT4g)6kErpBruLn)@oU$NdwIFePHBfa-^ut95}Y3@ygeOcI$KE-s&q z47N&5(JzAiR?Mr@XE|D0NK&k`P7>@yv<<&=4!FnqJEmf+d?$01(U(cb82)8`(rm)t zh)Hqk@~R+X0-NnM%KEVh0`zc9UpW+(Oep!do74H5Cifd80^ux7n%B z6+Ri)5n8J;AGF{_{?cYm%SywVRTWApVo`^@Ih(A8GKR;pdg~c}B!Xy*k|i6hFM(e8 zX;N8(J6@;@;-dJHpSw6_)%J?2X7?V3t#9Wm0V5Z4&QILqqH3EA&a$4b!SeM)SBGYX z>(mUB8Cp79Q)DZ;(5cMd>Vdt?I~wkRbgT;*U&782f1AcnXVDH8jyQp(EOMm2(^^mu_I)0SrC&ey1yQYj(;` zz0Aun7R$=2xPq-9z|wHF{%jKWe(|hlyHIX#uCo#g8^tu8cC9ESVpFw}nTJ7H+SZk2 zN$Se$TogPf+g8&j>I?^7Kfo6qU_ed6yZGY3TlinreGgnRV&Ds0f+qpm|SBL?3_ zE`?vwo@j99-ZY2^@og1)pun|#tT4&5$b071QKWjG%xiBEC8{CFaW~ zW6DnTx}q!0?XHWp%h~KguX`Zh2mNfTY*I0V>@cxd;d?MF<|(bFv&4^hrQ>F&=P4?S zKqPr#xU-V`jXh9EaBSF27%hYjP`%b_I;XRP(_Xy9)aC-GxC#k>O!FsWjYhB0=p?iU zJT{x-!{O)n5td?^QAKJ({(g?F{6MjKG#Ths&u=R$gEJVFoAP7I9h3X$u|qnoPP^}F z{@~~=lnlL&9~i5k-&jxpg+!&wA4gUL3k|HZwFq8S$3;|fz#BgE%zHfkK5(*&letY zcmyJ~A|N9rX@=D2j)w1JRophgN(~BOzHZGT{u7Vyp=8-K_f=sOy(SOS=K?fl2!ZCi z2mw&a%fIRGinX6R81OWmP)?PPw!3t%->cU8krOP{=Pt+BDb+8HLbRH+gb-xa4G0>q zekXJ^TZYHmy=tcgHw-Gmar~A;mb|?_^D&>ffabHN2V?yqFiDmS_u~meA4`e;L6RF5WT9S#&sz`nQC4mJ>&g=^UtbSL7-qXc}`7BLlCb;3^Qqc+IjIjuGMvV*M*s)*-U z-eqFo1@CZu`p!O7lk;-vXg?bY)iI*!d>yHy>&%FO0OQGxXyrPG0dn%+1nd$|bGcFo z;|2<5Fm*f@&$hSom?V?o9DX)JWQ=PIlH6LOUY;-%E7Z+?NZoy>c3}|?iAw}h{iNZ1 zL?M`juXyy@t#4|pusYg=vnR9HDCpuKjg3sY?Vx5-uvx^MzPM4+cnme=2z6y}_E-mJUpK^-b7HVa zqYU(sfM}4{!ZCxnVBs^C_DZ7Uy1l zaCW7CGIPMT?Uov93Wp(7y=(69kQ;w+UGs4V|F3}$BmRBhw+Pz}z4oh# zK{Gl<2WJknUjlFpQ~~}CLv?!>vy_lzzXLmbv9(Q*1Kc1S(*Ll5?i4PJclSAt zZe>|mcEHw|!Mh-#N>|3KT(d*6q+Q$M@{{^2 z3FP3-Azlb`fbv{0NYy=M*nW<`K}i?UFcwNNL2*Hm@w)a3|62HU=H(%N>Gea7CV+Z< zxWCyUH)+jt`VCATt4k+Wec6ww^v672UG(ynS$l9e-`g5CoBI7Cq4G5H_`l*tx&E%Jb&yd>MABQTQr=haZ9%V(M=( zn2D}9GKpm>>i@J>!yGfyT({z$I#bwIKmPYx^1`?_TiH`06GFv$$zrisC>ut{`w4@= z1mvD7Fd#JYNv0QRQn6Sv5l<@Ks^bB5Os#Spr$jobLZM!yRnwV#IG&7Im3%}686cbK zXqY1y_&rV~hv|d?eYa#*hAXuZM=S6DR(?1Y?Bm&U0H&Jv< ze;BN+Viq$Bp>-6gO6M`>IOQOnz??g(pB^_D5{^Qu6+G7q&^<`s_tT7MNa_$?Zghwl zQG6H);E>SXasce?#?d+3u+%;9!xr}?KE?-P^UWyztLE4R1_cwNIW<0g6|B0hJ70Rq z6rT}m0V$_+BVA*OA(GlaiQX`G;0y*XK#A3Uup5Ywtt6--n zAr-)$Y+qDeuk6ZeH4I(BFnvI6men;mpN}=nPvND}<)JxbLw4jajlwe91qd_s*{lZf z9)lx0t=X_b`e?P-vt@~mC6(L#ma$FOGw9jN;$A2Vy_qL^xQ%wQTvo|g{78k!I_F7b z6p=3C+DMhmZV1k#d8M-u@(7l`K_DkAj^K-pv?T-fGNWm@O?)^FQS7GEpy*52qsHwN zDjt<`UingZ%PJ8#cw!LbagQ{W(B~?Yw!&FJ1)!o_ z3A+jcAwJ78n6~PK$uR`gzbB#_XE&q24X(hpQdxBh>+}tVBr@6c)iK>2_pITOM`Y9UrwGFRw7s^?9zSTIySL@;@30+C+bi1Kto z7tNBai3jTKO_}Cn(u%o+%n4-4Wp$7(Z7GH%;iWyHjhn^?7R8#4l2*WaUKYaz3DYhA z+#60oPT&4Ckk|V5W}o)*-v#lB8D!UGu$w3AW>d;3y0dt2a%d%>{I>bzYp>go zJu-ykS>QAis^3n`%zyb3`q3%Lp9MKnclZ1JtSSPOIKIZ5KqG1tZhS^U*{nAMemT^P z{^AH5c#g1{fhqo!01j#KA^yF+77Uaa*Jsk$+*o#&grWc41?wJ}J1KAOrLh8fa$ zB0$HD$tUrqgeEAu`J$*LVPCs=nN9tu(-_YNyjWy15EQ$p*p8AYlcFAgA5_qMJ!~CS zIAl6KOWoF@_)ju(68N9xKHte?IaAPDLZfYvJTCqM3vccqh_E?N76xDOwNSoIg2Rp0 zcGmg?(e+q=X>T**U<{63+X;I7!`)lmc3vSu{FlgG` zoIRA(-J22jq(g#}#KPdDc`0I8*racb*2izVox{ecg-Uqn% z*`499VzSIW-ayl^xb=GO2Pwnap&7m*jUl=o;6FjCI~E|X+WSCCU5pUbFkb@Y8r81w z6Uen29>}O++7@MtZsk?aC|&YPT1axMfvVCJ=@u2|>u!F4eawH>c2swLpMGF{k!J=2 zX1AaX*IcKwz)O9my+J+bc;6*gO8c9Ej~46??h?5iNKBQ}Q}&F4J5wm^<} zs42TQWT&RBOnF-Z9SDhZL)Vby584|IO0F~zIlap5$|;Z7gysAWoMGmeh)% z|Gwez`Sh;fc|HDC^ul+Z{{9@HMsV?W^44TaN$fR|?2<0WQCFI=QWacBDzh&Qg*nR4 zgm{_HtkXVgp1vqb&v>pph>m&_eT9EY3*M&#>Aj*KFKYrYl}hjNq#&s7R&+q|ua)OL+F0jR;US+9qr@A_eAa ze2~AZ0}76q-)c95+9)Ul!I&0S^v(HzhAGIl>>D7t!y&dpL?xpD#?oFK&0i(^0&yr| ziuFqwDzSZ>CxvRu)FzD&KlH#Em7AW=?{Xw7_AAG9J|TW-t1TgaZgf%t>XEe&r}*W+ zTlQv2?fLty30PMDiaZ1*Ozj2uDO=VwGi6pYt!mh6up%QMFflnOCnKFCFia)BaiWhk zknSaNi1%KrsXO zCHxrNHxLcUhpGWSbFDicaXo}VQ0w6c6o;6cSxdMA{h2 zl8-%^9?sE^ie>v$8rK<@uGSBB99R3Bc*9v`CrRqX?A@UTRYmhD`L11{T{$436Vgn& zz?cY>+T`Q=Ixh4qg&>!XBt-0I-^Wq^<@)1Zkog?TbE_dA9$N{IQol;xx89@*#^2MS z7pXLora~;jH5ztJ$&WDB^ml*Di8e=5D)3hka`<%f-}`eGf@FN7emW0gp(fUJQfu-c zZZUF&G}^~O)7t7EvoYor*Kg5S<wa#G>9cJhYih@iGAR;-n-}k(+!2#11cEo`3ffrN9Q?6D9iId*(vgndltY1;(;$4s z#-&Rvy#~!KSn(IM6BsJpIHmCKEfAJ>7SKO!w`&*1pHnY|_OSC6u3J3Cm{U59lO9W2 zK@6HBL)2BC*WC}=*+VOKG+TyMIp+!xI3d^^yecQ7sf*FwR7E%6jvoXOB^azWum}fV zfE+cZ4W~aMxPc+MRN!{Z*I8>*B46&frDplljxBUYZ|mF&>)l?%xxeNtpAfH7B*Ydz z?w(*6qxVE@i7erLVeDOWdj$mBX@f%J{1NPCAxwV5&?G0b7r8%1(XYK1JH}HB`_;lr%1mMNz1X zx?{FG-7$E6YqrZv=AehcB`CqxJQT8gV@gHf%@Ivv@=}a2dfJJ6f3oOhZOb4F6JVWP zaInaxY~8evpt~M9f$6xHJ=(wIA=jCo>!0>HM`QfOt&}BPwtVV0i3j%8-SLg)`}W@_ zYCj1FbwlNa^17Ah>iizJpd@=x6CZ{wSQk{R)0@IMqDGz-WPT;FTB=Ys0MvYv*g91tVi5v zKFDoYG?6izC`guqsRgn4PyrXGZhe1Jj{!mKRPtiBKKp(?@&^-DwbrT(oZM zSU7`w6GJ`rlJ=3y^g89kgt0yTG@WcP!F)g604rf`n#`#9iMqx~%Q^XbEX%1-UbB|g z-IBv{J!P{W?_bjy1#eGjJvZ)ev7Ei((5k|FA#LDV(i_(y>u(G=>G76$MpQ~GyY_AG zc%v-_sw3?3VmVJXJ7uMGoeDVHMhW)2aQz06{Ld$x~*gc z!%ogiNSV9vorucD<>%3^8m(UGK%;WwpQ*2V`8p_xslH{$zDE5!7g=_RZ5b`H|A(I% z_=syf=hBh_pV~ka8PD$ZS~%6=nB|>lO1-RiXod=sMc4-tu&>e8s|;Qdw&#ggQREf< z_0CDi`xTJ>2waDh)FxmYc8LpDuj3)=`;soupNkyl2V>{QBq88L;HCgUKeiBnJ43PD ztPcg9hAn>)X0Cqgo_Vr?zRrrBHvzl&BX8diWJu9W7X%7Qd7{9#uc2eT(%v#k>K4{t ziRm9FD5>Pp8_CH%+@fn#&8CvIpwPipHwXH2dWpR&vCtV|3}gBFYqB$oEAd8^ z&HT^Z1sTf33t;Sy2V%LO5mn4|a7$Ukli2G8;2uL9l}QfU1PQB2jx~rr@>84EDR$a` zv}z?SGnX@VJaX}YMkMyE!k!&o<3~$73`I2N(QN8N;xKLf9H$b6l(F=RhfwwjhrgO} zRY;n|s!VJTM=c;tnff*#@V!BKrBo+F$FC@~nW_8+9Aut86oDbB1*0>K0C_8((S8Ya z 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 z zK8S_?>WoFJ-`O*ppf2<(u!~}rmU z;<;JqwU9X!{PAzmYNrfFZC zd2z>%zPR`BTs^qYWuhRF(heOP7fGe)nR7;b>=D>ALrPHF@Eww)P>2+ z!@R_hsR>~Kb7G(qK$Bsp(mQ!sl`k;~o@YjnA2d)RPO$pJFdSkIkzxkXXoSTImj;YQ zE+v=?caz;ZGolb@o`KLn?!z&1)C8J!mIstFkcJ1K>l!Lsyqnc6TCvFFJB2?Vu{-Zs z6|QLKqu*KdhmCXVBLU;>1iD)dWzA{*kGmwIQsnoyr!8=i-y&Mpg`LL%O-<2m5q;Iwq% zV)4r;A<32=+LjwU$QUY=vZR?LnV_k}M?IOf148%!+g6JOhvm&llIKg=bKlXn@r z(k}c`h7};1apsBSGvW9Ls8;HZ3DT;b zrusXVg4#sPVXuYw7#=A1i|g7Vt{_L5cYn94qNhP}j)lW*dm*7QsP-TnpBXi0dS%qiNF&^6Ue4YgzynLfX&YJO%V=xDhU5qxG!F7!!QQ*LCKACtHcK2EDJkaV2{ zR(I-%kd9+%R)2t}31Hr?!q+RMD}GAu4105D=6ILl(iLrX6IQC9H$BosLl;{TRFeb#j6B#$9Nss#rMa-7c>1idV)&f~uMvY9kFJ@3UuWxLG z4GYcQAKjsu^B;U8Y&iH?47|-+Uq2QfKQ<@@DW$T%zcUvq*M}a7mnYN7OaB7Y$5j4Ld(b4zI)Vdm0Rcp@ zP38suZ8HlNWE3ta$gLPBMSUVOG_xQHlD66*Lbf8S(<;%pWyq|Ko1e^sfp?m~O&jCH z9_mG8kaDN0zq1q6CLj(fpzcv-Lqw31c3-?G*`B7}*PA|4Y0hn#KpALTKaJAz+9*Yg zHl_=cQ8LWi`jKS+LN};cdOsrt&Xbg=uP`_TfU+z| zFvr2x-{?uqeF~c4@32bALhK1316Zt$4o7MzO3opn1d_+iXa z+^OdvvTGH~BW|THiFglC57>-ZCEbsLqx8S^Q^b zNBK)U)GmR!ZtNJu$S9fKtaVxlhT^z3x)R_+ISuqk)<+(;b-7eSL(PG)JNiX8T_J9| zDe-z)s?nI7G`Ve?s* zST_fw2XGfHlQ@COXox0(%0jlWjJKWcM zpwCpU%Hy*#?FSRu{TtF&s@ObMKxNEjL`FpJe@*u)H|o|#D5~mGpGZ0NGwfGiLhGVM91zet>t?l?KiervXju}XJeM=3jBScOpJyc3*{ql-xBwt_BCCEB z*)k?b->FWH^u^13}Qwp64ftV3SQn?DieQFHmo4S)8pbg8Qy4I{bV~V4$d((wOW7s=KA`#btg~O%Y*%L`jgsiB0z~0c_C~56#^M=vQqsF zeu30c4@@xo-9pja%)a@AVjZ#d^Z{|{bavtwX$nFjuC0u%jqKSP9GES->v*A2EP_0| z1t;NRcT3MdvFD&ZY_9&TL;!6r{ zhsn{x62Y;yfj@tKcI-T_KG&D9WY6ONI};4X?;iet5qRR%KNzogH?nU@qU5Z5_?^+X zz_n<0P02TKc>&hEz+5uZJOl0{wc+9ce^JZw6loyXn=I6`3h2wA3{S`$C`{TbGBC5MXAWeBpaOA3Vsgiw0g5YuTa zS+u=0itsP)>>L74XhfS$a#h$sLzL?@(htVn!NircH}1xH1Q5sS7tvR&;5s{d_5p3# z%%|QsSJRI`H(+ptBDp^4tgM92ZoQH(CUxjVmbRJ(xAB7@Z`Ta!5QC+>)!Hw{dfeM( z{!US)Y8JcnhB*(ZS~`#kDwRsi7%t_L4VhY!(Y7^pt{zbJ*i={oNOF-Ac|~mF&UCAL zg%c_QYd&RwchxCU@V(Jk=(IfDl1)&k=IpK>TxrMgVvfL3kJ!e>U2iaS%hpRPDh-A( zLS?+axuTJpp8rG6t+ulXFXr@Hw~^?O3+M2L5?F&W*_2LYKmia*#@-6a7N%ZfQK?>_ z{G^~Z_@;j`H&5PFV8P7=52>o(R5v&0*$~?Q28F6-*|%vMAOi+hW)11pNGe-f#<)ES z3~5CO8`Nr5g;3F@MBnU`ALMtjEia~0ZKZ~^nBhxeI9H1OmaLmqJv;Z}a5r8g+UR2? zHmo&emsEEbMjfF++Q$+oC>;YG)nbsMUBC0HfTr(6b2apx+F|n`ZuvvdYc%qCHN@b5 zCHv#|6fV2ZE43W9P!>&64)ii2Qxnvl@JLQ0)R zx~qmiRm^S8Q@rPtQDT~p*V)o7l-*$PcG6_)1GmE&#SPefv7-MS4nl}fXc$#!R>F=ib;PUnQpzuBv=P}&qM&XEl69ok_)Kp^Qb zXtQH85J`qI@Wj?Ud7Lc9IGec`>^K(?1f42!q|&V4VY-}iM%<(TKBCBsNCR@l4 zIrAC=Ug!N~bP1(o5zxSe={wNXuqFu5{-NP{Yn5p|hAAjZu6=~184?}(sd{O zHb!QrRxpdDJbFzax)!dR-@Nj7gHb9-P|ghVN9kZcAV{e;hxxzft9`>CzbkT)PyVQV z`R)$}2m3OXk?w{`?sS@f6pn#&u&?Gi-KEbM(VWUaAOnkxii|C~bhMB)VvMuO$`s`V z)({zAH#5RXT{3@)Zql_2(o3kKXg)6*IQziK6F{5krqN+O9)*ZCX$3UOj3P>{Cx)9n z0G=>%UZnds1hd6c^CiBKhoq9&!gRSPP*kOqNch>cBbOOD$1lY_OlZO%*+zREq|~J; z37i1VxmZ_3nORkt8KIrkDwUH;^-hkF!3_7+`G+fH2JUqTve#xDMB;pdn35l8dBnH_ z152NO_St_gA#J2i{Y1aN&-GtketX-PmJ6dWjsWTPn?e9oK&!uEMF8%XSz#TjbGve| zh1p|>j-*&R3%>Kt@Y#1{3U{|<^3e~v_Mua4Wk5ePVec1SSP$!k_l%31cxE39gX|Ep z=ok2ev^QARHInPr*EFuT)Po>p;Bir_aGwTpW(x=Yt7PyVaE#s7w)ofBTy_WhSRy3I zKgXOomzLi6Dw*F3Irquvyt%m-KD*Zb>1)IlS9)$-Vws++$oc>L2ad0fAnuoQYwkY< zRcGU=Xn+ zbmaZ}9DX4sm+9n2_*adSLTfY6;caf`)BLjKWBiQb;I61L&3Efsmpa*Pt!zNf9?1by~FP6Gix3l>Ae6UwB z@52>`EB^<0la)9+V`-`dLm1QMzA1w+1Tvyhsaz_EluOQ=4TmiGGOgY!Nvj84fxreu zmf*qL)yDcP4hO^R`K9#LIU!pv^XKrOhPNRVE5UPBB{>uSp z<&m`K2bSttKFI^mUu&RJ^9Evf#HQy}FN&;)Y1|pRJvJ>*zNz`+#UCzic8iBf!+T0A z6ky&hjUBGASL>EF|4u&LzWUw(Oo)2*YJJXS{E%}fdM|%J{$Lub1?g4T*8F)U{3#_t-P@<)U+@W z7<$rIt7A>EYONZZ#nmnjCmt|AV8q=BVTR@jPY=i+@9fOk?cti$lXyZ=tTb)UQpQ3~ z{6}aw@<1Vj7se;T^kHm1|M0yk;t4N~NutW4(d{?o2f^x+t9k3^iejroD()+=qFMZJ zZgTzpV~Ku&8#yf9Ko`zcj;W0$%**<2YHdV~hv|UuE9ru|IskiU@o~JF%tvtPeoN=} zzEb)I%$Jq%ywHG`y*qdCA7=8Mo&3@zgT1|cT^;xT1;l=VTygQdyx@{n$8o7WJEM(f;nrP2(98BB5W#|`dixV)t!BEd#DW~qlg^Y> zki%ot78>l?%of$lcb(XrZxcA<3*K!}cZt8tqSa$7K4MpptpB(_3lw(4d5R`a_4S_` zJAA+qk}u18|FR@ba{2u%eJt~m<%KL-n;ciz-d2=giZdl>LO>+bcf*JwqSHp8O`?gZ z3r4k16Cm71_$+$X^FE!M*T*keiwpB|`(|H5t5z*qH0yG$3gmHHnJAxN4 zM)kjYvL%#*92+07@rqHDU~5Lmr1Fj%=$Im`_eL<-dR=uv=d zo2xM~4iKs2wUL#&R<7byAET~97dtXRl^aHJ@G;4o4-m@$-&HwP zv2AB&3sGZuK1^v>2CTTW;H4y$sQg+{SneT+FWCJ>eEcb5GuxyNngeQ{o&B{Y~v1FvjRQ0uUa9h#WX)f_6Rl|ybMl|NISkSb68oC^WOUI3J>D@ix zoN9iOU&TTKj*oLRS8e%sU19d(!fgL+H$Mpi<19;2&KDH>nkWpr-MOdv2eX~Bo9}{3 zTPG>9+_Ty_(VZ7^YHQck)h$RZ&%QB|Ya55-(3W8^FNX$&2@tIQ|*fi z2v(tl{aOMM)Rc(9nCBV+?%bunJrBd?-4Wl6A$WXFp7)6L4AP~_!)j8)!c#*Op8Asb zot=S9YCt<*-0J@&seDMb^8O9@(A)hV5-ORIY^VlJ-P-Y6gmTrk_#LZDC{*nHtW?Qr zY*GBGph&7|20%a$5IOT|f=v_Cz=>@F!6-VLMNHdijsr*m3`*NbBalpzWjKxqy}H@( z-8za^?>4M?(I9G{yHjudoV|QxUrn*4ak;!qC6W(chxNIE?)xpPm=_YT@qfDpBi$+>6Vr>4 zB~RZ{RU4A6UFfG)woz1@QccVmfT*oi99mP5P*5Wgfr~C$+{D+AE~t6tu-UBg6r|;~ zb7dXzRl_j>U*pj(hZEbLNNULn_cj=@boBN0staRp^U}oROmMoiE|bZ{U_xxt!#4&3 zo@cz!I_DkEk8{_aC3&(ka zgtF~{TK%wN9`3?voYG)421#v!1>KBBBKMn+WZ@2>*Qtb4Ugo4GhkWx>Q1u!j_w2Xe zg{U3>wlvCgH^un2dP(lsuHLA;$)qKQ-mk0jQjB-$`^}HWDb1gZ^qkJyvRBluv0Py5 zU3)BG&zXOYZ>XO&T%ttOdALrWV(cXGfk~0@&41pF{sk8x2GKCqzdO|7Do9?JP!^_KE+8Q^nQuU3tY4bP7C_3?duEk7PT8eH44q%PQVZ~P;Ua%~c#1~dmn zqpjq1?`_fKSMF-@e}cBv#U_Ti)u5eFt-Z`(&`*jyif#klXPa`D_r%cWi<4G}H@k(} ziwj-8| z8L;Jlg3$QxJX4_RjhGi5N&11N{ocpJlls2cI%kIr-E|aRih#wQ>;tV67oDnT2iy9+ zzr3u(yL)bU%odXyqpMx6C7>-OiGQtC|J%QpJyrU`z;8Ea=X6DV^Ck+$GvHFL>TV#6 ziZpqJj!im+qL3$Y^6McX8IYYFV5e&W?f(WxHID+4ynvV^e+oY(u^2 zM0JiA=`S}Ji9sjm`P%PVil%hI&oVD$Y;y>@xPmX`s`70=>2)jge~x`4t+ z>Jx?L)6ELWr(oy7;HXs2H%`$ci&h*@Y^dkUN>{k)VuUDhe6q8L7O(@cQ-AYo487NFy#PnV1p-4KpUj=jj2&9oPdyn5}LBouLr;d zmW4=1n#;PIg9@Uj8;i3N$`k0EQA?CVY>i4Opr%j&wX<5;2In*uDU5`W+1Ee(6E{TU z)a#pgBVEjZY!e0TSP`5Q)&H8LEv@x@5A=>jL5Al2!j`bwG}tt21^1Pi;`tdiKD$V#YXpP857~5% z6;wANOXm>)3}Ge)>Hu%eGt0lizX~EsZic=na9u&NCJ^Nh?`+f!qhiID-2VE|4G4^Nc zU~X|BmasVx3$e4S5{u(uTuO!R?YW;4gq+Y2%Ub_rJ{G9tXaVWKFk#2qpjq)1_SL)h z1uEECtzu~macBYJ`gQBR!`=W)j*@oL!yOMzqH=Z&nw~gJBPbwqgUvnZk4`JV=1v}9 zBq6I|@0YK9`T5+MrOy8OICe_`y`46vE(`G>>#(RggxKqZPB}gD^XZd&YtP?^yRqtbQ}(G~%_&9x z@8EDQ4c>)c#PYC<_&P&iPq>!eD-(4~cl#Os*ea48MRd%RJkMKMS7@x06-$Z>f{gQ) zeYr_~okeG}Km{;N(G=&3wD^lZgIumVvoAUHfcx+*fhxrth~Kw<#r=5X{&aB-|Nast zjoCTe`A>W~XjJUeH-qXeoqPQVmLRxKRGyREc@oNl1xXe%L_lIlRumo4u}diM)6mjs z=|gF|ES^Gc;7~HNMKZMvYndm}x z;2WUZLMot+is_x&=**3rYJ1-PD7xpu9v3hvK>S>r0mtr+N!Zwn2a6gdWHy1 zsA*MPI;S}=e=$#$umNYBt&=irW6U_7KD#L5zYtSBjHj*`wBZqHF1w2af3 zO^~kH1}?OxjVSzdbX8ed!tm_kcy_GW!o>L$B1KhdD$n}FEe@(S3B!C)ChXrG>UikE^KxmLK+(#(=Ct6^~H)lb~;MA*w>#-=opcgLki82}@Y0&F3NnF_G5(te& zF8ahu&02qM+RXjr%y@thh_3-izO?Q(1gi{4Bsu~n4X2FZMa#?u@RC^ciPCr{!g+v^ zr&!2tGT?H;DZReHm7cCi=^GrVQRRtDiaCdZrqJcD1gVbAmw4&O7vIVBbO@7VoPksv zEfjTFiHQYAO!z<5>@GSP*WUln^)*)Xe)RRZImiLO!Kq7cP>f^_D^x;KAnX)GgrAYC zRbk@o!mKL3BucB&M$HN31SX*>Jm!LmP*tF;9aAF=!&z+(!UnR3D~~B6Rr2N`5$kX+ zO#AYcB9l}}QEvDY5~vizis`Zs0Dx37z(Kboo=+M2<6FLTm2)l9P+~AI;2MGN}k#-PlQ*bdvC{YtwBIwTn z0{ndz*c04PHs`Ch5MQ0AJz=F_zysFHw7SaOk`{NEfnj#*fI8PZTkoZpLxF90qu7gu zWta6;yO(03pYQeXC%fBr;=2~OX-9=v!eW(;Gx zah{l{##0ngDxpW*F`+#;&nbaOyX?q`nL;H_{-P*9qCh&rR>vGCxgupbD~v!yZz3&~ zj(d!iLf-L_ua1LablEJ%y^&TJt#AMDbB6*TSTGPFb=)86V<=@bh=cJ!c6}xHKey<; zTg`huee~DwSv0ZeJ&mW%@}{$EoSLXF_!jfrb90Uy2wwDWbGNp7{nAf_^^0zWfI5AM zfog-4#{m*j2CKG=8KO(ag4d$=JRmMPR6vLCj0(*^{%Yt`o=aalEsm1znXe(4muO5r z)yw@n1n$L&TR7pt7pu3g@iy3f6s?3}&03I`;Fphehz5lNH19MTTs)QREh^xSLF!4s z*%7wwTQLuj!3Yn=>(F-vT2y_xX58!&1nEG~uWOr4^XJ}+SpEFwSh0_+x%v4u;iB02 zajV5XTzE|648{g8`0&DJBJ&S#TCllnmRrz1QZ^OQp$>%cb3t#KU^MeBhu1%AuJyW@ zqDhM1cWd=Ufh|Gv&Ac25Klnw3lq4Nyx8~fdw z_X$KuW4gqmfJv=rB0#I}ijfkCcz?}zWk-Osgfe&uCtv}c zst`pE)ulZ5q3jr>mHwUwEsB6iljzMCqj&SM|Lsn&G7lH^_!f`f6KdDagMcv!(@0H{ ztujJZS5Fpg%m~jT;CZJ{mira$RjjOgUvfDsUltHg%o-e zd=S*7p+xn#5BS6n(@${0?$S&Nac$7xEqpI~}wG6Rdk#2dAe=f~XwG;TW}Vf?YUZ zg|0BL!B}7}FhV3|@bpHYQm1&GXTdbBvUadXsq7h~!(EDii6F(B{-&URCKTZ}{)J7b z%%#ZZV~}qto0=+vn09h>IT)+nl4TN_{(P)>&{1@_G0XT=;y}_slGn$$sLT<)XzKa$ z$y7JTT$m2O-UNpAdPdr_hhwyBR|o-oBZEJw0LD({L1&X?=X{SgSf+tyt(7QeTZ}EU zN)`WJvTCU0qzcoEMXw(G5`B5_RZ-Y{v%np0hkCGda`*PS*Jrh;sQfRR3WJ#0^|V2zRe& zk_r=o0TKaA2a1^)v$d097zFB-V%*W{KUf}nqXh_ehdtr1LhU!Qa2`kb*n96i=IYOK@V9O` z@eu#`Yau(FPxT2YC`y0fp`h|*Aulv|(%v0y#l>o$VnMN+Ht{^o5_OB;I=>Oz&6!s| z=UR>$K^25MGb0uQ0-zH#m*wfl#sAb!)c#ZaUb2ol!A31u48! z2l!Dsq{GCwp1maoZSM!GtEyiAYbxp*e?IDbL;d;4t!BQVo(IgV122#@qDbvb@Vt&7 zjzbg-|93)xuJfa$P+Wl`O`(rN$&n!EfnSUAqpGA!`o&(b1o8-lYSRvcKr5FK=xi&rW#h2 ztt}faiwm>^r!jj5B0HA*=!e)L#l%0<*CCOD!6qaM2o_=nBl2t#M81&C%ZV-o&>%d~ z)m2zvw-*#9=kig(0Y54W3j*LKa=-jcOJoK4+x%G0A8rp|Z>jciW4JWIJFpc=`5;K^ z85sETMPU#rh#syn-tngeP@pZ1B(LKfG50GfI0hX4>~&b`^&}@2k}UQUlLuXcZ61VP zmy88ubWl$I`k1$3Olxovr@`o4Fzcia9GHCc{iH4Hl@2zW%hhP=;?UR~cFx)cfW4)w zKQ}D^BZBCU*Pos=o+vh*@Oba=-2W*RyQTIoJTWU0Hww$Xoh-W>!XG?O9Y9%Bp<02;xKesBE3} zc19~iUmsQCY33|?XV%Ui7yYu1wdL)(keBHtX#c%l-}%vY?B~weI%a&dPrlBaH@_we z{sWqE&R#PL1V`Xs)$B23%Z$oJ!Kb#80Xj(WkcYAUF#yxim#S=RXrTygqNw2>O0CNbp{4xEgG~{?Of5>7A8nY69Se%Xq0A56IKr z+tKUC5g)mRc|{Sq)=Q4|TJDHu-x6LTr_hkxM?UBn4AWYaLvN)9~`4vGlTpzyJZQ#~gen()U0 zi+oEVMVLZckqh-hS?6b}a)|9`FACmXyhabSiw%^DmpE}=?+QX<=oO+hKb zTqU`rTY}6eCYmXq^t;>GPqlZ$!^Z=H45zOYH@viyz0H3z70O&%?9bM0ctI2XICrV7 zqq!2QetF&|u>{1c#u(b7Loflig!%vY|3Lng*236VxiJ=VQ)8bii7W|0u9fa_%OvE- zD4S+@Iu}MGi;hMB5dbhJ<{1_m&6I>TNeGy^;OdNRZ0dJCMquXA{Fq_>Y&}`+%`CKXrmG|^ZGkwHq9~mO3PxR! znP#Gyvq0q6}b5DIxMH`B5nOUZG)%lf4?SLFWFmH{h@XJELY;oov{J1(Nhp- zd;`4e7kfzbK;T9}y4TDwCPBrq`}^q{HCJCjB~e)?*#$$Q!0F(*^o{Ad?`QKwb59~( zyWP}h?l$#N+u^}I>q1xpS0MXD#mFPUF9 zUpg3_vMkY^<3(qqZ5#l(AVgrS5*j}}%7_?BssZ88?{&s#o4;)pjn3xMnEoalykCZh9$*6`> z+^34+n(jDDJQ(8+xcW|1}(aKi~dUE^H}qk32Yhm}|gupmUZMmTQ7MQBMuG%SJ^ zgmlZv1e7pX>_4?K0Vec&Zx`Udt*F<@vB8Aa8u@8&1~75ejlWS2!=Op9eo;=a*J1pR z4{7C?ZzMhz4A4*G@KC8}+C1%;V)Fxm+ELl?Swq~8R~r|KaMo`6Oyr-kTnMnxottHm z^ETB2PN<#K(*^@Ff~f9i8-Pw+TRM8K4Gj6A=hvTW-)Q7gA_7g-Dxb+FLN|#l;Wvn+ zox+Ux!E69TuGx4e(8LW{NDQ=9M=)mN7#bU=NQxpTL;)0y=pchZt98@>1e9QE)_4-0 zT=^w9XDtnBb_fj(j{R57E&hB<%WQ@V(Fllhpmkv5kld?#^ZY}<;9s9&x1a3OO5>@L zj<7Twv1tAI+}!%;H?MpqJa_%YNT9&~jQ+FqgyquWI1fbLa)nH}2;N=X)rC=5R~IFs zCObr}Z}QhCyDXCi1HZs&G&&dX^kiLaxNA&DgxA&zd;SjZFhc7En-)qvz~xoooV{nL(DK`B~rBmnD1@LPwnLE=2h&E8zDvjJZz1 z3}waByi1x0NPwni!(NoA=mC=wE_DOy;oGtb?gK=Lr?eFdLI9=_BBnA0JWWf=bf7kN88XLGZm zg9%9;F=Fi#J{9!qd20(`>ld7JV^0gd79MV~1iHYG$$F<6t#<52YNvkdPag-q>H5{7 z-Q+mZS-^1>P2EM!; z03nRS5Js6fGX<>#LPR4(K-WB_rqW5#RnrC*u@3My0x&FdQ2PGEFwMvrnUg5yJ3m}% z1d3Jt*KZ{F_ueb2-2gNW=QqaY-{|rc0K#InD~PkJq&e}&j>-Jk>DVLjD_WRu;4}n6 zf~%ulqgQu4ze#XhP}LP!Tc>$;_s<%w#~GZy;54SaslnExPMrdqHv`!L`q#~+V9czN zrl#jy>)o@nr;Y)z3l{q`jmD!#Db!C0g2k1nx%p(jIJn>s&g{!7@aCG1tQq^WjE1-S z!~)^q9b7E$jR_vQ{NBi5J4Bf?FCZzXwdS>xF3?NT|#?b-a7 zy$4W5ze4!Y0pXVu2t6Ed$P1m&Ddb6t8-D-|lTc?E5)Z(?HC}^Cg+mhQ{9r@c za6piboF^g993*NcL%#4n-r??urT;&3F88>?Q0BA{y0ic~TH z4OGqdP%PLRfkE&SqCxe*fiFD>1Yt8#>%XKPbku5v6LKK_vy#jAxB02%^)N2n>WbD* zxyESN)MgOuL<(}1QK(!%AHq!44iG@hX{UQ z^}`+cd9B|1Z7~shH)rJ!-d*=%@C>L^R|+SXqu*>-wbIQ42xtr9$c@uJ2mlvAilJC+ zSD{0KSI!t1;43Pn*c67j?Ic~dj=z)-plplz_awrx6{GqXuXFT+$cIABAu94~Yai>h z69M2=-_*A);9v!nTl!ltz&yecv*2KrBvgxGQ>=Ij1CpqS62OfI@dZakfsw64p6Gck zPwzcKQ7!px?zR-V*}WyJJuXnYi{eEedm@9a8mK%}xVv}L$E~jFIx3t79d(e#0fy=I zkOsHRcuU@ar>0K@9IZ{uE%sWVDg6F>VOC@&vo3Uul9rZUhT!N=K8w!($y>_b=0xd- z|H^kR)1K&8UO!%56%As3_{TYEXhjalNB8}nhsxaDQ6X|$f?DOCIk#tXoCh2Z%cI0@ z_1Yv+gh;K^1l!OeQiUY<|)=nBNGrgj$ay4i$aZ-~!&!DZC&TCR|4cT%sxKpJE_5wta!G zl(1@$l=*QV9Z}JP9jdJ;MTMtp^;leiLNC|H#mNiw1@cI^$rS~0eg%o4L1ul$f|o^%J_*)5U2>?kZSXKBI}-n!$E zy7A*o?X>P_H-01uGa>cvoCk>&axyEoGAc2YJYvb+ z60Z)+jRwy`dAYGE@CGPbC6bQ3k=ddS02258CoL`I2L>$pZ@m5nSj>8~<@wIe=j!i1 z@u56Gs-C&|#tA-k%N8afKQA9tcKr71c2`$gMo=Pk1tzr8B;1}g8aYURjuwafsn%@v zt}!CUQhc4|WVLwp=tQC9NodBeQI9 z%M#2Ne1B1K$s^6h#Y*J!=D`5dq`!%r$OXq1dX4)pvX7k69B6Un?(w<~iy#KQ>wog_ z8v!Qu^8nm?verjWol+-yHe`vR*32B=`OsepsYssGn}2=prB`3&M@Q%7(Mr4Tv;8N3 z2%<+2RG%@xcXZ@D((k8QYrz#08Y+jLOD+YS8;bE6$B|6X^`d4V2pqEa3Sy;Wyd=?< z#M^;gBC$d56&d2VdqnQ=ih_IB*PDU2Xf+Sxos|J6%hTC+VNLJiV*A~$x2q#+Qs2M( zg9OT7$l35YRBz?;XU-VQmFD_{`Y zWVfGEHIiu=u*TLmIUEIr9^l)i;TSg(J$PIc3BT3hK=&@J7m>UdXntokBl82$Z1Ado27>5YFIF1g0J6_G^cxN}{V6Vh z^m;sN4&WvH-y7kIiGO5H|2ItG;{nJE9zB-TCoj|2C3roKCuVcRtL+3LIJt*q)g^01 zgL`0+?bS}wRJS$R(}&PXg5yUV;fvFL>xxi#60Fgw`xv?F0Ks?aBS}2 zEm%=24)7QOGs>02m3nRA0m=h~4cAk6z4UHxo1RaZlD+g9e@3fc3FWzSC<27B zL!a_g>E+C zU66YT_J4OY(Vsbv`3IlB49q3rpyxmGy8rhy{7&B=vd!ME@4PK+ zI@VV*(bLm?y8ApNArW&xH+p=(r`q_`vSoYslJHI{bFQms&1!H*>*V>U^Vj(62IFLx zCFR6E*`R(he}`ho;9cJIkB@@E&UyCfU}9b1rzpW3#7gQ;MT zG0C8+M!S#EDPfPU-L5$d0vX$o2_N3BAP%O)eN2oDxa>`44Lgd>#f~Yp0e|?$tUukw zyAUrk?)=%#dv_-U-d>ILhtJ-&oj=XFo}pd0cju-AoQ;EN?y!ki&qG0cvYS8((p@?g zf_kQ8b%vFWMJz^DEsfAllkLDb=+TZthrUS*(3Oe}O0R7UNbSJq->*7xqTaSD9ljVO zoS;V0JeMOEy``(}I0#ffFQ=2GGwh~SIueXQ`wn#k-D_4*{@RSp*kK@FDE@ND62NK6 zWxfcT)t$c6?{`BXNw(XQl*i{Gxy_BjFxL}P)EK2h)*OijNRts5E*2txUg zW8J{6)5gngP2eIpP4wTL(M^1Xe0-x7Yw0dbU+{Ca5d)ELhjjJI3kguJjn zfKt%tZ>QLu>=_pS_^(&LN8zQNuT};pjfE`n4`EUYq^p0-cq$L~0PXYEyY}T$i0M+kc4kT#C|#1c|ZYR2tw)?D!`OWMa!cv)Q6zZSGGxI?~a7Y_P;B07v%zi z2Ha6n!p=??d|jXRM4#_U(?87Dg8;Sl<(at%quw)L_(Y70KY45Ydr?qpjGRcSQoVG^ zU*ixY`m?ZZ81(!>bu{w2^McALS%-vELA1EN8-Xpj^SPc+jx z%}%>$oM5L}0=(F=DMV=rDPdKtn6$;y-Xk3fGe;KGi2e%?uZf!jlzU`VO!&VcRRxje zFaUrUCo`bx#eJSUGC+Y5k!5J{m@G2@txMiXPK^1fcU~tD65r_$?ZOD7*$JH^ht6O7ZN;9rcPG09FYwWWy|5yo{v#9#i{!4Wo)76ur86p?FN(m)8a(r2#_VVY&@M8ZXl88YIbC56)`J4(%ia zDW$AjFZs@BzmxSuHV{!q1%NE`@H=!ZKo=BzzR%wnlzsM{2MF#f0Y(AhN{N2BEl)s2=-< z7TEm`X8Ch9#RaUIk@-NX+`MYZ5)c4l1Wvo_(8LlL!Eg|2nqRzT4&QKo+sMM_=I1hV z7C680IY1;G2%n>!{ z+fFrNYqWG?odfuchg$u@t36=cBDs3cL9n0prYgI=vsTc1{DNBdNx5=rF7kWsvH3ome%HujZmeJdcIeADCy2!e~s*z4n4 zf<2`ysZk|)RFkLdnwz`so3CF5g;BeUik4XaN|1)@?m*_rDJgi4*u%gw>H&H~)V5A1 z8FC=fQVCPH211)QIUuq_2*nyK?W`EW91aWwGr>)SXP@0?PU8snoz2#~P0&QiDcps_ z2{eHq9}!_Aa=pag-UV?iHa;{EUF5BjP&_v%?Lj6?_amdCEgV`y1j+H)9BE1@-l=Md z+y1(evp)S+0r;0eTwii>ZZbh6eYLQ$+!G<>s2tYI`r@BFzjfm>Y50W$#cv}s!Vp4W z)43+onCQ|4K{yB*k_89X-5EH22@B(-?2ph!hC&vwAf{!bF{a9@b`DFvZR{Mt~Z5WRJJXQcm(^*x1k|-SyZ-n5sL9CaOL%YHh^yr zFGSc7TdS=|ic=NbP3iLQ#PtNgtm@RScWc$Ao-2V+|iHXuQMH%k~aW^*DO4 zeV;>3#evsPU7i*QrZ1nG3RJpWWK6(jL+}=7Bn>b@*@>llv>~Ew3=6OXbI4~8Sxz$K z)nJUk2pl6i#r_O~scf=4#<;r>;TjhQ7lws81R1?uqD zRsB0OzGvoDP&swezwg0`SD#E)G9SRMj zV9*fj>_`Q5QczNReo*%82emJHDI!la5rgqq8o!&-*omMp#&n|jhZue7AEr;wiV{)# zGYF0c6}gkL?M2&N{4VtSmm$LhFR!~;x-b|<;eAgdGv!`nqof%nt3@@rzm%Yk)davk zwquQ8&)wUkfo4$59ctr(Vyo{I#qUMJ@PBP<9rVYRJmnidYO6#lRB0nEF-DbfG6R2D zy;whARquKOPYC#%`*5zZd;7_*{}d>t%HQxX?M7Q@j84 zh&p3pMf{(sr!XSyR|WY|aGTEwcJ-OOt)T%*zh%{DR^xB`v@SjEgPrF6deR-4m!}0- zdP-P8mr`{-FXp=Qap~A4ch@dupsj9!J6V=<0oP=${^_C)#8~WW?;defU2z!fOAjgN zfTgM&R~GJg`TM}olTZbdTrQAl@ZK=FAE;d~?(r_(^Vwg;op{j0(nml&8v8R<7`w$5 zk6%XdYo^rn)gCHyNyLzkJ1LtF=er*FDg`GAJ2p!-lP-h`Y?U;T7uQ1)7_hViiP#^=+OxfZhZ7pL;dX7)YO@J`r7_T`E2K&&($#D z0p;3du0LZpFtU#cF>6K|+yI=9iQ@uPH%?u42n3GHryPO6azj0PfXAu4#6-X1u@e1H zj*LB!fazGSJ7Xm{Sb=)Gi)h_a5IIj?3}mP5>(Ef0C=wjfTNfJo^==Os{7DZGZ+dIq zb)0epnj6(JL&BF@XDSKIovX_N?>EFNGIg`d1<;NI9EbIJ#RAmB`7tbq* z+=6~x_{>s^s+S&-CgEc?ZxKnE5Ta>3Fj?!TB#VV*CrRxLe`3ibbwHb4z6SFSYa)*9 zc3raU+TEt|iuxB`Knmtxym)XH0%E`@Q<;fX9A!eYCP3f-WOLhO#g=oG1BG7|MMVy} z)vmDBD($u?2zs%GJMfNGAqZ(a%~qFMBP(csPfhidUH@_uBL(mR)17`fz>r^MlKAQL zfWqp5hSW61SDyY+9ctA@0O^F?(#?W?WE%((1L!MM2=Ag1G37CVr>=G`(#f^Pr~^F9 zs^`5I88XkPg3^)QKE52u3o)xcPX4RI#SaW@AU^*1xh)}0I{ZnWfnGHK!zaaG?uqIY zF-_>MTEOI)a~j#vzwJD=pA{V)X-0J>~B^q-oFBDl&l>pd(wJ(YS;(;_0<`HOl9KrR*Z8ZViGYUpvE&dj7Ltr1R+0wC ztHh@n-{MBtT)-N_t%Qk3Jn#@Tl(hIOD^i8YyFXrk<$SU>{bg-x-4|5Ff>l3-N;U%j zg9E_gU&DZ)a~gCo$*H&sR>guv4?ElV9+r&Xu{nOtTysXVs?~4KG2a0>w&KVEIv29Y z8K0G>6ki-wYxnr>)*P=O28~;pHt&c{$>v(6j%fVUSah%!^0^C3Alxz#EUC~ zz4T%|g+47gA;>fLilPTL#^9@@&*!J}wOOdr{)!l2#MS(y3Gv++HV;PDNdVOOy za|x>x18YnTQoO`+eJjPK4NrDZ@&J4HRL$aIM|8Hz$6o{zxZO-#81dg_wfe*VNX0mY zxx^xtC;}b?So2lWC3ww`j1(+(#t{nuS3s!0Fb|JGyk_mG<(E%Rgsz{vxxRja0KPF}Wk2s_Re^2GB*lzr&ZvD!PR-$RqA>#^pmi{#nAvj4X2@_ zwoq2_>73S=oXv&-Upt2{a9%+;WShXgB%E&zRGvKD-^kZE_!&&zZI}s=WdYMb;Y?@l~a;1( z%>g;~*Y=CnD(Us}?*43ZyjO|)>vhRuEIFhE5)Q)8Mv7!Hq_XaBQh>}lIYK)kNGGfh zV;oGFIfteZav*pDo9fLlxF($6rT~Nq0=;e!ML(dK0595^qQU5%mG$(iQQ~t0oXSfK zMDShBXaLdXy+Q(Of%=~qUNbT)H9!K2E$nzD*Z78do9#Bx+lcgi;W0tQ#a&x=g=*v_ z^9mvtv}2dsV#4>O6HNskRy!+9uTS`}YyNc*9Y6CeZCN@=&UDb5Zw80Gy<4^Wb1b;B zQD0}(q-zfDQRvJiHg0h1=LQ9Tr1@bF*923WJ`#tf0kZMC_So%vc3IXfYOOYQ$Fk7P zaQ2rk&&opOy05zk<`M~}Ca&cH(NYSEx5YHxE)&353z_qhQQRF}a^2VM)lFsx-K zdzRqiSoH9@;3?ygyN>0W%C={O1*DaF9_EQaT2ia*KDM(J48|W1Cep*4=VGP<_`JrY2b?UZKX}kjf}lte9>ozZw5fpZ${l4(oy|~ zpq%?i`{ePd!xbad5Pp!Qd&3Of0=2_*&I2J;15U~2Bn(+)sUWqei&9Ztq9lfCW-Jgw z%SB7)&y;N3L6i5_iP%7o_1fK6Wq>#Yi_*p-1~x z&j#%DJ7$Jvnvp)sadZ(|>y}a0{KVKIEq@0=n-Mq7N!go&W>(!(hI|@+<6jEEwgkDt zo8*3Y9PAZ}ZbLWd{s}>%47xU1|0QDxE3Je{ti*C+lM;PTES|&ZyD0FRh3$kV#v%vM zgQ8Sopa;(BRz6B1CeXRG@*9cJagQ1;jYCLBDbJK+?9=JEoSF8f7V5ZZ4j2!IpoJQT zLB;kR9GT9(zRynuK^snPH<>f4{ijRgH*cBTy!n$o#>4h+W1@5NiH=A#^ua!~1vH&N za|867x}Ll@B}Wm>T(+!h)y5Tx+nfeGH#+3d(Yg4`PJUo8tgb>Jmm{6Lqw{Crcm^TA z)eOYU$V{91(&8wR1b_tSU;Db{1pdb6Es|UO(@#6O{K^U*KmciF`ka{IW=`Oi)1>K> z;jWUemwti1(5#nB@DGKe554N0(2iJ9Xu}uY{b-)H&@1q04^zO!ls*Vwm{rw0fVYr^ z7BM8?HU-VoFU^h>4HQr1e!*9NrIz!kJoBeuRJ*%0VH6YqL8uoFHkjm zm>Ub#_i~xoP+eA2V_fYF+H_pB6A=G}&`Pw=qpXw@ikGmIaxqtPUB}MBCb!RK8Vy>B9xEJR)6p9p( zbrn?^dQWMTVL%EtE&YafCR7e|D}PCOW0xrH1Hwoq0H06bjD5BN*7phGOxJgC9LBO- z7A;l2u@=yI+_wAdexX;nb(v8^*!RkgpzVKp#tY6qb~`&m@sqdI~= z-D&!HFw@47TJ z(@`!jH#p-JzS0*iNs7aBAi4U|{rj1(tyth>SM(mbDk;e|lGgwtlmUZgUf&4BrZM=` z#VqMCiN<;0Ys@B>dSFU%2zcX3!9iOV7FT`uQ7lN_XS-J-E=m5bEHGd0fP#lgirz3e z)~Rd8@~_oEwBT;f&w&4lEx(X&r~C0l`rH1Gw!H11N$*?dr$R`g$S4C$a@S9^Cycm; zsR!{g>w`@jxFFF17qVteZ9G8a$ujc_M-lTltsw=*i1gN-}?g6~$2!0fyAjZcjjGORYe@B@vr zTqu8|>h$&-OPat`k5b}ACPGu7m*v9T)SKT*bEDyZ>jepF0ZjDuF5ljqcg}Wk$e<>H zSFsF|+ZbDfNbo1HgcKc9@5cNb1amPN545OOV4rOKdycE+39kYCB8K2k&nTc8*xOK@ zUUBA&U;u%DW)A%gBsD_Tr3u1jNZf9w{M2$(Xn-> zds}IL=Kjz$MOi-jOcB`R5)~B^r(TI<@+k8&hf;k>02riH)YCL4+Cwqp#S`7H2hN)X z66#0bAbx8=ck>1h>`%9@mGXL-Nsr9A-Re{v3SFy$FjWGSlRo}pEfL36xD-W zxA4e03L5SGwFrEE#nlk;xsMmHy;c7%)x!9Tr)&eW!k1ckFZ6R==o44%?qesn&pVO; zwauTmKEJ)Cnb%B^X`D7EO*i1k|2{}Adsr<$9{jBdH8vND8s4k!+ByEYsgkvL)jT10 z!U-$ zwz(A(0j7}76A`;>_?DJazpFkWEr!63txH6CQr|^wW3;!}exl=I_h8K+xhtNRk`v<- zHf_44rzWXL-w;m|bk2a4S8K6{Mcf3RVwp?qB(n$SrtpTWVO0 zEOPZpvBG^jNhuh&zk1^QLK}`fUS0qUa*zvU!^6kJqf}AKaiwxRF~1mm0OEf za9H95h9}%9AsRSNW+U9^`!0Jd-&j*vXbH$D%&12JN?}%9Zf=!lCg{l&8%Jc{=8ume zT7|hKOMnH5%g(y>3);EJQ8j>hK6}jV|9iI3IxbdqKC|%Gs$b_k(>Xq9wH7}6KXmIq z*pSRfo8#X$glw?X;GlNIn4h8_!v~mRw?*&0+_Gj`@6K3Kot#@Dvr-5a{GtN)etk<@ z=N9?AkK!zbU&aXrN8csTtqQD1Up!|muG0SFmai+A+v>K-QRlIPD{W4jur>kEeg~cx z01E8C@U^5W(@qYVhbm5$Xu<_2D(%gkvY(;SfRTU`d*6g_+TIR0MsWGnyQRD-V)mQ6 zA&lHJhTQ#THlj%$soAS0H+g^rb@~7K-aFB`MkxADFaQ4rpHT2A*IiH=85E>i&8sd& zW7$qSaC(1iNsEyTQzEc=klgVAFiK))QqCZFg za6^)ej*M9-oS?`PM{GBD5*M73JTXF%4a1{AA{7JTWJfxNFcr?*EijKb%zRMP-+%sg zef`i7(55bCv@jel=^vDgC-@0-C?KP-+^R3P4K<7xLR5O>(xzoK0+3RQ1bw6vA)+kL zV32FK*w2jnksxL5CbQaCIMNxMmziGK2Dt^OUmk8RYjG+Fw z`H*8o10qG>-G37b0<&ziKw@ zrH&3gt3sifs_gFf{is`?t1NDpF6sF@z&i*-AZLvUjf^VcR038k>$F4*K1EgN{c}cj z>mdTKGFV)3GWFx{E@Aybg<|3Q52iViagr_%4d=6qbO=6UxQp(4Mz#OBMQ*{;9Gu3b zt4=?h!T~jRRL#J zQI@_=T>P1DG$)hZ7TnB1G{q3Fmmv%>N_3xajSOXe=OyAuQxSqD4i?T9yFilHkb)j3 zgNTT}bnA&#TN=R}1(m!~HD7^YWQ>ii3Ut1N?t(QnE=6Xv7iCr%-uuj~YWhAxu=2yp zW9vX;3Zb6J-jlX*C4(59;)9fEuc3Tex{6v{X%>Yt(%pHVu*m}C5)(G)4&+S?1fG|p zJmjiUf9>Cp!ou77nk?Z#eAQ+kd?&Ck5fc$`-I<7@&QcKcf3Fgd+jal6q z6Wf|u?*6k#{3;iBhz_PT{@U7FZLVHZ^J`Mwb8fIq2FsocscdUoGv^@6Mb5YWvcE?I zlGW(ZzE)noXZje5Db7o@qBZ)+5_z#kBTPw_)*$N@Z=JFl9n!6hb>5UJ`&#!s5}NnO z6%S`)*XmHLRM#2S+kxX9ySYYO*(dyS#}giV5HM z(!3>PKmeGLIb$Abbd-fsi3Ef=F)>p_#0vh}m~A{c#;)<_fmpXqssC`1+h2;Wqu$8(*a?E(?p&Ch}y7y00Yizlwd(ytrbqa&#^^Im~W z1;k*}p|Yd>$DIa2`o(FKxCydZ&QYkd&_NbdEDj_|wS#^pD%xy}7eq{z3v?(uQH5*; z_$JQ_$Z~;LVQ(mYl~%nMRtrLTYDx@CqwWCw>!hcaaELQde0;#+IZknM+8AV@l3&Jn zF6J7@QW_D1RIlk^p&Sm5fV2W?5k%AgEQcLnO_5L>!NUMAN{~T>>&Ys3>6wB~pF3!~ z{76|;H>E*Y)X~tM0uzwTl9@_44AElm8IU0%x!I3&$r-vw*}AFJ(IcA|B?}QTN9qB_ zmUxQ`ul+g8`=fc{WA1qYx$(hp8{7WIRs8Gm)7AL_#L8A!@8yAe4~~wREccvvH`Wb6 znwg}k{_g@TJ48wlkV7n4Vl6~RC?q^Yx?LOSf6G1Mp6>1(GO!on!z}FiZ_|n3j zo^JNjR>7b|?f0BA8)`gv`u{5lF4o3s+ID&KW zRFM=P2f=5xjI<8T5YXIX3DT-~m6o!y6l@MOQ#@r>C9^aHtRaP`2U=7!j>ZXr>k+*o zo6dqY=^{ghMWW%5xP8)qJ6jtEgC#Geuy=Qf>8^Lef}TH?ujj3~p*F-)z1=kH;Gr>z z)k`)lYSRuaEaz3FtwBeS5NW0|cYr_xir$Ddyl+Pmt5M2a6F)+KK45-z=t4-t8p0;PIOvu*bdYo|~gfe%B*c3!Ym4 zcy>rmPLuffO93QLDi8T_5gs4yEcNXlqYFHKE?fM3c5&01UvoWxz+rLT;m#TB^o&)k z*>*q$dAdRXlaqe$eHs(23IFhl-#8=??|v3tzs9hSF8g(I2BVAAEG5IHtvS^tjtU9yeACQEXFx{;IoIaRz=I)ty(w@#k5%ELRJ4@omPi0MOv2B7!44niXYMZ2{TPZ$cO;uDjtQXQ!Zp-69t-iV@A z$)kxdQMf6xa8^@9w2Y#mRw#>FMIr57!VHbS0v&huWHO|d4uYHZu5wo^J&`SI#c`K( zomn$Y5r;dl2&Q+Z)_(u+XJxXZ=^r;Y2&+ykw$kwsLkwF$@sDqFMWC-%UjZ)Z`qzGk z*jn4G@R8sS0~47rV!=KQHA|Xd2_2zTLPC%s!}I{RZzwgJfgFU=hnLqe`0wYePpBrq zY_uqUvLQiMlDi-<^U)V*BcYea`xA-mQmxsL;xU;??wAZXGf@q&YVD+D$LwVQF4 z9V6VJ(;^^_f=J5}V7W%CYpSn4@UmrCoQ1b(lQ5{X5CWN`2%f*3R_$c-zt^I;zZ^R$ zvS#1>+HITi&kqFx_3q!&e&87Ofg^zF!{dWBAc!pd-c8XDS3C-1{8baG!mR(jl2N6^ z&ik(H7k7=OBihYA3*>-Q>aOeRXJFP?T$2N&qXn_g^XsN%GJkP$jxBK!2=< zFjEws{d6T>LsxuWaGTstkJ4CryY%zAx=8+t;swE;z5%v%D^1BPv(z~|E4)uYCpSeS z>h>yT7ztw(r^nW#jveE{=u%nX*usLQpCu_pCO@|b4**IFc0a$8`hea>QPudkz=iUr z&|h&Am-C%UvAe1Ht~XeNUwvgtZ~_ou0~hYGX;UIay)5~_V|o0pu`z4nUB zmbJF7U{3xLLHj`wZV*(-epwpg35QJo60Z^sipm>2b1B6GiGSyrgSdebi)Ua!LM13F zBl)l?Lp)pp5kSjQ#?p0X1{8XgB(++vnZ82qD?sTqZP}ce6A9_NZ-H{LpuX(#n0Ic* z_+!UzK3`CnGN8o?5wQ2r)D`^`TUBoeP%eyh?->ioQDwi}0`6t*n11Qm`jrZ)9JOC| z9rV#uMO+H$29)uT;AA#Kv&gIy?F4}+NP#;Lp&FKk5V0UM!tvd~&vMP#9#ZemPQ(J% z>N}uw_?`ZZ)fmFmQV&G3x>^`%6tb-gDFG+%69PG8|~S#9Rbw#W3-Q z^1AZ(zfTf^3`dsR-_KW!zgzwmnH%gI8E^h2d)AXc$ch61n91SpQFeSPy=Ldf5uW|d zmN39}z9~54cXyZHhN9KSU;aiOwDVxkm%y8OKDAaEZpfbde+w2kG8XkPS60Jjl*yw4 zn@ra&5V)n@h7JV8Gxteg)Wgt$he(%>7SXp(A7c{Ilv~@QM~U=P5i9^=p2|REdXlerE$5SF|@VvKTd{GzAUP{>U^Xvd>)r9J|2!1?bw8xxWdhyNbO$$Dcdt_t9zyOo5WJzL#uLC=?H1%jJ5d6yC zr;Q=`KfkGf=y+w1bZ;43wpZFyc^pB-TR&&_NRMIIF=_7BWHRt~F~ktqeN31f0o$N* zn=n@_&K0VqL)aFPEPTZrSfnHVvIm}gpfnC%e%OFDTpk2ZH6NyM4uD@vc!A%VHQ=CM z*Tg>Gd|+UJKmXoELFS+F+H7fWyI0b0NFype@hSW?e>$u_^D%>8eYvpUCBE>|{9an% z94Sw91~<5Aupy?fK%@V0#q#H}IVU{rX|1eU0m0fvW^GX5$Y@yD=t!6WVDMdY^PJD? zirBvl6sMYt->TfAGnB25V>q3G+zB4t-~Zsc;ui4hO8fS|K&1-C4(-zrLUR7vTxCo> z<4Tbe_65QT6ueR zC|(ZV=dtT_R{~=Zfig&DhuEQQOk`eE8w=Xo1q;H$76|xrpNK@CoUS8I&W`&$?K6+0PlpsgGuOrWG1KEjKJW!x`#)vNz#*=j)09X&Sb8|2d`Y`&(~s- zYe$`|3Doi$Kos@$?bU3${dJT+OX)m^e;1nkRxJLuFS$yvMF5|D)RSFu8=UoF`K{vO zMW_sD-cE7tGwPfpLkh*v>l3>FcZMv3ciy(wgHdPQyk+vwqmjZjIvTAETAf5@#O0=> zR2{CC*XC7HpBDNk22dpQ(i+LN&@~s*JkjCh%I*av;zC0LFjYy;b1fZ;cWE%C;XsWH z{&EgGAgk?8c3k>xw;U_@@ZK{EQPYbD3-JSmI2d_ld;8piXHB2(U%r&yRF368b^ORP z@duubU$>nU0mE19&#eOutH{w0A9-V23g#`8e;19yACA5o9jsnuB@1J7Q_{$T$-)vt z@}6&3FO2PKdDRovZ_>5}rnTCG5@57TFD0OF-nHOn5YT5FhrPcAhkCHyl;jyDNSmYw z<@2v%u4cI*_KOiFPsqZB5sD)ai#A@VUCge`+ASIciBnCRzuw<6f7A0RgvZ>C9Vzhz z!sH+J3rkW(`5(6+RZUoFw=X(?!SR=W4*&Q@(PR`<{&%^m4*8=W4_~ZkMvwfOQmwA^!qNijh?#^+-qRNTiucww?^A9Kr!7_9hbszi3_x(EYEW z@nr1v^wVE?NJ%xx#Y4FNmLDcXfjXr5d3TqDjd(|=AIN?aFw-|tn0x7i z>ji}cpbZdNyxV819aB=rU25PS4|v9_(V|Y?twwD)-41 zR&D^(317VZV|=5!FMAfUaN|<}txB>(S4gGp0fdkFSzEV$Tx4r|`fg>d2!+`E28xFP z-h%N>%W3B=Eozka^Uj4I(H||`b74`zRKh3wEr3-@6B7H9xi)=Uv^ zAS+nVrh~yAx3E;FN&bn54JoB4X8NAOFshOU4OJ1}H>s!xH_6$=lD~H+3_$; z->91rdmj`4Fo6)lNOFRku)t~aG)-^i04Z>P&smtge8o?!d`Gsy;O~eMF7AQgmN>X@elWq`e^-h~uE|pLOGwE2>v^ z5I>#H?{g1-+u1+u>gVNl&m0jc*u$r^%$3Eprw+3U(Gh@_!o-Yi0<#tvlDM3 z5W3bvh@y#xE|Ek+tDVuhNtKoY$ixkL2s)-KV7dUpn3i@OW*HeCcoGR&;_-nDSlsdi zk`a(y^EC>2>8j!Now}e2MvvvE~)w@ zcijv}@&{PzxYxvkT1F*o>802z5!Ckp+Fi+R4jfqyKb zMQ>Clwj*w*h;26&dtxOw%8jg|tmBSow*}UP{%@k{Gan|_dAi9U-?K+w`M-y#-M{9) zs<4BpfBhxVCtMq{syGqgeuyWkt82IhOG-Q(ca_xliqQWNc)}drg3ouR9LX<-qbZ}e zMq@2?x{}<4@b-xRVtTRSKfoS-oJgjMqt7lE-cf zVCLk05&Am+H7MV6t(x`Xm;kN=YL2q;=Bkk3%V~Q=so!lp>K7_PWpQ7z5<+46G7keV zU6=ao848T5QbhV6S|3s^E1Z8Wm|=7&uLJ$qyXivTh}JJx4=vk!{826o+MK_aTtgO! z;NG3wc|UH~)yJ5dKio&mn>lZUo&die7Wx=GeAup`0|OG41|6wsJa0Dku?FN7&$q1Y zpPamX4Fq9T2@oebKy{ObkuRoc1gG(K-8KH&bJh?eFfYSE&P7pBZL15BMfBi8KD(7TWDD_AbWU{R8CCuz-e^5iE^ ztHYx_SFQ{ze(I^pym0k9U%x9bQBw8st7Bu=URA4K9mCG&jz`#V7mh}0z#rQ9UsF*g zD2&a}`<9JD6sUbGWxx8u6>*_P)g%@^T{}8j`?OHpq|%5BuUt^?PpSF&Ga=}pkz51n zTEFqjTKFZlhi}FT*Zrr?43IT>+o7VXs?*T9NT@v&wntRh^`N`~Bkefej=)V_QO^{l z8+8{0{V@7~BoRxISIzvG69kU!>f)MIo*yzBFk_h1F=G6 znHZ(ky9OV>Pp_4|_lXB=L}v(Sf!9?UkPbvF%{X=|uwhEfJCGe%rcj_C&I^u^D_oQ&ir1vS^kalXP z8%vn`Rhd%2AMPANLl}TH3=b&1dXk?t82I!qon>NvOD(8V2enxz6zurU54nD1UX0uQ`z z4c6GkQvA``6};!-@UJ98s&=@a_8}!0kzp^4?^eDC%6mv0DCEncI_J5h zpiax+?|kP0;6?;rM~&S#MEvT9!fc;${#a{&{&FPz?(A2$S6gQgbu0>tdA$GKGiWOh zMfP330y+7J%f;Qz*_Rge81J~}RrDwI?#vpn+X$Y&N=~shc%2LcXneu`u1}K_Ye(N~ z5MBEh6Ef#5!&{!%1Rghg!aM&UdYvC!`EWOL}`?VqUv&Hd!7pgHph`ySZ+1qgWb zu@)G6)U;-EdHo8!^$N`0r#8^MTj8-G8-UM#SNsdyRRO0n$eqVv|Kj|NiYuP9Pgo)L zW5-JJ>&u?bhz)$N_@=$K+-n+C_g4oCBSfm4-5K8L$Zy=;QSz3*k9=?uvxh5`Prl+b z`9$+1pYpwlcQAJdII&KdmoB!-VxwrvR%Kyhty3vQT}L!vm|rp@rU@EsT0DVs|E@6T z)QvmuM7{CMxR4+CP+B?k+V1&n3Hqb>j2U}WpHMUZr8nGU(34G0Nk9I~8&SvaPMr#R zutc4DeAr4h8bLZ%QGRKTqoT15+v7cp)wU?4fy_5nm-1veuyRWWu~|e{JpE1UB-=os#chdPr;vEQ2ZsE-FmJ0d zNL3eFvf2#$x0~6(=7|wIyYzcve)~S-6BTTWZgjwrqd)=owjXJ5^gcsv2h?kP&MV@R zJ!+6bP&V7M?{eFevtabK%1OmyBg7^v#E5tAa7+t{M6 zF)*-vvd8$;Cr_B`Jj;R?u95gmP|Db6rT`C9GSSvt%^XY-^F{Rt+Un0^2I0%JvQrSP zd@=hxPq7~vZg<}&3l!@8H{B6fG5c*2h3p)KBC#ECdUbA5{qFf=eKOFm$bn zg}L%3>9X;|PAl<>tA9gCBSN=YXkt)*1o0?DIoHkO{;J=_Duie>;EXw#cPL7(rJGhQ z4Xb~O%dP%@l<-0@V;87|gIHasAHXUIU}tHv^?DuYuk@rPw1^OMfr+Uu1CTK705_%c zrSoMD8Y?aVyc|WArElCUdC)KJ{jfNu8vXMDsSwG3n}+0k0qlTIkGmN{iCsgPy6F*f ziZA0pt4h?O%Z1ZL)m2_9k~83cs61f0}xs{=z7y-??Anc;DF z5~=G<1kp%bvD~q?*F!GW!ueWoAO_-T&yN{helW23P`T`3M^{QfLZ;7tAl{YapjvGRwe1>y6 z6fiUM^aatn@FD7<#Ma){IsgucsDueDE?vW`vjPUg!^86c%Q)Zqx@AvXf2M-djHb_SrPMGXr6UNTq%lLZY>jycSO#c31Lys!jjN3v zMSA~%6~Bz_2vglkVme&L{Z1mp=s`0&qP%@N-cz6llqaJfRBE8Vv0w!-UmmA^`SKol zMCiqa<9pNgXakKK951_k#xR_#u`%4)8kaGgoX%l;ESFbI6LRq8{x(2C%x7FI7UVQ8lVEYUfWVmaUZE&j1R5S2&F7`0u;2^z9gwz;LKq z3I|7muO^YMQT_k0;g5r-g|zey4!)Qcxg74g1#NdcYETYHYXQq3 zAdrbW9wVFzj6fh3JUnZ&kr_~UYzc#|#D-SE9bF8(xWpQ)vCeyk6Q7&@PRs@V>t1-E~${9p>(zN+D| z@Bd+0*UfS1Gso7X?!}k){$1lYb zlq@3TsC=tEF(o=rHUN|xrB^ABcGV9H1J_n37Tq}Yo-{qJ_IT##nwB6E7{@$nr*Ml} zZiz6@-LOT-4$bPYc2y5vOrMqkVgd-g9g+`Q1Nc3cNmI?osESSnWHiSS)JTTN#wkC= z`-=nHl0mOVR;=zD4fsCgqw=8NuZ8AE?!ti+E2FXqIT;zP?cHc(Sl)+JH53~F^X3jf zaTtqn6bg=GIci7A?+S3ZTe-57Ijra3R@T%6!fNsjC6N!_rc!Z$)5PWj=%ziKqK5%x zlKf^*rwiwo#CREC(YXTic^7sAHMwitM|pTpBhu^RZ?wJ?@TTGyY_GPHo4qEb&Cg6t zcx^rj5HK^SPjcE`0=56xTm(moxs9y40FPTS;ZN_!Gu6)XVDjXjt7MdKp7)dQKIo(9 zOp2n~6*fr5=0+FF&X0u^7}@)h+47uBqsWq|5AQYaZn^2%q^dkjED^WCm)@S6>cs7aXqdd zoiR|u;qOOx5xObyIH6h{e91qe{QHQA2hWu0XU>-9zaC^Ue_sxq!{=%Uni{uQWB>{b zQ8w7q(|wg>5z9eUL2U!rygeB0X{`C4Gr4D2zxU|qFhx;>(-8^)^Z1r#0yjk{`g`s= zyb;U;J_hf#{=GlG#g@^aWl_$s25MMnqis+tV4T^T7*H^yl$b(H_ds9=)HKpjQ9m9) zi&^k`R3Br(FiVVq=XQ+fWLQ(&dq?VV3*qpL=h+jS&-Uq!vL}vOLI2$|mYBHj9Nm=z zgqmRDNQr-RwEP|F2%*+-bVwB)6D}ljw(7t1-2clVDRHUS=h_0 zg3-L`KP_M!1$NyH>=LBoiT-b7W!6vDgUa)aO+i#caqde5OS6Q{l@-w_m>q0La`8is zp?|L`j^!ZY2kgJ!?8s0lQW@7CG^3JT6j@J?1F zWB~%6PCLc^xzPv7o^Zn3!2f@jp?^0%b!EKCCZi~f5>t*&M)k3Hu*gYObm02+Teq;m zZ#f({JnF7U32t}FHJmu3Cu_owLp) zXw18q*lb8Qs~)fh0X6}1<0^2KiYRf@VkEMj3q)j&|?|krstRSzghP%IK_@^ZE8FL@lQp^OPs4|;XX`42s zc}J3-98e#;HFz_YCpCAt^&Qj)-^*){!m0P$f3;w86Bq*v5bu5(h!}9uw4ugCdbv*V@UEMfv`gDJz zX|h0YG;_(8#ML!zJ@dafU#@5|KXx`3u48q?C` z^Wzj!nHg2irxA2gQUv{Jj*2l0Cs&MO&?GV;lJ)Nq>2K|O)91RS;sZP+Oox~RNLx(2 zsgAPvL%ezWMWQ~DXaKNf(cIizo{e+S*x<6fq_I&l@J972X7k^lnPTWMK-}nk3-czGbH?zrWrGX^741bgGsmEnvS(!28 z`58qFan!=}Q>sk)S|xd4XtdU+5UfXLIV7oL?`{tVtT!)x^CbPansFm>kc%k2r4?@@ z@xmOGMO~X9qHsh`J8Q<1E`&3(I;tO^-|?CR;1kKwRPzTpE#3K&J5c6Q3iKX0Z3%xW zz&a+?Q7C}k&~p4@V^1){=>FdR4tqDqeBd?Qs|MA}tEnUiAIB-XbCH#lTjZ6HGd13_ zHvIRn(fu-V-0o!iM~^x@#jX;QJTN~#KpB&k+5jO9tU9R#Wnmg|h$cXETfy+AVKi*X zTE_U+`l059-waEbck6qH;c)M=TP-s$-}2-ZMNuR#bjv=U7^CbNtW^?-2>L{xY8zGouDQ(+sIBPCgw!D zkQAwXE$xyM7)|_98g)v^DNjwu{|9mTy%4Sy5e%Pn38nRi6nwa;B zzH3_LEjSSLV+v5+@811dKL$8Q%7qJCi_%R7^-PTofPaiH+`RE$>xC^AhHR(6a}#3% z;vJ(T$x&DQB#FXrgpYnm@=$dx7*mPeA9s!tI2M0_=LVHKHg&uy6uw^RcVY1YkQ#?I zOY*r9!PBE#i&Fm|6Y7IShJTZaK+j|}hsamw6#&2DA^O>gVr~j(v zN&>w7?cx+5fe$|au>7t3Uz*Ge2?;Z_n*`%j0`kcs{IF)Whw8sR8~d*^;UJ75P;C{l z#QX1-o}JA4n1D{0C%ZL!X@oH3N?~gw3$JFj)3bl8VW_uZGos~5bW7V&7+^$g_wxie z^))j$1SFMY#>h;bsb~H9x(>Dy1~)LWAi;eAfT#|M)r@?TFh_zj0rW03!Q$qEGZImm zL6sA94C%#948}kAzHO6P83iYo%K)h)`4H40H#ZW^b?WK^udXHl@!UpFrH%$z8u%6O zw233By0TOT5hZq-KgJpo8prx7+z7q1mX8^W#gNqNO3xb5>plRW92i63YOG|>S$1cM z#Uh%yF$^3JhIR%ROw^|c7MskymCkTsMMq;Z2RSLhJz$by(ONgkf4~1Y>@cDM2Pm1J zY;6uI+?Ilrn5VlU%`7{Y1-lKDPXeDJHT*M59D5&tSr$HxwE)TCnWe`FXm26`F-66J z&0B``{aTfcGm3XE-}LUsXV zP+;5IPL9I7jhMD{+qxi9YeWNXQ4r44hX=(N!2`H(*4G>>p;qY4o+(NWC4KWXBewi*7 zYnQPhkT(F@7$1=h7Q6PSmzeAZDhmT6>*41{X7IJmRWit#0>i?aJ7ND{#G7G5x=;<$ z1&oMFp>ZHsI6`;@HF!#&5<3$2xPfQa|7~QqTNDk-F6R>pB}O`ahStTj(=m0I|5i$R z9jlic4e`Y&qK^AI3p^J}7IVzwcf{I8K)xUsch!gynfV^DnF8@sLoJUf&ZE^iu z+-RA7eZ54u37^9LR0$5@;YO?;!BRP*%0{ThW=(rHPKSC;0)RHGQO$>QA?-uqtBr8) zmqMvDk$FK0WvHK;7NUrlRG|n{EUE?)joX69YvI=rs~{f4YAuTQ$vl%Lh_7ba$=bL*56mJm8{{Zl05cM^pgu^M! z<_^lC0iY3ht_Lw{c0C!&TGx}SvQs)-zaGNimY*&t-XHR<)Mc&JIxVqOH)n?P%c+tMwY&o{E%d(OnSVxfZm#M4OdX0FZS{ z^eosG=Bo{vTn0oRFORWp|WW}Mrn R|B)%4k>Kv + + + + + + + + Platform default waw project + + + + + + + + + + + + + + + + + + + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..e5b6083 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,13 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic() + .bootstrapModule(AppModule) + // eslint-disable-next-line no-console + .catch((err) => console.error(err)); diff --git a/src/polyfills.ts b/src/polyfills.ts new file mode 100644 index 0000000..095851e --- /dev/null +++ b/src/polyfills.ts @@ -0,0 +1,55 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js'; // Included with Angular CLI. + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +(window as any).global = window; + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/src/scss/Classes.md b/src/scss/Classes.md new file mode 100644 index 0000000..1e90d5c --- /dev/null +++ b/src/scss/Classes.md @@ -0,0 +1,69 @@ +# • HOW TO USE OUR CLASSES IN HTML • + +## STRUCTURE +### Components + included file readme in components folder + +### GRID + row // row + col-1 // column width 100% + col-2 // column width 50% + col-3 // column width 33.3% + col-4 // column width 25% + col-5 // column width 20% + col-23 // column width 66.6% + col-2m // column min-width 50% + col-25 // column width 40% + +### CARD + w-card // card body + w-card _pd // card with padding + w-card__header // header card inside w-card + +### Atom (should turn on in file app.scss) + 1. Display + d-b //display-block: + d-ib //display-inline-block + d-f // display-flex + fd-c // flex-direction-column + jc-sb // justify-content-space-between + jc-fs // justify-content-flex-start + jc-c // justify-content-center + jc-fe // justify-content-flex-end + ai-c // align-items-center + ai-fe // align-items-flex-end + ai-fs // align-items-flex-start + ai-sb // align-items-space-between + fg-1 // flex-grow-1 + + 2. Margin (should set numbers in margin.scss) + m$ // margin $ px + mx$ // margin left and right $px + my$ // margin top and bottom $px + example: m10 // margin: 10px; + + 3. Padding (should set numbers in padding.scss) + p$ // padding $ px + px$ // padding left and right $px + py$ // padding top and bottom $px + example: p10 // padding: 10px; + 4. Other + pos-rel // position relative + + 5. Size + w100p // width 100% + h100p // height 100%\ + + 6. Text + ta-l // text-align-left + ta-c // text-align-center + ta-r // text-align-right + ws-nw // white-space-no-wrap + ws-pl // white-space-pre-line + ws-n // white-space-normal + fw400 // font-weight-400 + fw500 // font-weigh-500 + fw700 // font-weight-700 + tt-u // text-transform-uppercase +### Icons + edit // We can use material icons in these formats diff --git a/src/scss/Readme.md b/src/scss/Readme.md new file mode 100644 index 0000000..072d411 --- /dev/null +++ b/src/scss/Readme.md @@ -0,0 +1,61 @@ +# • SCSS FOLDER PACK BY WAW • + +## I. GET STARTED +- Import app.scss to your global styles -> ```@import: "scss/waw";``` + +## II. STRUCTURE +### Atom + 1. display + 2. margin + 3. other + 4. padding + 5. size + 6. text +### Components + 1. w-btn + 2. w-checkbox + 3. w-card + 4. w-forms + 5. w-radio + 6. w-switch + 7. w-table +### Layout + 1. base + 2. grid + 3. scroll +### Utils + 1. fonts + 2. icons + 3. media + 4. mixins + 5. vars + 6. angular +### Vendors + 1. normalize +## III. SETTINGS +- Go to ```waw.scss``` and turn on/off imports scss files +## IV. INFO +1. atom - include atomic classes. +2. common - include styles which appears on few pages. +3. components - include independent blocks +4. layout - include global layout settings +5. pages - include style for specifically page +6. utils - include utilities styles +7. vendors - include imports resets, normalize, libs + +## V. HOW TO USE COMPONENTS +- Go to ```scss/components/README.md``` - ready made html for components + +## VI. HOW TO USE CLASESS +- Go to ```scss/Classes.md``` - ready made htnl classes + +## VII. HTML/SCSS RULES +### We use BEM technology but changed a little for themselves (optional) +#### a. HTML + 1. block -> "header" + 2. element -> "header__link" + 3. modifier -> "_active" +#### b. SCSS + 1. block -> "header {}" + 2. element -> "&__link {}" + 3. modifier -> "&._active {}" diff --git a/src/scss/atom/display.scss b/src/scss/atom/display.scss new file mode 100644 index 0000000..7a00984 --- /dev/null +++ b/src/scss/atom/display.scss @@ -0,0 +1,41 @@ +// ===== BLOCKS ===== +.d-b { + display: block !important; +} +.d-ib { + display: inline-block !important; +} +// ===== FLEXBOX ===== +.d-f { + display: flex !important; +} +.fd-c { + flex-direction: column !important; +} +.jc-sb { + justify-content: space-between !important; +} +.jc-fs { + justify-content: flex-start !important; +} +.jc-c { + justify-content: center !important; +} +.jc-fe { + justify-content: flex-end !important; +} +.ai-c { + align-items: center !important; +} +.ai-fe { + align-items: flex-end !important; +} +.ai-fs { + align-items: flex-start !important; +} +.ai-sb { + align-items: space-between !important; +} +.fg-1 { + flex-grow: 1 !important; +} \ No newline at end of file diff --git a/src/scss/atom/margin.scss b/src/scss/atom/margin.scss new file mode 100644 index 0000000..55eb83a --- /dev/null +++ b/src/scss/atom/margin.scss @@ -0,0 +1,52 @@ + +// ===== ADD NEEDED SIZED SEPARETED BY SPACE: $margin-px: 0 10 20 30; ===== +$margin-px: 0; +$margin-x-px: 0; +$margin-y-px: 0; +$margin-top-px: 0 10; +$margin-bottom-px: 0 15; +$margin-left-px: 0; +$margin-right-px: 0; + +// ===== GENERATORS ===== +@mixin margin { + @each $i in $margin-px { + .m#{$i} { + margin: #{$i}px !important; + } + } + @each $i in $margin-x-px { + .mx#{$i} { + margin-left: #{$i}px !important; + margin-right: #{$i}px !important; + } + } + @each $i in $margin-y-px { + .my#{$i} { + margin-top: #{$i}px !important; + margin-bottom: #{$i}px !important; + } + } + @each $i in $margin-top-px { + .mt#{$i} { + margin-top: #{$i}px !important; + } + } + @each $i in $margin-bottom-px { + .mb#{$i} { + margin-bottom: #{$i}px !important; + } + } + @each $i in $margin-left-px { + .ml#{$i} { + margin-left: #{$i}px !important; + } + } + @each $i in $margin-right-px { + .mr#{$i} { + margin-right: #{$i}px !important; + } + } +} + +@include margin; diff --git a/src/scss/atom/other.scss b/src/scss/atom/other.scss new file mode 100644 index 0000000..13752c9 --- /dev/null +++ b/src/scss/atom/other.scss @@ -0,0 +1,4 @@ +// ===== POSITION ===== +.pos-rel { + position: relative !important; +} diff --git a/src/scss/atom/padding.scss b/src/scss/atom/padding.scss new file mode 100644 index 0000000..1bc6ca9 --- /dev/null +++ b/src/scss/atom/padding.scss @@ -0,0 +1,51 @@ +// ===== ADD NEEDED SIZED SEPARETED BY SPACE: $padding-px: 0 10 20 30; ===== +$padding-px: 0; +$padding-x-px: 0; +$padding-y-px: 0; +$padding-top-px: 0; +$padding-bottom-px: 0; +$padding-left-px: 0; +$padding-right-px: 0; + +/* Generators */ +@mixin padding { + @each $i in $padding-px { + .p#{$i} { + padding: #{$i}px !important; + } + } + @each $i in $padding-x-px { + .px#{$i} { + padding-left: #{$i}px !important; + padding-right: #{$i}px !important; + } + } + @each $i in $padding-y-px { + .py#{$i} { + padding-top: #{$i}px !important; + padding-bottom: #{$i}px !important; + } + } + @each $i in $padding-top-px { + .pt#{$i} { + padding-top: #{$i}px !important; + } + } + @each $i in $padding-bottom-px { + .pb#{$i} { + padding-bottom: #{$i}px !important; + } + } + @each $i in $padding-right-px { + .pr#{$i} { + padding-right: #{$i}px !important; + } + } + @each $i in $padding-left-px { + .pl#{$i} { + padding-left: #{$i}px !important; + } + } +} + +@include padding; diff --git a/src/scss/atom/size.scss b/src/scss/atom/size.scss new file mode 100644 index 0000000..c592643 --- /dev/null +++ b/src/scss/atom/size.scss @@ -0,0 +1,9 @@ +// ===== WIDTH ===== +.w100p { + width: 100% !important; +} + +// ===== HEIGHT ===== +.h100p { + height: 100%; +} diff --git a/src/scss/atom/text.scss b/src/scss/atom/text.scss new file mode 100644 index 0000000..9597d92 --- /dev/null +++ b/src/scss/atom/text.scss @@ -0,0 +1,34 @@ +// ===== TEXT ALIGN ===== +.ta-l { + text-align: left !important; +} +.ta-c { + text-align: center !important; +} +.ta-r { + text-align: right !important; +} +// ===== WHITE SPACE ===== +.ws-nw { + white-space: nowrap !important; +} +.ws-pl { + white-space: pre-line !important; +} +.ws-n { + white-space: normal !important; +} +// ===== FONT WEIGHT ===== +.fw400 { + font-weight: 400 !important; +} +.fw500 { + font-weight: 500 !important; +} +.fw700 { + font-weight: 700 !important; +} +// ===== TEXT TRANSFORM ===== +.tt-u { + text-transform: uppercase !important; +} diff --git a/src/scss/components/Readme.md b/src/scss/components/Readme.md new file mode 100644 index 0000000..4ef4e18 --- /dev/null +++ b/src/scss/components/Readme.md @@ -0,0 +1,118 @@ + + +1. ==== button ==== +``` + + + +``` + +2. ==== input ==== +``` + +``` + +3. ==== select ==== +``` + +``` + +4. ==== textarea ==== +``` + +``` + +5. ==== switch ==== +``` +

+
Sound notification
+ +``` + +6. ==== checkbox ==== +``` + +``` + + +``` + + + + + +``` + +7. ==== radio ==== +``` + +``` + +8. ==== table ==== +``` +
+ + + + + + + + + + + + + + + + + + + + + + + +
ClientsAddressEmailPhoneadditional phoneGenderDate of birth
Ivan PetrnekoStreet of Blue Flowers 23korsun_anna@gmail.com(201) 555-0124(201) 555-0124Woman2.05.1978
+
+``` + + +9. ==== card ==== +``` +
+ +
+ +
+
+
+ +``` diff --git a/src/scss/components/_w-alert.scss b/src/scss/components/_w-alert.scss new file mode 100644 index 0000000..a6ffbb2 --- /dev/null +++ b/src/scss/components/_w-alert.scss @@ -0,0 +1,546 @@ +@keyframes iziT-bounceInUp { + 0% { + opacity: 0; + transform: translateY(200px); + } + 50% { + opacity: 1; + transform: translateY(-10px); + } + 70% { + transform: translateY(5px); + } + to { + transform: translateY(0); + } +} +@keyframes iziT-fadeIn { + 0% { + opacity: 0; + } + to { + opacity: 1; + } +} +@keyframes iziT-fadeInUp { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + to { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} +@keyframes iziT-fadeInDown { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + to { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} +@keyframes iziT-bounceInLeft { + 0% { + opacity: 0; + transform: translateX(280px); + } + 50% { + opacity: 1; + transform: translateX(-20px); + } + 70% { + transform: translateX(10px); + } + to { + transform: translateX(0); + } +} +@keyframes iziT-bounceInDown { + 0% { + opacity: 0; + transform: translateY(-200px); + } + 50% { + opacity: 1; + transform: translateY(10px); + } + 70% { + transform: translateY(-5px); + } + to { + transform: translateY(0); + } +} +.alert-wrapper { + position: fixed; + bottom: 50px; + left: 0; + width: 100%; + height: 60px; + overflow: hidden; +} + +.alert { + display: flex; + -webkit-box-align: center; + align-items: center; + width: auto; + background: #3aed92; + color: #fff; + max-width: 700px; + margin: 0 auto; + transform: translateY(300px) scale(0); + transition: .3s all ease-in-out; + + &._show { + transform: translateY(0) scale(1); + transition: .3s all ease-in-out; + } +} + +.alert-icon { + min-width: 60px; + min-height: 60px; + position: relative; + display: flex; + justify-content: center; + align-items: center; + background-color: #2bd17d; + + &:before { + content: ""; + position: absolute; + width: 25px; + height: 25px; + border-radius: 50%; + border: 2px solid #fff; + } + + &:after { + content: ""; + position: absolute; + top: 22px; + width: 7px; + height: 11px; + border: solid white; + border-width: 0 2px 2px 0; + transform: rotate(45deg); + } +} + +.alert-text { + padding: 0px 20px; + + word-break: break-all; + overflow: auto; + height: 60px; + + .text-block { + width: 99%; + + &__text { + text-overflow: ellipsis; + overflow: hidden; + white-space: pre; + } + } +} + +.alert-close { + min-width: 50px; + + margin-left: auto; + font-size: 25px; + display: flex; + justify-content: center; + align-items: center; +} + + +.font-bold { + font-weight: bold; +} + +.waw-alert__progress { + bottom: 0px; + position: absolute; + width: 100%; + margin-bottom: 0; + border-radius: 50px; + + &:hover { + span { + animation-play-state: paused; + } + + } + + + span { + display: block; + width: 100%; + height: 2px; + background-color: #a5a5a5ed; + animation-name: waw-alert-progress; + animation-duration: 10s; + border-radius: 50px; + + &._red { + background-color: rgba(255, 175, 180, 1); + } + + &._green { + background-color: rgba(166, 239, 184, 1); + } + + &._yellow { + background-color: rgba(255, 249, 178, 1); + } + + &._orange { + background-color: rgba(255, 207, 165, 1); + } + + &._blue { + background-color: rgba(255, 207, 165, 1); + } + + &._white { + background-color: white; + } + + &._black { + background-color: black; + } + } +} + +.waw-alert:hover { + .waw-alert__progress>span { + animation-play-state: paused; + } +} + +.waw-alert__close { + width: 15px; + height: 15px; + opacity: 0.3; + position: relative; + order: 2; + + &:hover { + opacity: 1; + + } + + &::before, + &::after { + cursor: pointer; + position: absolute; + left: 15px; + content: ' '; + height: 12px; + width: 2px; + background-color: #47525d; + } + + &:before { + transform: rotate(45deg); + } + + &:after { + transform: rotate(-45deg); + } +} + +@keyframes waw-alert-progress { + from { + width: 100%; + } + + to { + width: 0%; + } +} + +.waw-alert-container { + font-size: 0; + height: 100px; + width: 100%; + transform: translateZ(0); + backface-visibility: hidden; + // transition: transform 0.5s cubic-bezier(0.25, 0.8, 0.25, 1), height 0.5s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: .3s all ease-in-out; + // transform: scale(1); + opacity: 1; + + + &._close { + // transform: scale(0); + opacity: 0; + transition: .3s all ease-in-out; + + } +} + +.waw-alert { + display: inline-block; + clear: both; + position: relative; + font-family: 'Lato', Tahoma, Arial; + font-size: 14px; + padding: 8px 25px 9px 0; + background: rgba(238, 238, 238, 0.9); + border-color: rgba(238, 238, 238, 0.9); + width: 100%; + pointer-events: all; + cursor: default; + transform: translateX(0); + -webkit-touch-callout: none + /* iOS Safari */ + ; + -webkit-user-select: none + /* Chrome/Safari/Opera */ + ; + -khtml-user-select: none + /* Konqueror */ + ; + -moz-user-select: none + /* Firefox */ + ; + -ms-user-select: none + /* Internet Explorer/Edge */ + ; + user-select: none; + min-height: 54px; +} + +.waw-alert>.waw-alert-progressbar { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + z-index: 1; + background: rgba(255, 255, 255, 0.2); +} + +.waw-alert>.waw-alert-progressbar>div { + height: 2px; + width: 100%; + background: rgba(0, 0, 0, 0.3); + border-radius: 0 0 3px 3px; +} + +.waw-alert>.waw-alert-close { + position: absolute; + right: 0; + top: 0; + border: 0; + padding: 0; + opacity: 0.6; + width: 42px; + height: 100%; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAJPAAACTwBcGfW0QAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAD3SURBVFiF1ZdtDoMgDEBfdi4PwAX8vLFn0qT7wxantojKupmQmCi8R4tSACpgjC2ICCUbEBa8ingjsU1AXRBeR8aLN64FiknswN8CYefBBDQ3whuFESy7WyQMeC0ipEI0A+0FeBvHUFN8xPaUhAH/iKoWsnXHGegy4J0yxialOfaHJAz4bhRzQzgDvdGnz4GbAonZbCQMuBm1K/kcFu8Mp1N2cFFpsxsMuJqqbIGExGl4loARajU1twskJLLhIsID7+tvUoDnIjTg5T9DPH9EBrz8rxjPzciAl9+O8SxI8CzJ8CxKFfh3ynK8Dyb8wNHM/XDqejx/AtNyPO87tNybAAAAAElFTkSuQmCC") no-repeat 50% 50%; + background-size: 8px; + cursor: pointer; + outline: none; +} + +.waw-alert>.waw-alert-close:hover { + opacity: 1; +} + +.waw-alert>.waw-alert-body { + position: relative; + padding: 0 0 0 10px; + height: auto; + min-height: 36px; + margin: 0 0 0 15px; + text-align: left; + display: flex; + justify-content: space-between; + align-items: center; +} + +.waw-alert>.waw-alert-body:after { + content: ""; + display: table; + clear: both; +} + +.waw-alert>.waw-alert-body .waw-alert-texts { + margin: 10px 0 0 0; + padding-right: 2px; + display: inline-block; + float: left; + display: flex; + justify-content: space-between; + align-items: center; +} + +.waw-alert>.waw-alert-body .waw-alert-icon { + height: 100%; + position: absolute; + left: 0; + top: 50%; + display: table; + font-size: 23px; + line-height: 24px; + margin-top: -12px; + color: #000; + width: 24px; + height: 24px; +} + +.waw-alert>.waw-alert-body .waw-alert-title { + padding: 0; + margin: 0; + line-height: 16px; + font-size: 14px; + text-align: left; + float: left; + color: #000; + white-space: normal; + margin-right: 10px; + font-weight: bold; +} + +.waw-alert>.waw-alert-body .waw-alert-message { + padding: 0; + // margin: 0 0 10px 0; + font-size: 14px; + line-height: 16px; + text-align: left; + float: left; + color: rgba(0, 0, 0, 0.6); + white-space: normal; +} + +@media only screen and (min-width: 568px) { + .waw-alert-wrapper { + padding: 10px 15px; + } + + .waw-alert { + margin: 5px; + border-radius: 3px; + width: auto; + } + + .waw-alert:after { + content: ''; + z-index: -1; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: 3px; + box-shadow: inset 0 -10px 20px -10px rgba(0, 0, 0, 0.2), inset 0 0 5px rgba(0, 0, 0, 0.1), 0 8px 8px -5px rgba(0, 0, 0, 0.25); + } + + .waw-alert:not(.waw-alert-rtl) .waw-alert-cover { + border-radius: 3px 0 0 3px; + } + + .waw-alert.waw-alert-rtl .waw-alert-cover { + border-radius: 0 3px 3px 0; + } + + .waw-alert.waw-alert-color-dark:after { + box-shadow: inset 0 -10px 20px -10px rgba(255, 255, 255, 0.3), 0 10px 10px -5px rgba(0, 0, 0, 0.25); + } + + .waw-alert.waw-alert-balloon .waw-alert-progressbar { + background: transparent; + } + + .waw-alert.waw-alert-balloon:after { + box-shadow: 0 10px 10px -5px rgba(0, 0, 0, 0.25), inset 0 10px 20px -5px rgba(0, 0, 0, 0.25); + } + + .waw-alert-target .waw-alert:after { + box-shadow: inset 0 -10px 20px -10px rgba(0, 0, 0, 0.2), inset 0 0 5px rgba(0, 0, 0, 0.1); + } +} + +.waw-alert.waw-alert-theme-dark { + background: #565c70; + border-color: #565c70; +} + +.waw-alert.waw-alert-theme-dark .waw-alert-title { + color: #fff; +} + +.waw-alert.waw-alert-theme-dark .waw-alert-message { + color: rgba(255, 255, 255, 0.7); + font-weight: 300; +} + +.waw-alert.waw-alert-theme-dark .waw-alert-icon { + color: #fff; +} + +.waw-alert.waw-alert-color-red { + background: rgba(255, 175, 180, 0.9); + border-color: rgba(255, 175, 180, 0.9); +} + +.waw-alert.waw-alert-color-orange { + background: rgba(255, 207, 165, 0.9); + border-color: rgba(255, 207, 165, 0.9); +} + +.waw-alert.waw-alert-color-yellow { + background: rgba(255, 249, 178, 0.9); + border-color: rgba(255, 249, 178, 0.9); +} + +.waw-alert.waw-alert-color-blue { + background: rgba(157, 222, 255, 0.9); + border-color: rgba(157, 222, 255, 0.9); +} + +.waw-alert.waw-alert-color-green { + background: rgba(166, 239, 184, 0.9); + border-color: rgba(166, 239, 184, 0.9); +} + +.waw-alert.slideIn, +.waw-alert .slideIn { + -webkit-animation: iziT-slideIn 1s cubic-bezier(0.16, 0.81, 0.32, 1) both; + -moz-animation: iziT-slideIn 1s cubic-bezier(0.16, 0.81, 0.32, 1) both; + animation: iziT-slideIn 1s cubic-bezier(0.16, 0.81, 0.32, 1) both; +} + +.waw-alert.bounceInLeft { + -webkit-animation: iziT-bounceInLeft 0.7s ease-in-out both; + animation: iziT-bounceInLeft 0.7s ease-in-out both; +} + +.waw-alert.bounceInRight { + -webkit-animation: iziT-bounceInRight 0.85s ease-in-out both; + animation: iziT-bounceInRight 0.85s ease-in-out both; +} + +.waw-alert.bounceInDown { + -webkit-animation: iziT-bounceInDown 0.7s ease-in-out both; + animation: iziT-bounceInDown 0.7s ease-in-out both; +} + +.waw-alert.bounceInUp { + -webkit-animation: iziT-bounceInUp 0.7s ease-in-out both; + animation: iziT-bounceInUp 0.7s ease-in-out both; +} + +.height { + height: auto !important; +} diff --git a/src/scss/components/_w-btn.scss b/src/scss/components/_w-btn.scss new file mode 100644 index 0000000..057d2ab --- /dev/null +++ b/src/scss/components/_w-btn.scss @@ -0,0 +1,69 @@ +@import '/src/scss/utils/vars'; + + +.w-btn { + font-size: var(--fs); + font-weight: 500; + font-family: var(--ff-base); + background-color: var(--c-primary); + border-radius: var(--b-radius-btn); + transition: var(--transition); + color: var(--c-white); + position: relative; + padding: 11px 25px; + line-height: 19px; + text-align: center; + white-space: nowrap; + display: inline-flex; + justify-content: center; + align-items: center; + user-select: none; + text-align: center; + width: 100%; + border: none; + cursor: pointer; + transition: all .3s; + border-radius: 4px; + &._primary { + background-color: var(--c-primary); + + &:hover { + background-color: var(--c-primary-hover); + } + } + + &._second { + border: 1px solid #256eff; + background-color: var(--c-white); + color: #256eff; + } + + &._danger { + background-color: var(--c-secondary); + color: white; + + &:hover { + background: var(--c-secondary-hover); + } + } + + &._link { + background: transparent; + color: var(--c-text-primary); + font-size: 14px; + font-weight: 400; + + &:hover { + color: var(--c-text-secondary); + } + } + + &:disabled { + background-color: var(--c-grey-dark); + cursor: default; + + &:hover { + background-color: var(--c-grey-dark); + } + } +} diff --git a/src/scss/components/_w-card.scss b/src/scss/components/_w-card.scss new file mode 100644 index 0000000..e76c7bd --- /dev/null +++ b/src/scss/components/_w-card.scss @@ -0,0 +1,53 @@ +@import '/src/scss/utils/vars'; + + +@import 'angular'; + + + + +.w-card { + display: flex; + flex-direction: column; + background-color: var(--c-bg-secondary); + border-radius: var(--card-border-radius, 8px); + box-shadow: var(--card-box-shadow, 0 2px 8px rgba(0, 0, 0, 0.1)); + overflow: hidden; + margin-bottom: var(--card-margin-bottom, 20px); + + &__header { + padding: var(--card-header-padding, 16px); + border-bottom: var(--card-border-width, 1px) solid + var(--card-border-color, #eaeaea); + //background-color: var(--card-header-background, #f5f5f5); + flex-shrink: 0; + display: flex; + justify-content: space-between; + align-items: center; + } + + &__body { + padding: var(--card-body-padding, 16px); + flex-grow: 1; + display: flex; + flex-direction: column; + + &-section { + padding: var(--card-section-padding, 8px 0); + border-bottom: var(--card-border-width, 1px) solid + var(--card-border-color, #eaeaea); + + &:last-child { + border-bottom: none; + } + } + } + + &__footer { + padding: var(--card-footer-padding, 16px); + border-top: var(--card-border-width, 1px) solid + var(--card-border-color, #eaeaea); + background-color: var(--card-footer-background, #f5f5f5); + flex-shrink: 0; + } +} diff --git a/src/scss/components/_w-checkbox.scss b/src/scss/components/_w-checkbox.scss new file mode 100644 index 0000000..f63d4da --- /dev/null +++ b/src/scss/components/_w-checkbox.scss @@ -0,0 +1,83 @@ +@import '/src/scss/utils/vars'; + +@import 'angular'; + +.w-checkbox { + &__body { + display: inline-flex; + user-select: none; + color: var(--c-text-primary); + cursor: pointer; + padding: 6px 8px; + border-radius: 6px; + overflow: hidden; + transition: $transition; + &:not(:last-child) { + margin-right: 6px; + } + &:hover { + background: rgba(var(--c-primary), 0.09); + } + &:hover .w-checkbox__svg { + border-color: var(--c-primary); + } + @include bp-max(md) { + width: 100%; + margin-bottom: 4px; + display: inline-block; + } + } + &__input { + display: none; + &:checked+.w-checkbox__body .w-checkbox__svg { + background: var(--c-primary); + border-color: var(--c-primary); + animation: wave 0.4s ease; + } + &:checked+.w-checkbox__body .w-checkbox__svg svg { + stroke-dashoffset: 0; + } + } + &__svg { + position: relative; + width: 18px; + height: 18px; + display: inline-block; + border-radius: 4px; + transform: scale(1); + border: 1px solid var(--c-border); + transition: $transition; + box-shadow: 0 1px 1px var(--c-shadow); + } + &__svg svg { + position: absolute; + top: 3px; + left: 2px; + fill: none; + stroke: #fff; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; + stroke-dasharray: 16px; + stroke-dashoffset: 16px; + transition: all 0.3s ease; + transition-delay: 0.1s; + transform: translate3d(0, 0, 0); + } + &__text { + padding-left: 8px; + line-height: 18px; + } + &__svg-icon { + position: absolute; + width: 0; + height: 0; + pointer-events: none; + user-select: none; + } +} +@keyframes wave { + 50% { + transform: scale(0.9); + } +} diff --git a/src/scss/components/_w-forms.scss b/src/scss/components/_w-forms.scss new file mode 100644 index 0000000..5c543f6 --- /dev/null +++ b/src/scss/components/_w-forms.scss @@ -0,0 +1,101 @@ +@import '/src/scss/utils/vars'; + +@import 'angular'; +// forms + +.form-container{ + margin-bottom: 15px; +} + +.w-forms { + position: relative; + + display: flex; + flex-direction: column; + width: 100%; + gap: 10px; + + &__title { + display: inline-block; + color: var(--c-text-primary); + // font-size: calc(#{$fs} - 4px); + font-size: 19px; + line-height: calc(#{$fs} + 2px); + letter-spacing: $letter-spacing; + // margin-bottom: 6px; + font-weight: 500; + margin-bottom: 15px; + } + &__component{ + label{ + padding: 0 !important; + } + .w-btn{ + //margin: 0 20px; + } + } + &__input, + &__textarea, + &__select { + height: 42px; + background-color: transparent; + border: 1px solid var(--c-border); + border-radius: $b-radius; + color: var(--c-text-secondary); + font-size: calc(#{$fs} - 2px); + line-height: calc(#{$fs} + 4px); + transition: $transition; + width: 100%; + display: block; + letter-spacing: $letter-spacing; + padding: 10px; + + &::placeholder { + color: var(--c-placeholder); + transition: $transition; + } + + &:focus { + transition: $transition; + border-color: var(--c-primary); + } + + &:disabled { + background-color: $c-grey; + border-color: $c-grey; + color: $c-grey; + cursor: default; + opacity: 0.6; + } + } + + &__input { + &[type='time'] { + display: block; + -webkit-appearance: textfield; + -moz-appearance: textfield; + } + } + + &__select { + appearance: none; + padding-right: 30px; + } + + &__chevron { + position: absolute; + top: 30px; + right: 12px; + + &::before { + color: var(--c-primary); + } + } + + &__textarea { + min-height: 80px; + resize: vertical; + max-height: 250px; + margin-top: 10px; + } +} diff --git a/src/scss/components/_w-modal.scss b/src/scss/components/_w-modal.scss new file mode 100644 index 0000000..3f41ec3 --- /dev/null +++ b/src/scss/components/_w-modal.scss @@ -0,0 +1,82 @@ +@import '/src/scss/utils/vars'; + +@import 'angular'; + +#html .modal { + padding: 20px; + + &-content { + background: var(--c-bg-secondary); + border-radius: $b-radius; + border: 1px solid var(--c-border); + max-width: 700px; + padding-top: 45px; + } + .close { + top: -2px; + right: 5px; + + font-size: 50px; + } + .close:hover { + color: var(--c-text-secondary); + } +} + + +#html body._modal-small .modal-content, +#html .forms_modal .modal-content { + max-width: 500px; + width: 100%; +} + +.modal { + position: fixed; /* Stay in place */ + z-index: 9999; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow-y: auto; /* Enable scroll if needed */ + background-color: rgb(0, 0, 0); /* Fallback color */ + background-color: rgba(0, 0, 0, 0.5); /* Black w/ opacity */ +} + +/* Modal Content/Box */ +.modal-content { + position: relative; + background-color: #fff; + margin: 15% auto; /* 15% from the top and centered */ + padding: 40px 20px 20px 20px; + border: 1px solid #888; + min-width: 20%; /* Could be more or less, depending on screen size */ + max-width: 80%; /* Could be more or less, depending on screen size */ + @media screen and (max-width: 767px) { + max-width: 100% !important; + } +} + +/* The Close Button */ +.close { + color: #aaa; + position: absolute; + right: 10px; + top: 10px; + font-size: 32px; + line-height: 1; +} + +.close:hover, +.close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + +.big { + .modal-content { + margin-top: 5%!important; + margin-bottom: 0!important; + max-width: 100%!important; + } +} diff --git a/src/scss/components/_w-radio.scss b/src/scss/components/_w-radio.scss new file mode 100644 index 0000000..81ea9ad --- /dev/null +++ b/src/scss/components/_w-radio.scss @@ -0,0 +1,52 @@ +@import '/src/scss/utils/vars'; + +@import 'angular'; + +.w-radio { + position: relative; + display: flex; + align-items: center; + cursor: pointer; + line-height: 20px; + font-size: 16px; + margin: 5px 0; + &:hover &__label:after { + transform: scale(3.6); + } + &__label { + position: relative; + display: block; + float: left; + margin-right: 10px; + width: 20px; + height: 20px; + border: 2px solid var(--c-border); + border-radius: 100%; + min-width: 20px; + &:after { + content: ''; + position: absolute; + top: 3px; + left: 3px; + width: 10px; + height: 10px; + border-radius: 100%; + background: var(--c-primary); + transform: scale(0); + transition: $transition; + opacity: 0.08; + pointer-events: none; + } + } + &__input { + display: none; + &:checked+.w-radio__label { + border-color: var(--c-primary); + &:after { + transform: scale(1); + transition: all 0.2s cubic-bezier(0.35, 0.9, 0.4, 0.9); + opacity: 1; + } + } + } +} diff --git a/src/scss/components/_w-select.scss b/src/scss/components/_w-select.scss new file mode 100644 index 0000000..c7348f0 --- /dev/null +++ b/src/scss/components/_w-select.scss @@ -0,0 +1,236 @@ +:host { + display: block; +} + +// waw-select styles +.w-select { + width: 100%; + &__label { + margin-bottom: 5px; + } + &__body { + position: relative; + cursor: pointer; + display: flex; + min-height: 50px; + height: 50px; + align-items: center; + border: 2px solid var(--c-text-primary); + border-radius: 12px; + transition: var(--transition); + //background: var(--c-bg-secondary); + &._active { + border-color: var(--c-primary); + } + } + &__header { + padding-left: 15px; + display: flex; + align-items: center; + width: 100%; + overflow: hidden; + white-space: nowrap; + padding: 14px 10px 14px 40px; + position: relative; + svg { + position: absolute; + left: 10px; + top: 50%; + transform: translateY(-50%); + path{ + fill:var(--c-primary); + } + } + } + &__text { + margin-right: 10px; + flex-grow: 1; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + .text-overflow { + overflow: hidden; + text-overflow: ellipsis; + word-break: keep-all; + color: var(--c-text-primary); + } + } + &__arrow { + margin-right: 15px; + transition: var(--transition); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + svg{ + width: 12px; + height: 12px; + path{ + fill: var(--c-text-primary); + } + } + &._active { + transform: rotate(180deg); + } + } + .item { + padding: 10px; + transition: var(--transition); + border-bottom: 1px solid var(--c-text-primary); + &:hover { + background: var(--c-shadow); + border-bottom: 1px solid var(--c-primary); + color: var(--c-primary); + } + } + &__popup { + z-index: 9; + width: 100%; + left: 0; + position: absolute; + top: calc(100% + 10px); + background: var(--c-white); + box-shadow: 0px 0px 4px var(--c-border); + border-radius: 10px; + border: 2px solid var(--c-primary); + background: var(--c-bg-secondary); + color: var(--c-text-primary); + padding-bottom: 15px; + padding-top: 15px; + &._search { + padding-top: 60px; + } + .popup-block { + max-height: 180px; + overflow-y: auto; + padding: 0 15px; + margin-right: 10px; + &__empty-search { + padding: 15px; + text-align: center; + color: var(--c-text-primary); + } + } + } + &__search { + top: 10px; + position: absolute; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + left: 0; + padding: 0 15px; + .search-input { + outline: none; + width: 100%; + cursor: pointer; + display: flex; + padding: 10px; + padding-right: 30px; + align-items: center; + border: 1px solid var(--c-border); + border-radius: 10px; + transition: var(--transition); + } + .search-icon { + position: absolute; + top: 50%; + right: 25px; + transform: translateY(-50%); + } + } + // scroll styles + *::-webkit-scrollbar { + width: 5px; + height: 5px; + background-color: var(--c-white); + } + * ::-webkit-scrollbar-thumb { + border-radius: 0; + background-color: var(--c-border); + } + + // checkbox styles + .checkbox { + &__body { + display: inline-flex; + user-select: none; + cursor: pointer; + padding: 6px 8px; + color: var(--c-text); + border-radius: 6px; + overflow: hidden; + transition: var(--transition); + &:not(:last-child) { + margin-right: 6px; + } + &:hover { + background: rgba(var(--c-sky), 0.09); + } + &:hover .checkbox__svg { + border-color: var(--c-sky); + } + } + &__input { + display: none; + &:checked + .checkbox__body .checkbox__svg { + background: var(--c-sky); + border-color: var(--c-sky); + animation: wave 0.4s ease; + } + &:checked + .checkbox__body .checkbox__svg svg { + stroke-dashoffset: 0; + } + } + &__svg { + position: relative; + min-width: 18px; + min-height: 18px; + width: 18px; + height: 18px; + display: inline-block; + border-radius: 4px; + transform: scale(1); + border: 1px solid var(--c-border); + transition: var(--transition); + box-shadow: 0 1px 1px var(--c-shadow); + } + &__svg svg { + position: absolute; + top: 3px; + left: 2px; + fill: none; + stroke: var(--c-white); + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; + stroke-dasharray: 16px; + stroke-dashoffset: 16px; + transition: all 0.3s ease; + transition-delay: 0.1s; + transform: translate3d(0, 0, 0); + } + &__text { + padding-left: 8px; + line-height: 18px; + text-overflow: ellipsis; + overflow: hidden; + } + &__svg-icon { + position: absolute; + width: 0; + height: 0; + pointer-events: none; + user-select: none; + } + @keyframes wave { + 50% { + transform: scale(0.9); + } + } + } +} +.selected { + font-weight: bold; +} \ No newline at end of file diff --git a/src/scss/components/_w-switch.scss b/src/scss/components/_w-switch.scss new file mode 100644 index 0000000..dd51224 --- /dev/null +++ b/src/scss/components/_w-switch.scss @@ -0,0 +1,59 @@ +@import '/src/scss/utils/vars'; + +// SWITCH +.w-switch { + display: flex; + align-items: center; + cursor: pointer; + &__toggle { + position: relative; + width: 45px; + height: 25px; + } + &__input { + display: none; + &:checked+.w-switch__slider { + background-color: var(--c-primary); + border: 1px solid var(--c-primary); + } + &:focus+.w-switch__slider { + box-shadow: 0 0 1px var(--c-shadow); + } + &:checked+.w-switch__slider:before { + transform: translate(15px, -50%); + background-color: $c-white; + } + } + &__slider { + position: absolute; + inset: 0; + background-color: $c-grey; + border: 1px solid var(--c-border); + outline: none; + transition: $transition; + &:before { + position: absolute; + content: ""; + height: 16px; + width: 16px; + left: 6px; + top: 50%; + transform: translateY(-50%); + background-color: $c-white; + transition: $transition; + } + &._round { + border-radius: 34px; + &:before { + border-radius: 50%; + } + } + } + &__text { + margin-left: 10px; + font-size: calc(#{$fs} - 2px); + line-height: calc(#{$fs} - 2px); + letter-spacing: $letter-spacing; + color: var(--c-text); + } +} diff --git a/src/scss/components/_w-table.scss b/src/scss/components/_w-table.scss new file mode 100644 index 0000000..9566e16 --- /dev/null +++ b/src/scss/components/_w-table.scss @@ -0,0 +1,478 @@ +@import '/src/scss/utils/vars'; + +@import 'angular'; + + +.wtable { + background: var(--c-bg-secondary); + box-shadow: var(--c-shadow); + border-radius: 10px; + padding-bottom: 70px; + max-width: 100%; + height: auto; + margin: 0px auto; + position: relative; + + @media (max-width: 991px) { + padding-left: 10px; + padding-right: 10px; + } + + @media screen and (max-width: 599px) { + padding-bottom: 50px; + } + + .table { + border-collapse: collapse; + margin: 0; + padding: 0; + width: 100%; + table-layout: auto; + + &-plus-btn { + cursor: pointer; + font-size: 16px; + font-weight: 500; + border: 0; + display: flex; + justify-content: center; + align-items: center; + min-width: 140px; + height: 45px; + border-radius: 4px; + padding: 5px 12px; + background-color: var(--c-primary); + color: var(--c-white); + border: 1px solid var(--c-primary); + &:hover { + box-shadow: 0 0 3px 0px var(--c-primary); + background-color: var(--c-primary); + //color: var(--c-bg-secondary); + } + span { + margin-left: 5px; + @media screen and (max-width: 599px) { + display: none; + } + } + @media screen and (max-width: 599px) { + position: absolute; + right: 0; + min-width: auto; + font-size: 28px; + } + } + + // search + &-search { + position: relative; + display: flex; + flex-grow: 1; + margin: 0 30px; + &--active { + .table-search__input { + opacity: 1; + } + } + + &__input { + width: 100%; + height: 45px; + border-radius: 4px; + padding: 0 10px; + color: inherit; + background: var(--c-bg-secondary); + border: 1px solid var(--c-primary); + + &:focus { + border: 2px solid var(--c-primary); + } + } + + &__icon { + width: 40px; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + z-index: 4; + cursor: pointer; + } + + &__icon-mobile { + display: none; + margin-left: auto; + margin-right: 130px; + } + + @media (max-width: 599px) { + display: none; + + &.table-search--active { + display: block; + position: absolute; + margin: 0; + width: 100%; + z-index: 2; + } + + &.table-search--active + .table-plus-btn { + display: none; + } + + &.table-search--active + .w-forms__title { + display: none; + } + + &__icon-mobile { + display: inherit; + } + } + } + + .table-header__sort { + position: relative; + cursor: pointer; + .icon-arrow { + transform: rotate(90deg); + font-size: var(--fs); + position: absolute; + top: 3px; + cursor: pointer; + } + } + + th { + position: relative; + padding: 0 16px; + height: 48px; + text-align: left; + font-weight: 500; + font-size: calc(var(--fs) - 2px); + font-size: var(--fs); + line-height: calc(var(--fs) + 8px); + letter-spacing: var(--letter-spacing); + text-transform: capitalize; + color: var(--c-text-primary); + border-bottom: 1px solid var(--c-border); + overflow: hidden; + text-overflow: ellipsis; + .icon-arrow { + opacity: 0; + transition: 0.3s all ease-in-out; + } + &:hover { + .icon-arrow { + opacity: 1; + transition: 0.3s all ease-in-out; + } + } + .table-header__sort._sortActiveDown { + .icon-arrow { + transform: rotate(-90deg); + opacity: 1; + } + } + .table-header__sort._sortActiveUp { + .icon-arrow { + opacity: 1; + } + } + @media all and (max-width: 991.9px) { + display: none; + text-align: left; + } + &:last-child { + width: 140px; + } + } + + td { + cursor: pointer; + padding: 5px 16px; + height: 60px; + text-align: left; + vertical-align: middle; + font-size: calc(var(--fs) - 2px); + line-height: calc(var(--fs) + 8px); + letter-spacing: var(--letter-spacing); + color: var(--c-text-primary); + word-break: break-word; + display: table-cell; + border-bottom: 1px solid var(--c-border); + @media all and (max-width: 991.9px) { + display: flex; + align-items: center; + justify-content: space-between; + column-gap: 5px; + border-bottom: 0; + border: 2px solid var(--c-border); + height: auto; + min-height: 60px; + } + &:before { + content: attr(data-label); + word-break: keep-all; + display: inline-block; + font-weight: 500; + font-size: var(--fs); + line-height: calc(var(--fs) + 8px); + letter-spacing: var(--letter-spacing); + text-transform: capitalize; + color: var(--c-text-primary); + text-overflow: ellipsis; + @media (min-width: 992px) { + display: none; + } + } + } + + tr { + &:last-child { + td { + border-bottom: none; + @media (max-width: 991.9px) { + border-bottom: 2px solid var(--c-border); + } + } + } + td { + &:last-child { + border-right: none; + @media (max-width: 992px) { + border-right: 2px solid var(--c-border); + } + } + &:first-child { + @media (max-width: 992px) { + margin-top: 20px; + } + } + } + th { + &:last-child { + border-right: none; + } + } + } + + .table__actions { + display: flex; + gap: 6px; + + a { + i { + color: var(--c-text-primary); + } + } + } + + .table-body { + &__last-td { + @media (max-width: 991.9px) { + margin-bottom: 20px; + border-bottom: 3px solid var(--c-border); + } + + i { + font-size: 22px; + width: 22px; + &:hover { + color: var(--c-primary); + } + } + } + } + + &-footer { + height: 65px; + display: flex; + gap: 120px; + position: absolute; + width: 100%; + left: 0; + bottom: 0; + padding: 0 8px 0 15px; + align-items: center; + justify-content: space-between; + @media screen and (max-width: 599px) { + height: 90px; + padding: 10px 20px; + flex-direction: column; + position: static; + gap: 20px; + } + + &__pagination { + display: flex; + align-items: center; + position: relative; + bottom: 15px; + + @media (max-width: 599px) { + bottom: 0; + left: 5px; + } + } + + &__arrow { + border: 0; + background: none; + width: 30px; + height: 30px; + margin-right: 30px; + cursor: pointer; + + .chevron { + position: relative; + display: block; + min-width: 22px; + min-height: 22px; + border: 2px solid transparent; + border-radius: 100px; + &::before { + position: absolute; + width: 2px; + height: 90%; + background-color: var(--c-grey); + mix-blend-mode: overlay; + top: 8%; + } + &::after { + content: ''; + display: block; + box-sizing: border-box; + position: absolute; + width: 10px; + height: 10px; + border-bottom: 2px solid var(--c-grey); + border-right: 2px solid var(--c-grey); + mix-blend-mode: overlay; + transform: rotate(135deg); + left: 2px; + top: 2px; + } + } + + &:disabled { + i::after { + border-color: #9f9f9f; + } + i::before { + background: #9f9f9f; + } + } + + &._start { + .chevron { + position: relative; + left: 1px; + } + + .chevron::after { + left: 8px; + top: 4px; + } + .chevron::before { + display: block; + left: 2px; + content: ''; + } + } + &._left { + .chevron { + position: relative; + left: 4px; + } + + .chevron::after { + top: 4px; + } + } + &._right { + .chevron::after { + transform: rotate(315deg); + top: 4px; + } + } + &._end { + .chevron { + position: relative; + left: 2px; + } + + .chevron::after { + left: -3px; + top: 4px; + transform: rotate(315deg); + } + .chevron::before { + display: block; + left: 11px; + content: ''; + } + } + } + + .item-page { + font-size: 12px; + color: #9f9f9f; + letter-spacing: 1px; + display: flex; + align-items: center; + + &__dropdown { + position: relative; + margin: 0 10px; + font-weight: bold; + .caption { + background-color: transparent; + padding: 11px 24px; + border-radius: 4px; + border: 1px solid var(--c-border); + cursor: pointer; + &:hover { + background-color: var(--c-primary); + color: var(--c-bg-secondary); + } + } + .list { + position: absolute; + background-color: var(--c-bg-secondary); + width: 100%; + bottom: 100%; + flex-direction: column; + border-radius: 4px 4px 0 0; + display: none; + z-index: 999; + .item { + > div { + padding: 11px 20px; + cursor: pointer; + text-align: center; + } + &:hover { + background-color: var(--c-primary); + color: var(--c-bg-secondary); + } + } + .item.selected { + font-weight: bold; + } + } + &.open { + .caption { + border-radius: 0 0 4px 4px; + } + .list { + display: flex; + flex-direction: column-reverse; + border: 1px solid var(--c-border); + border-bottom: 0; + } + } + } + } + } + } +} diff --git a/src/scss/index.scss b/src/scss/index.scss new file mode 100644 index 0000000..c628d74 --- /dev/null +++ b/src/scss/index.scss @@ -0,0 +1,51 @@ +// ===== MAIN SCSS FILE ===== +// VENDORS +// UTILS +// LAYOUT +// COMPONENTS +// COMMON +// PLUGINS +// PAGES +// ATOM + + +// ## VENDORS +@import "vendors/normalize"; + +// ## UTILS +@import "utils/vars"; +@import "utils/media"; +@import "utils/mixins"; +@import "utils/fonts"; +@import "utils/icons"; + +// ## LAYOUT +@import "layout/base"; +@import "layout/scroll"; +// @import "layout/grid"; + +// ## COMPONENTS +@import "components/w-alert"; +@import "components/w-btn"; +@import "components/w-switch"; +@import "components/w-forms"; +@import "components/w-card"; +@import "components/w-checkbox"; +@import "components/w-radio"; +@import "components/w-table"; +@import "components/w-select"; +@import "components/w-modal"; + +// ## COMMON + +// ## PLUGINS + +// ## PAGES + +// ## ATOM +@import "atom/display"; +@import "atom/margin"; +// @import "atom/padding"; +// @import "atom/size"; +// @import "atom/text"; +// @import "atom/other"; diff --git a/src/scss/layout/_base.scss b/src/scss/layout/_base.scss new file mode 100644 index 0000000..68250b3 --- /dev/null +++ b/src/scss/layout/_base.scss @@ -0,0 +1,36 @@ +// ===== BASE STYLE ===== +@import '/src/scss/utils/vars'; +html { + font-size: $fs; + overflow: hidden; + height: 100%; +} +body { + font-family: $ff-base; + color: var(--c-text-primary); + line-height: 1.4; + position: relative; + overflow: hidden; + height: 100%; + display: flex; + flex-direction: column; +} +/* === PAGE LAYOUT === */ +.container { + margin-left: auto; + margin-right: auto; + padding: $padding; + max-width: 100%; + width: 100%; +} +.container-box{ + display: flex; + align-items: center; + .w-input__checkbox{ + margin-right: 5px; + } +} + +.showTable{ + padding: 20px 20px 0 20px !important; +} \ No newline at end of file diff --git a/src/scss/layout/_grid.scss b/src/scss/layout/_grid.scss new file mode 100644 index 0000000..42f124c --- /dev/null +++ b/src/scss/layout/_grid.scss @@ -0,0 +1,58 @@ +// ===== GRID SETTINGS ===== +.row { + display: flex; + flex-wrap: wrap; + width: calc(100% + 20px); + margin-left: -10px; +} +.col-5 { + width: 20%; + padding: 0 10px 10px; + @include bp-max(sm) { + width: 100%; + } +} +.col-4 { + width: 25%; + padding: 0 10px 10px; + @include bp-max(sm) { + width: 100%; + } +} +.col-3 { + width: 33.33%; + padding: 0 10px 10px; + @include bp-max(sm) { + width: 100%; + } +} +.col-25 { + width: 40%; + padding: 0 10px 10px; + @include bp-max(sm) { + width: 100%; + } +} +.col-2 { + width: 50%; + padding: 0 10px 10px; + @include bp-max(sm) { + width: 100%; + } +} +.col-2m { + width: 50%; + padding: 0 10px 10px; +} +.col-23 { + width: 66.66%; + padding: 0 10px 10px; + + @include bp-max(sm) { + width: 100%; + } +} +.col-1 { + width: 100%; + padding: 0 10px 10px; +} diff --git a/src/scss/layout/_scroll.scss b/src/scss/layout/_scroll.scss new file mode 100644 index 0000000..3aee410 --- /dev/null +++ b/src/scss/layout/_scroll.scss @@ -0,0 +1,17 @@ +@import '/src/scss/utils/vars'; +@import 'angular'; +// ===== SCROLL CUSTOMIZE ===== +*::-webkit-scrollbar-track { + box-shadow: inset 0 0 6px var(--c-shadow); + background-color: $c-white; + display: none; +} +*::-webkit-scrollbar { + width: 5px; + height: 5px; + background-color: $c-white; +} +* ::-webkit-scrollbar-thumb { + box-shadow: inset 0 0 6px var(--c-basic); + background-color: var(--c-basic); +} diff --git a/src/scss/utils/_fonts.scss b/src/scss/utils/_fonts.scss new file mode 100644 index 0000000..c2c2500 --- /dev/null +++ b/src/scss/utils/_fonts.scss @@ -0,0 +1,28 @@ +@font-face { + font-family: 'Poppins'; + src: url('src/fonts/1.woff2') format('woff2'); + font-weight: 300; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: 'Poppins'; + src: url('src/fonts/2.woff2') format('woff2'); + font-weight: normal; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: 'Poppins'; + src: url('src/fonts/3.woff2') format('woff2'); + font-weight: 500; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: 'Poppins'; + src: url('src/fonts/4.woff2') format('woff2'); + font-weight: bold; + font-style: normal; + font-display: swap; +} diff --git a/src/scss/utils/_icons.scss b/src/scss/utils/_icons.scss new file mode 100644 index 0000000..f3c95de --- /dev/null +++ b/src/scss/utils/_icons.scss @@ -0,0 +1,21 @@ +// ===== ICONS IMPORT ===== +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: url(src/fonts/5.woff2) format('woff2'); +} + +.material-icons, i { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 26px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; +} diff --git a/src/scss/utils/_media.scss b/src/scss/utils/_media.scss new file mode 100644 index 0000000..9760b7e --- /dev/null +++ b/src/scss/utils/_media.scss @@ -0,0 +1,44 @@ +// ===== MEDIA MIXINS FOR RESPONSIVE ===== +/* USE: @include bp-max(sm)... bp-min... bp-only... */ +$breakpoints-map: (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1980px, ) !default; +@function breakpoint-next($name, $breakpoints: $breakpoints-map, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} +@function breakpoint-min($name, $breakpoints: $breakpoints-map) { + $min: map-get($breakpoints, $name); + @return if($min !=0, $min, null); +} +@function breakpoint-max($name, $breakpoints: $breakpoints-map) { + $next: breakpoint-next($name, $breakpoints); + @return if($next, breakpoint-min($next, $breakpoints) - 0.1, null); +} +@mixin bp-min($name, $breakpoints: $breakpoints-map) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } + @else { + @content; + } +} +@mixin bp-max($name, $breakpoints: $breakpoints-map) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } + @else { + @content; + } +} +@mixin bp-only($name, $breakpoints: $breakpoints-map) { + @include bp-min($name, $breakpoints) { + @include bp-max($name, $breakpoints) { + @content; + } + } +} \ No newline at end of file diff --git a/src/scss/utils/_mixins.scss b/src/scss/utils/_mixins.scss new file mode 100644 index 0000000..7746217 --- /dev/null +++ b/src/scss/utils/_mixins.scss @@ -0,0 +1,14 @@ +@mixin text-default($ls, $lh, $fw, $fs, $color) { + letter-spacing: $ls; + line-height: $lh; + font-weight: $fw; + font-size: $fs; + color: $color; +} +@mixin flexBox ($display: null, $row:null, $jc: null, $ai: null, $wrap: null) { + display: $display; + flex-direction: $row; + justify-content: $jc; + align-items: $ai; + flex-wrap: $wrap; +} diff --git a/src/scss/utils/_vars.scss b/src/scss/utils/_vars.scss new file mode 100644 index 0000000..899633b --- /dev/null +++ b/src/scss/utils/_vars.scss @@ -0,0 +1,119 @@ + $default-c-white: #fff; + $c-white: if(variable-exists(--c-white), var(--c-white), $default-c-white); + + $default-c-black: #000; + $c-black: if(variable-exists(--c-black), var(--c-black), $default-c-black); + + $default-c-grey: #e7e7e7; + $c-grey: if(variable-exists(--c-grey), var(--c-grey), $default-c-grey); + + $default-c-grey-dark: #bfbfbf; + $c-grey-dark: if(variable-exists(--c-grey-dark), var(--c-grey-dark), $default-c-grey-dark); + + // classic + $default-c-warn: #e67e22; + $c-warn: if(variable-exists(--c-warn), var(--c-warn), $default-c-warn); + + $default-c-error: #e74c3c; + $c-error: if(variable-exists(--c-error), var(--c-error), $default-c-error); + + $default-c-error-hover: #d62c1a; + $c-error-hover: if(variable-exists(--c-error-hover), var(--c-error-hover), $default-c-error-hover); + + $default-c-success: #14c76e; + $c-success: if(variable-exists(--c-success), var(--c-success), $default-c-success); + + $default-c-info: #17a2b8; + $c-info: if(variable-exists(--c-info), var(--c-info), $default-c-info); + + // geometry + $default-container: 1210px; + $container: if(variable-exists(--container), var(--container), $default-container); + + $default-b-radius: 8px; + $b-radius: if(variable-exists(--b-radius), $b-radius, $default-b-radius); + + $default-b-radius-card: 10px; + $b-radius-card: if(variable-exists(--b-radius-card), var(--b-radius-card), $default-b-radius-card); + + $default-b-radius-btn: 10px; + $b-radius-btn: if(variable-exists(--b-radius-btn), var(--b-radius-btn), $default-b-radius-btn); + + $default-b-radius-img: 50%; + $b-radius-img: if(variable-exists(--b-radius-img), var(--b-radius-img), $default-b-radius-img); + + $default-padding: 10px; + $padding: if(variable-exists(--padding), var(--padding), $default-padding); + + $default-fs: 16px; + $fs: if(variable-exists(--fs), var(--fs), $default-fs); + + $default-ff-bold: bold; + $ff-bold: if(variable-exists(--ff-bold), var(--ff-bold), $default-ff-bold); + + $default-ff-base: "Poppins", + sans-serif; + $ff-base: if(variable-exists(--ff-base), var(--ff-base), $default-ff-base); + + $default-letter-spacing: 0.3px; + $letter-spacing: if(variable-exists(--letter-spacing), var(--letter-spacing), $default-letter-spacing); + + $default-transition: .3s all ease-in-out; + $transition: if(variable-exists(--transition), var(--transition), $default-transition); + + // theme + :root { + --c-white: #fff; + --c-basic: #3558ae; + --c-primary: #256eff; + --c-primary-hover: #0051f1; + --c-secondary: rgb(197, 61, 61); + --c-secondary-hover: rgb(150, 42, 42); + --c-bg-primary: #f3f4f7; + --c-bg-secondary: #ffffff; + --c-bg-tertiary: #fcfdfe; + --c-border: #f0f1f7; + --c-shadow: #f3f3f3; + --c-text-primary: #666666; + --c-text-secondary: #19235c; + --c-placeholder: #313335ab; + --c-img-round: 50%; + --card-background: #fefefe; + --card-border-radius: 10px; + --card-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + --card-margin-bottom: 24px; + --card-header-padding: 20px; + --card-header-background: #e0e0e0; + --card-body-padding: 20px; + --card-section-padding: 10px 0; + --card-footer-padding: 20px; + --card-footer-background: #e0e0e0; + --card-border-width: 2px; + --card-border-color: #cccccc; + --file-img-border-radius: 50%; + --file-add-bg: #28a745; + --file-add-bg-hover: #218838; + --file-item-border-radius: 10px; + --day-name: #988888; + --b-radius-btn: 10px; + --transition: all .3s; + --events: #4c8e9d; + --border: rgba(102, 91, 91, 0.432); + } + + html.dark:root { + --c-white: #fff; + --c-basic: #333; + --c-bg-primary: #282828; + --c-bg-secondary: #343434; + --c-bg-tertiary: #404040; + --c-border: #404040; + --c-shadow: #444444; + --c-text-primary: #ffffff; + --c-text-secondary: #ffffff; + --c-placeholder: #d3cdcd; + --c-calendar: #141414; + --day-name: #dad5d5; + --events: #1c2e32; + --border: rgb(255 255 255 / 23%); + } diff --git a/src/scss/utils/angular.scss b/src/scss/utils/angular.scss new file mode 100644 index 0000000..0de1b0a --- /dev/null +++ b/src/scss/utils/angular.scss @@ -0,0 +1,4 @@ +// ===== ONLY FOR ANGULAR COMPONENTS ===== +@import 'vars'; +@import 'media'; +@import 'mixins'; diff --git a/src/scss/vendors/_normalize.scss b/src/scss/vendors/_normalize.scss new file mode 100644 index 0000000..8243ba1 --- /dev/null +++ b/src/scss/vendors/_normalize.scss @@ -0,0 +1,98 @@ +html, +*, +*:before, +*:after { + box-sizing: border-box; +} +html { + line-height: 1.15; + -webkit-text-size-adjust: 100%; +} +* { + outline: 0; +} +html, +body { + margin: 0; + padding: 0; +} +main { + display: block; +} +h1 { + font-size: 2em; + margin: 0; +} +hr { + box-sizing: content-box; + height: 0; + overflow: visible; +} +pre { + font-family: monospace, monospace; + font-size: 1em; +} +img { + border-style: none; +} +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0; +} +button, +input { + overflow: visible; +} +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} +textarea { + overflow: auto; +} +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; + padding: 0; +} +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; +} +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; +} +[hidden] { + display: none; +} +img { + max-width: 100%; + display: inline-block; + vertical-align: top; +} +a { + text-decoration: none; +} diff --git a/src/styles.scss b/src/styles.scss new file mode 100644 index 0000000..dc39dfa --- /dev/null +++ b/src/styles.scss @@ -0,0 +1 @@ +@import 'scss'; diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 0000000..cba5368 --- /dev/null +++ b/src/test.ts @@ -0,0 +1,14 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..82d91dc --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,15 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..aea5f9a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,33 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "noPropertyAccessFromIndexSignature": true, + "forceConsistentCasingInFileNames": true, + "strictPropertyInitialization": false, + "esModuleInterop": true, + "typeRoots": ["node_modules/@types"], + "noFallthroughCasesInSwitch": true, + "experimentalDecorators": true, + "noImplicitOverride": true, + "outDir": "./dist/out-tsc", + "moduleResolution": "node", + "noImplicitReturns": true, + "resolveJsonModule": true, + "importHelpers": true, + "declaration": false, + "target": "ES2022", + "module": "es2020", + "sourceMap": true, + "baseUrl": "./", + "strict": true, + "lib": ["es2020", "dom"], + "useDefineForClassFields": false + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/tsconfig.spec.json b/tsconfig.spec.json new file mode 100644 index 0000000..092345b --- /dev/null +++ b/tsconfig.spec.json @@ -0,0 +1,18 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +}