@energie360/ui-library 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/base/_input-resets.scss +9 -3
  2. package/base/_resets.scss +5 -0
  3. package/base/abstracts/_mixins.scss +11 -5
  4. package/base/main-base.scss +1 -0
  5. package/components/accordion-item/accordion-item.scss +62 -0
  6. package/components/accordion-item/u-accordion-item.vue +44 -0
  7. package/components/card/card.scss +58 -0
  8. package/components/card/u-card.vue +26 -0
  9. package/components/card-header/card-header.scss +102 -0
  10. package/components/card-header/u-card-header.vue +51 -0
  11. package/components/card-hint/card-hint.scss +13 -0
  12. package/components/card-hint/u-card-hint.vue +23 -0
  13. package/components/card-price/card-price.scss +110 -0
  14. package/components/card-price/u-card-price.vue +47 -0
  15. package/components/card-table/card-table.scss +76 -0
  16. package/components/card-table/u-card-table.vue +77 -0
  17. package/components/card-toggle-switches/card-toggle-switches.scss +13 -0
  18. package/components/card-toggle-switches/u-card-toggle-switches.vue +30 -0
  19. package/components/collapsible/collapsible.scss +14 -0
  20. package/components/collapsible/u-collapsible.vue +81 -0
  21. package/components/collapsible-group/u-collapsible-group.vue +14 -0
  22. package/components/icon-teaser/icon-teaser.scss +58 -0
  23. package/components/icon-teaser/u-icon-teaser.vue +35 -0
  24. package/components/icon-teaser-group/icon-teaser-group.scss +10 -0
  25. package/components/icon-teaser-group/u-icon-teaser-group.vue +19 -0
  26. package/components/icon-text-block/{icon-text-block.vue → u-icon-text-block.vue} +11 -12
  27. package/components/index.js +14 -0
  28. package/components/language-nav/language-nav.scss +32 -0
  29. package/components/language-nav/u-language-nav.vue +27 -0
  30. package/components/panel/panel.scss +107 -0
  31. package/components/panel/u-panel.vue +48 -0
  32. package/components/progress-bar/progress-bar.scss +37 -0
  33. package/components/progress-bar/u-progress-bar.vue +21 -0
  34. package/components/richtext/richtext.scss +208 -0
  35. package/components/richtext/u-richtext.vue +21 -0
  36. package/components/table/cell-ctas.scss +12 -0
  37. package/components/table/cell-icon-group.scss +12 -0
  38. package/components/table/cell-icon-text.scss +22 -0
  39. package/components/table/cell-progress-bar.scss +23 -0
  40. package/components/table/table-cell.mixins.scss +60 -0
  41. package/components/table/table-cell.scss +24 -0
  42. package/components/table/table-header.scss +5 -0
  43. package/components/table/table-heading.scss +8 -0
  44. package/components/table/table-row.scss +20 -0
  45. package/components/table/table.scss +12 -0
  46. package/components/table/table.type.ts +31 -0
  47. package/components/table/u-cell-ctas.vue +28 -0
  48. package/components/table/u-cell-icon-group.vue +31 -0
  49. package/components/table/u-cell-icon-text.vue +23 -0
  50. package/components/table/u-cell-progress-bar.vue +22 -0
  51. package/components/table/u-table-cell.vue +37 -0
  52. package/components/table/u-table-header.vue +9 -0
  53. package/components/table/u-table-heading.vue +21 -0
  54. package/components/table/u-table-row.vue +17 -0
  55. package/components/table/u-table.vue +11 -0
  56. package/components/tooltip/dom.js +167 -0
  57. package/components/tooltip/popover.ts +208 -0
  58. package/components/tooltip/tooltip.scss +75 -0
  59. package/components/tooltip/u-tooltip.vue +72 -0
  60. package/components/tooltip/viewport.js +21 -0
  61. package/custom-elements.js +1 -0
  62. package/dist/base-style.css +409 -2
  63. package/dist/base-style.css.map +1 -0
  64. package/dist/elements/text-link.css +40 -0
  65. package/dist/elements/text-link.css.map +1 -0
  66. package/dist/layout/split.css +124 -0
  67. package/dist/layout/split.css.map +1 -0
  68. package/elements/button/_button-base.scss +1 -1
  69. package/elements/button/_button-filled-inverted.scss +3 -3
  70. package/elements/button/_button-filled.scss +3 -3
  71. package/elements/button/_button-outlined-inverted.scss +3 -3
  72. package/elements/button/_button-outlined.scss +3 -3
  73. package/elements/button/_button-plain.scss +3 -3
  74. package/elements/button/_button-secondary-outlined.scss +3 -3
  75. package/elements/button/button.js +2 -2
  76. package/elements/button/button.scss +1 -1
  77. package/elements/button/u-button.vue +41 -0
  78. package/elements/button-chip/button-chip.scss +83 -0
  79. package/elements/button-chip/u-button-chip.vue +45 -0
  80. package/elements/elements.js +35 -0
  81. package/elements/form-field/form-field-base.scss +141 -0
  82. package/elements/form-field/form-field-error.scss +20 -0
  83. package/elements/form-field/form-field-prefix-suffix.scss +80 -0
  84. package/elements/form-field/form-field-states.scss +59 -0
  85. package/elements/form-field/form-field.types.ts +8 -0
  86. package/elements/form-field/index.scss +4 -0
  87. package/elements/icon/icon.js +2 -2
  88. package/elements/icon/{icon.vue → u-icon.vue} +12 -18
  89. package/elements/icon-button/icon-button.js +2 -2
  90. package/elements/icon-button/{icon-button.vue → u-icon-button.vue} +14 -15
  91. package/elements/image/image.scss +3 -0
  92. package/elements/image/u-image.vue +17 -0
  93. package/elements/index.js +6 -31
  94. package/elements/loader/loader.js +2 -2
  95. package/elements/loader/{loader.vue → u-loader.vue} +6 -7
  96. package/elements/numeric-stepper/numeric-stepper.scss +110 -0
  97. package/elements/numeric-stepper/u-numeric-stepper.vue +135 -0
  98. package/elements/select/select.scss +32 -0
  99. package/elements/select/u-select.vue +130 -0
  100. package/elements/select-chip/select-chip.scss +18 -0
  101. package/elements/select-chip/u-select-chip.vue +50 -0
  102. package/elements/select-chips/select-chips.scss +5 -0
  103. package/elements/select-chips/u-select-chips.vue +23 -0
  104. package/elements/spectro/spectro.scss +10 -0
  105. package/elements/spectro/u-spectro.vue +11 -0
  106. package/elements/text-field/text-field.scss +30 -0
  107. package/elements/text-field/text-field.types.ts +6 -0
  108. package/elements/text-field/u-text-field.vue +180 -0
  109. package/elements/text-link/text-link.scss +57 -0
  110. package/elements/toggle-switch/toggle-switch-small.scss +40 -0
  111. package/elements/toggle-switch/toggle-switch.scss +149 -0
  112. package/elements/toggle-switch/u-toggle-switch.vue +68 -0
  113. package/elements/types.ts +19 -0
  114. package/env.d.ts +1 -0
  115. package/globals.js +1 -2
  116. package/helpers/transition-height.vue +39 -0
  117. package/i18n/i18n.ts +40 -0
  118. package/layout/grid/grid.mixin.scss +4 -11
  119. package/layout/grid/grid.scss +6 -7
  120. package/layout/split/split.scss +96 -0
  121. package/modules/footer/footer.scss +161 -0
  122. package/modules/footer/u-footer.vue +59 -0
  123. package/package.json +33 -13
  124. package/tsconfig.app.json +12 -0
  125. package/tsconfig.json +11 -0
  126. package/tsconfig.node.json +19 -0
  127. package/utility/elements/text-link.scss +1 -0
  128. package/utility/layout/split.scss +1 -0
  129. package/utility/utility-text.js +1 -0
  130. package/utils/object/deep-get.js +1 -2
  131. package/utils/translations/translate.js +13 -0
  132. package/{vite.config.js → vite.config.ts} +2 -1
  133. package/watch.js +27 -0
  134. package/wizard/index.js +4 -0
  135. package/wizard/wizard-intro/{wizard-intro.vue → u-wizard-intro.vue} +12 -9
  136. package/wizard/wizard-intro/wizard-intro.scss +4 -0
  137. package/wizard/wizard-layout/{wizard-layout-block.vue → u-wizard-layout-block.vue} +7 -5
  138. package/wizard/wizard-layout/{wizard-layout-element.vue → u-wizard-layout-element.vue} +1 -1
  139. package/wizard/wizard-layout/{wizard-layout.vue → u-wizard-layout.vue} +1 -1
  140. package/wizard/wizard-layout/wizard-layout.scss +6 -6
  141. package/dist/base-style.js +0 -2
  142. package/dist/base-style.js.map +0 -1
  143. package/dist/index.css +0 -1
  144. package/dist/index.js +0 -5194
  145. package/dist/index.js.map +0 -1
  146. package/elements/button/button.vue +0 -42
  147. package/index.js +0 -1
  148. /package/components/icon-text-block-group/{icon-text-block-group.vue → u-icon-text-block-group.vue} +0 -0
@@ -0,0 +1,77 @@
1
+ <script setup lang="ts">
2
+ interface Cell {
3
+ text: string
4
+ info?: string
5
+ discount: string
6
+ }
7
+
8
+ interface Table {
9
+ heading?: [Cell, Cell]
10
+ rows?: Array<[Cell, Cell]>
11
+ }
12
+
13
+ interface Props {
14
+ title?: string
15
+ secondaryTitle?: string
16
+ tables: Table[]
17
+ }
18
+
19
+ defineProps<Props>()
20
+
21
+ const getCellText = (cell: Cell): string => (cell.discount ? cell.discount : cell.text || '')
22
+
23
+ const getCellDiscount = (cell: Cell): string => (cell.discount ? cell.text : '')
24
+ </script>
25
+
26
+ <template>
27
+ <div class="card-table-wrapper">
28
+ <div class="card-table-heading">
29
+ <div v-if="title" class="card-table-heading__title">
30
+ {{ title }}
31
+ </div>
32
+
33
+ <div v-if="secondaryTitle" class="card-table-heading__secondary-title">
34
+ {{ secondaryTitle }}
35
+ </div>
36
+ </div>
37
+
38
+ <table v-for="(table, idx) in tables" :key="idx" class="card-table">
39
+ <!-- TABLE HEADING -->
40
+ <thead v-if="table.heading">
41
+ <tr>
42
+ <th>
43
+ {{ table.heading[0].text }}
44
+ <span v-if="table.heading[0].info" class="info">{{ table.heading[0].info }}</span>
45
+ </th>
46
+ <th>
47
+ <div>
48
+ {{ getCellText(table.heading[1])
49
+ }}<span v-if="getCellDiscount(table.heading[1])" class="discount"
50
+ ><s>{{ getCellDiscount(table.heading[1]) }}</s></span
51
+ >
52
+ </div>
53
+ </th>
54
+ </tr>
55
+ </thead>
56
+
57
+ <!-- TABLE BODY -->
58
+ <tbody>
59
+ <tr v-for="(row, idx2) in table.rows" :key="idx2">
60
+ <td>{{ row[0].text || '' }}</td>
61
+ <td>
62
+ <div>
63
+ {{ getCellText(row[1])
64
+ }}<span v-if="getCellDiscount(row[1])" class="discount"
65
+ ><s>{{ getCellDiscount(row[1]) }}</s></span
66
+ >
67
+ </div>
68
+ </td>
69
+ </tr>
70
+ </tbody>
71
+ </table>
72
+ </div>
73
+ </template>
74
+
75
+ <style lang="scss">
76
+ @use './card-table.scss';
77
+ </style>
@@ -0,0 +1,13 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .card-toggle-switches {
4
+ .card-toggle-switches__title {
5
+ @include a.type(200, strong);
6
+
7
+ margin-bottom: var(--e-space-4);
8
+ }
9
+
10
+ .toggle-switch + .toggle-switch {
11
+ margin-top: var(--e-space-4);
12
+ }
13
+ }
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import UToggleSwitch, { ToggleSwitch } from '../../elements/toggle-switch/u-toggle-switch.vue'
3
+
4
+ interface Props {
5
+ title?: string
6
+ toggles?: ToggleSwitch[]
7
+ }
8
+
9
+ defineProps<Props>()
10
+ </script>
11
+
12
+ <template>
13
+ <div class="card-toggle-switches">
14
+ <h4 class="card-toggle-switches__title">{{ title }}</h4>
15
+
16
+ <slot>
17
+ <UToggleSwitch
18
+ v-for="(toggle, idx) in toggles"
19
+ :key="idx"
20
+ v-bind="toggle"
21
+ variant="small"
22
+ label-position="right"
23
+ ></UToggleSwitch>
24
+ </slot>
25
+ </div>
26
+ </template>
27
+
28
+ <style lang="scss">
29
+ @use './card-toggle-switches.scss';
30
+ </style>
@@ -0,0 +1,14 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .collapsible {
4
+ .collapsible__heading {
5
+ line-height: 1;
6
+ color: inherit;
7
+ }
8
+
9
+ .collapsible__header {
10
+ text-align: left;
11
+ width: 100%;
12
+ cursor: pointer;
13
+ }
14
+ }
@@ -0,0 +1,81 @@
1
+ <script setup lang="ts">
2
+ import { useId, computed, ref, inject, watch } from 'vue'
3
+ import TransitionHeight from '../../helpers/transition-height.vue'
4
+
5
+ interface Props {
6
+ header?: string
7
+ panel?: string
8
+ level?: 2 | 3 | 4 | 5 | 6
9
+ expanded?: boolean
10
+ }
11
+
12
+ const cId = useId()
13
+ const { level = 3, expanded = false } = defineProps<Props>()
14
+
15
+ // Initial state
16
+ const panelHidden = ref(!expanded)
17
+
18
+ const headingTag = computed(() => `h${level}`)
19
+ const headerId = `collapsible-header-${cId}`
20
+ const panelId = `collapsible-panel-${cId}`
21
+
22
+ // This will only be available if there's a parent <UCollapsibelGroup>
23
+ const { activeItem, updateActiveItem } = inject('activeItem', {})
24
+
25
+ const onToggle = () => {
26
+ panelHidden.value = !panelHidden.value
27
+
28
+ if (updateActiveItem) {
29
+ updateActiveItem(cId)
30
+ }
31
+ }
32
+
33
+ if (activeItem) {
34
+ watch(activeItem, (newV) => {
35
+ if (newV !== cId) {
36
+ // Collapse component
37
+ panelHidden.value = true
38
+ }
39
+ })
40
+ }
41
+
42
+ defineExpose({
43
+ isExpanded: computed(() => !panelHidden.value),
44
+ })
45
+ </script>
46
+
47
+ <template>
48
+ <div class="collapsible">
49
+ <component :is="headingTag" class="collapsible__heading">
50
+ <button
51
+ :id="headerId"
52
+ :aria-controls="panelId"
53
+ class="collapsible__header"
54
+ type="button"
55
+ :aria-expanded="panelHidden ? 'false' : 'true'"
56
+ @click="onToggle"
57
+ >
58
+ <slot name="header">
59
+ {{ header }}
60
+ </slot>
61
+ </button>
62
+ </component>
63
+
64
+ <TransitionHeight>
65
+ <section
66
+ v-if="!panelHidden"
67
+ :id="panelId"
68
+ class="collapsible__panel"
69
+ :aria-labelledby="headerId"
70
+ >
71
+ <slot name="panel">
72
+ <div v-html="panel"></div>
73
+ </slot>
74
+ </section>
75
+ </TransitionHeight>
76
+ </div>
77
+ </template>
78
+
79
+ <style scoped lang="scss">
80
+ @use './collapsible.scss';
81
+ </style>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import { ref, provide } from 'vue'
3
+
4
+ const activeItem = ref(null)
5
+ const updateActiveItem = (id: string): void => {
6
+ activeItem.value = id
7
+ }
8
+
9
+ provide('activeItem', { activeItem, updateActiveItem })
10
+ </script>
11
+
12
+ <template>
13
+ <slot></slot>
14
+ </template>
@@ -0,0 +1,58 @@
1
+ @use '../../base/abstracts/' as a;
2
+
3
+ .icon-tesaer__content {
4
+ display: flex;
5
+ flex-direction: column;
6
+ row-gap: var(--e-space-2);
7
+ }
8
+
9
+ .icon-teaser__image-wrapper {
10
+ margin: 0 auto var(--e-space-6);
11
+ display: flex;
12
+ align-items: center;
13
+ justify-content: center;
14
+ flex: 0 0 auto;
15
+ width: a.rem(120);
16
+ height: a.rem(120);
17
+ border-radius: 100%;
18
+ background-color: var(--e-c-primary-01-50);
19
+
20
+ @include a.bp(m) {
21
+ margin-bottom: var(--e-space-4);
22
+ width: a.rem(96);
23
+ height: a.rem(96);
24
+ }
25
+
26
+ img {
27
+ width: a.rem(56);
28
+ height: a.rem(56);
29
+
30
+ @include a.bp(m) {
31
+ width: a.rem(38);
32
+ height: a.rem(38);
33
+ }
34
+ }
35
+ }
36
+
37
+ .icon-teaser__title {
38
+ @include a.type(400, strong);
39
+
40
+ text-align: center;
41
+
42
+ @include a.bp(m) {
43
+ @include a.type(300, strong);
44
+ }
45
+ }
46
+
47
+ .icon-teaser__description {
48
+ @include a.type(200);
49
+
50
+ margin-top: var(--e-space-3);
51
+ text-align: center;
52
+
53
+ @include a.bp(m) {
54
+ margin-top: var(--e-space-1);
55
+
56
+ @include a.type(100);
57
+ }
58
+ }
@@ -0,0 +1,35 @@
1
+ <script setup lang="ts">
2
+ import { Image } from '../../elements/types.ts'
3
+
4
+ export interface IconTeaser {
5
+ title?: string
6
+ description?: string
7
+ image?: Image
8
+ }
9
+
10
+ defineProps<IconTeaser>()
11
+ </script>
12
+
13
+ <template>
14
+ <div class="icon-teaser">
15
+ <div class="icon-teaser__image-wrapper">
16
+ <slot name="image">
17
+ <img aria-hidden="true" :src="image?.src" :alt="image?.alt" />
18
+ </slot>
19
+ </div>
20
+
21
+ <div class="icon-teaser__content">
22
+ <h2 class="icon-teaser__title">
23
+ <slot name="title">{{ title }}</slot>
24
+ </h2>
25
+
26
+ <p class="icon-teaser__description">
27
+ <slot name="description">{{ description }}</slot>
28
+ </p>
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <style lang="scss">
34
+ @use './icon-teaser.scss';
35
+ </style>
@@ -0,0 +1,10 @@
1
+ @use '../../base/abstracts/' as a;
2
+
3
+ .icon-teaser-group {
4
+ display: flex;
5
+ gap: var(--e-space-10);
6
+
7
+ @include a.bp(lg) {
8
+ flex-direction: column;
9
+ }
10
+ }
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import UIconTeaser, { IconTeaser } from '../icon-teaser/u-icon-teaser.vue'
3
+
4
+ interface Props {
5
+ items?: IconTeaser[]
6
+ }
7
+
8
+ defineProps<Props>()
9
+ </script>
10
+
11
+ <template>
12
+ <div class="icon-teaser-group">
13
+ <slot><UIconTeaser v-for="(item, idx) in items" :key="idx" v-bind="item"></UIconTeaser></slot>
14
+ </div>
15
+ </template>
16
+
17
+ <style lang="scss">
18
+ @use './icon-teaser-group.scss';
19
+ </style>
@@ -1,20 +1,19 @@
1
- <script setup>
2
- defineProps({
3
- title: String,
4
- description: String,
5
- image: Object,
6
- })
1
+ <script setup lang="ts">
2
+ import { Image } from '../../elements/types.ts'
3
+
4
+ interface Props {
5
+ title: string
6
+ description?: string
7
+ image: Image
8
+ }
9
+
10
+ defineProps<Props>()
7
11
  </script>
8
12
 
9
13
  <template>
10
14
  <div class="icon-text-block">
11
15
  <div class="illu-wrapper">
12
- <img
13
- class="illustration"
14
- aria-hidden="true"
15
- :src="image.src"
16
- :alt="image.alt"
17
- />
16
+ <img class="illustration" aria-hidden="true" :src="image.src" :alt="image.alt" />
18
17
  </div>
19
18
  <div class="content">
20
19
  <h2 class="title">{{ title }}</h2>
@@ -0,0 +1,14 @@
1
+ /**
2
+ * It's not recommended to import components from this file, because tree-shaking won't work then.
3
+ * -> https://vite.dev/guide/performance#avoid-barrel-files
4
+ */
5
+ export { default as UIconTextBlock } from './icon-text-block/u-icon-text-block.vue'
6
+ export { default as UIconTextBlockGroup } from './icon-text-block-group/u-icon-text-block-group.vue'
7
+ export { default as UTable } from './table/u-table.vue'
8
+ export { default as UTableHeader } from './table/u-table-header.vue'
9
+ export { default as UTableRow } from './table/u-table-row.vue'
10
+ export { default as UTableCell } from './table/u-table-cell.vue'
11
+ export { default as UTableHeading } from './table/u-table-heading.vue'
12
+ export { default as UCellIconText } from './table/u-cell-icon-text.vue'
13
+ export { default as UCellCtas } from './table/u-cell-ctas.vue'
14
+ export { default as UTooltip } from './tooltip/u-tooltip.vue'
@@ -0,0 +1,32 @@
1
+ @use '../../base/abstracts/' as a;
2
+ @use '../../elements/text-link/text-link.scss' as t;
3
+
4
+ .language-nav {
5
+ @include a.type(100, weak);
6
+
7
+ display: flex;
8
+ grid-gap: var(--e-space-4);
9
+
10
+ .language-nav__active-lang,
11
+ > p {
12
+ color: var(--e-c-primary-01-900);
13
+ }
14
+
15
+ .language-nav__link,
16
+ > a {
17
+ text-decoration: none;
18
+ color: var(--e-c-mono-700);
19
+
20
+ &:hover {
21
+ color: var(--e-c-secondary-01-900);
22
+ }
23
+
24
+ &:active {
25
+ color: var(--e-c-primary-01-700);
26
+ }
27
+ }
28
+
29
+ @include a.bp(lg) {
30
+ @include a.type(50);
31
+ }
32
+ }
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ interface LanguageSwitch {
3
+ href: string
4
+ hreflang: string
5
+ label: string
6
+ isActive?: boolean
7
+ }
8
+
9
+ interface Props {
10
+ links: LanguageSwitch[]
11
+ }
12
+
13
+ defineProps<Props>()
14
+ </script>
15
+
16
+ <template>
17
+ <nav class="language-nav">
18
+ <template v-for="(link, idx) in links" :key="idx">
19
+ <p v-if="link.isActive">{{ link.label }}</p>
20
+ <a v-else :href="link.href" :hreflang="link.hreflang">{{ link.label }}</a>
21
+ </template>
22
+ </nav>
23
+ </template>
24
+
25
+ <style lang="scss">
26
+ @use './language-nav.scss';
27
+ </style>
@@ -0,0 +1,107 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .panel {
4
+ position: relative;
5
+ padding: var(--e-space-14) a.rem(400) var(--e-space-14) var(--e-space-14);
6
+ box-shadow: var(--e-elevation-md);
7
+ background-color: var(--e-c-mono-00);
8
+ border-radius: var(--e-brd-radius-3);
9
+ border: 1px solid var(--e-c-mono-200);
10
+ overflow: hidden;
11
+ align-items: center;
12
+ display: flex;
13
+ column-gap: a.rem(40);
14
+
15
+ &.has-image {
16
+ padding: var(--e-space-14);
17
+
18
+ @include a.bp('2xl') {
19
+ padding: var(--e-space-10);
20
+ }
21
+
22
+ @include a.bp(m) {
23
+ padding: var(--e-space-6);
24
+ flex-direction: column;
25
+ row-gap: var(--e-space-6);
26
+ }
27
+ }
28
+
29
+ @include a.bp('2xl') {
30
+ padding: var(--e-space-10) a.rem(344) var(--e-space-10) var(--e-space-10);
31
+ }
32
+
33
+ @include a.bp('lg') {
34
+ padding: var(--e-space-6) var(--e-space-6) a.rem(104) var(--e-space-6);
35
+ }
36
+ }
37
+
38
+ .panel__content {
39
+ order: 1;
40
+ }
41
+
42
+ .panel__title {
43
+ margin-bottom: var(--e-space-3);
44
+
45
+ h2 {
46
+ @include a.type(500, strong);
47
+ }
48
+
49
+ @include a.bp(lg) {
50
+ margin-bottom: var(--e-space-2);
51
+
52
+ h2 {
53
+ @include a.type(300, strong);
54
+ }
55
+ }
56
+ }
57
+
58
+ .panel__text {
59
+ @include a.type(300);
60
+
61
+ @include a.bp(lg) {
62
+ @include a.type(200);
63
+ }
64
+ }
65
+
66
+ .panel__spectro {
67
+ pointer-events: none;
68
+ position: absolute;
69
+ top: calc(50% - 700px);
70
+ right: a.rem(-1560 + 400);
71
+ width: a.rem(1560);
72
+ height: a.rem(1560);
73
+ user-select: none;
74
+
75
+ @include a.bp('2xl') {
76
+ right: a.rem(-1400 + 344);
77
+ width: a.rem(1400);
78
+ height: a.rem(1400);
79
+ }
80
+
81
+ @include a.bp(lg) {
82
+ top: calc(100% - 95px);
83
+ right: -180px;
84
+ width: a.rem(600);
85
+ height: a.rem(600);
86
+ }
87
+
88
+ @include a.bp(s) {
89
+ right: calc(50% - 300px);
90
+ }
91
+ }
92
+
93
+ .panel__image {
94
+ flex: 0 0 a.rem(360);
95
+ width: a.rem(360);
96
+ order: 2;
97
+
98
+ @include a.bp('2xl') {
99
+ flex: 0 0 a.rem(315);
100
+ width: a.rem(315);
101
+ }
102
+
103
+ @include a.bp(m) {
104
+ flex: 1 0 auto;
105
+ width: auto;
106
+ }
107
+ }
@@ -0,0 +1,48 @@
1
+ <script setup lang="ts">
2
+ import USpectro from '../../elements/spectro/u-spectro.vue'
3
+ import { Image } from '../../elements/types'
4
+ import { computed, useSlots } from 'vue'
5
+
6
+ interface Props {
7
+ title?: string
8
+ text?: string
9
+ useSpectro?: boolean
10
+ image?: Image
11
+ }
12
+
13
+ const { image = null } = defineProps<Props>()
14
+
15
+ const slots = useSlots()
16
+
17
+ const hasImage = computed(() => !!image || slots.image)
18
+ </script>
19
+
20
+ <template>
21
+ <aside :class="['panel', { 'has-image': hasImage }]">
22
+ <div v-if="useSpectro && !hasImage" class="panel__spectro">
23
+ <USpectro />
24
+ </div>
25
+
26
+ <div v-if="image" class="panel__image">
27
+ <slot name="image">
28
+ <img :src="image.src" :alt="image.alt" />
29
+ </slot>
30
+ </div>
31
+
32
+ <div class="panel__content">
33
+ <div class="panel__title">
34
+ <h2>
35
+ <slot name="title">{{ title }}</slot>
36
+ </h2>
37
+ </div>
38
+
39
+ <div class="panel__text">
40
+ <slot name="text"><div v-html="text"></div></slot>
41
+ </div>
42
+ </div>
43
+ </aside>
44
+ </template>
45
+
46
+ <style scoped lang="scss">
47
+ @use './panel.scss';
48
+ </style>
@@ -0,0 +1,37 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .progress-bar {
4
+ display: flex;
5
+ align-items: center;
6
+ column-gap: a.rem(4);
7
+ height: a.rem(10);
8
+ width: #{a.rem(64 + 4 + 10)}; // progress-track + space + icon
9
+
10
+ &.full-width {
11
+ width: 100%;
12
+
13
+ .progress-track {
14
+ width: calc(100% - #{a.rem(4 + 10)});
15
+ }
16
+ }
17
+ }
18
+
19
+ .progress-track {
20
+ width: a.rem(64);
21
+ min-width: a.rem(64);
22
+ height: a.rem(4);
23
+ background-color: var(--e-c-mono-100);
24
+ border-radius: a.rem(4);
25
+ overflow: hidden;
26
+ }
27
+
28
+ .progress-position {
29
+ height: 100%;
30
+ background-color: var(--e-c-primary-01-500);
31
+ }
32
+
33
+ .star-icon {
34
+ width: a.rem(10);
35
+ height: a.rem(10);
36
+ background-image: url("data:image/svg+xml,%3Csvg width='10' height='10' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%234BA528' d='M4.822 1.35a.2.2 0 0 1 .356 0l.975 1.909a.2.2 0 0 0 .147.107l2.117.336a.2.2 0 0 1 .11.34L7.012 5.557a.2.2 0 0 0-.056.173l.334 2.118a.2.2 0 0 1-.288.21L5.09 7.085a.2.2 0 0 0-.182 0L3 8.058a.2.2 0 0 1-.29-.209l.335-2.118a.2.2 0 0 0-.056-.173L1.473 4.041a.2.2 0 0 1 .11-.339L3.7 3.366a.2.2 0 0 0 .147-.107l.975-1.91Z'/%3E%3C/svg%3E");
37
+ }
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ interface Props {
3
+ value: number
4
+ fullWidth?: boolean
5
+ }
6
+
7
+ const { fullWidth = false } = defineProps<Props>()
8
+ </script>
9
+
10
+ <template>
11
+ <div :class="['progress-bar', { 'full-width': fullWidth }]">
12
+ <div class="progress-track">
13
+ <div class="progress-position" :style="{ width: `${value}%` }"></div>
14
+ </div>
15
+ <div v-if="value >= 100" class="star-icon"></div>
16
+ </div>
17
+ </template>
18
+
19
+ <style scoped lang="scss">
20
+ @use './progress-bar.scss';
21
+ </style>