@propelinc/citrus-ui 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@propelinc/citrus-ui",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/propelinc/citrus-ui"
@@ -14,7 +14,7 @@
14
14
  "lint:css": "stylelint \"src/**/*.(vue|less)\"",
15
15
  "lint:js": "vue-cli-service lint",
16
16
  "publish:dist": "npm run build:dist && npm publish",
17
- "publish:storybook": "storybook-to-aws-s3 --script=\"storybook:build\" --bucket-path=citrus-ui-storybook",
17
+ "publish:storybook": "storybook-to-aws-s3 --script=\"build:storybook\" --bucket-path=citrus-ui-storybook",
18
18
  "serve:storybook": "vue-cli-service storybook:serve -p 6006 -c .storybook",
19
19
  "test:unit": "vue-cli-service test:unit"
20
20
  },
@@ -1,9 +1,26 @@
1
1
  <template>
2
- <div class="card">
3
- <div v-if="title" data-test="card-title" class="card__title">{{ title }}</div>
2
+ <div class="card" :class="{ [color]: !!color }">
3
+ <div v-if="shouldShowHeader" class="card__header" :class="{ 'card__header--divided': divided }">
4
+ <div class="card__header__title-container">
5
+ <span data-test="card-title" class="card__header__title">
6
+ <slot name="header:title">
7
+ {{ title }}
8
+ </slot>
9
+ </span>
10
+ </div>
11
+
12
+ <div class="card__header__append">
13
+ <slot name="header:append" />
14
+ </div>
15
+ </div>
16
+
4
17
  <div data-test="card-body" class="card__body" :class="{ 'card__body--fluid': fluid }">
5
18
  <slot />
6
19
  </div>
20
+
21
+ <div class="card__footer" :class="{ 'card__footer--divided': divided }">
22
+ <slot name="footer" />
23
+ </div>
7
24
  </div>
8
25
  </template>
9
26
 
@@ -13,38 +30,88 @@ import { Component, Vue, Prop } from 'vue-property-decorator';
13
30
  @Component({ name: 'CCard' })
14
31
  export default class CCard extends Vue {
15
32
  @Prop(String) title?: string;
33
+ /** Removes padding from card body */
16
34
  @Prop({ type: Boolean, default: false }) fluid!: boolean;
35
+ /** Shows borders between header, body, and footer */
36
+ @Prop({ type: Boolean, default: false }) divided!: boolean;
37
+ /** Sets background color */
38
+ @Prop(String) color?: string;
39
+
40
+ get shouldShowHeader(): boolean {
41
+ return (
42
+ !!this.title ||
43
+ !!this.$slots['header:append'] ||
44
+ !!this.$scopedSlots['header:append'] ||
45
+ !!this.$slots['header:title'] ||
46
+ !!this.$scopedSlots['header:title']
47
+ );
48
+ }
17
49
  }
18
50
  </script>
19
51
 
20
52
  <style lang="less" scoped>
21
53
  @import '~@/styles/variables.less';
54
+ @import '~@/styles/mixins/buttons.less';
22
55
 
23
56
  .card {
24
57
  background: @color-white;
25
58
  border: @border;
26
59
  border-radius: @border-radius;
60
+ overflow: hidden;
27
61
 
28
62
  & + & {
29
63
  margin-top: 12px;
30
64
  }
31
65
  }
32
66
 
33
- .card__title {
34
- .overline;
67
+ .card__header {
68
+ align-items: flex-start;
69
+ display: flex;
70
+ padding: @card-header-v-spacing @card-h-spacing 0;
71
+ }
35
72
 
36
- padding: 12px 16px 0;
73
+ .card__header__title-container {
74
+ flex: 1 1 100%;
37
75
  }
38
76
 
39
- .card__body {
40
- padding: 16px 16px 12px;
77
+ .card__header__title {
78
+ .title();
41
79
 
42
- .card__title + & {
43
- padding-top: 8px;
44
- }
80
+ vertical-align: -4px;
81
+ word-break: break-word;
82
+ }
83
+
84
+ .card__header__append:not(:empty) {
85
+ flex: none;
86
+ margin: -6px -12px -8px @card-h-spacing;
87
+ }
88
+
89
+ .card__header--divided {
90
+ border-bottom: @border;
91
+ padding-bottom: @card-header-v-spacing;
92
+ }
93
+
94
+ .card__body {
95
+ padding: @card-body-v-spacing @card-h-spacing;
45
96
  }
46
97
 
47
98
  .card__body--fluid {
48
99
  padding: 0;
49
100
  }
101
+
102
+ .card__footer {
103
+ .button-container();
104
+
105
+ &:not(:empty) {
106
+ margin-top: -1 * @card-body-v-spacing;
107
+ padding: 0 @card-h-spacing;
108
+ }
109
+ }
110
+
111
+ .card__footer--divided {
112
+ &:not(:empty) {
113
+ border-top: @border;
114
+ margin-top: 0;
115
+ }
116
+ }
50
117
  </style>
@@ -0,0 +1,102 @@
1
+ <template>
2
+ <v-dialog
3
+ :width="loading ? '160' : undefined"
4
+ :persistent="!dismissible || !!loading"
5
+ no-click-animation
6
+ :value="value"
7
+ @input="(value) => $emit('input', value)"
8
+ >
9
+ <c-card v-if="loading" key="loading" data-test="modal-loading">
10
+ <div class="modal__loading">
11
+ <div class="modal__loading__icon-container">
12
+ <font-awesome-icon :icon="faSync" class="fa-spin modal__loading__icon" />
13
+ </div>
14
+
15
+ <div
16
+ v-if="hasLoadingMessage"
17
+ data-test="modal-loading-message"
18
+ class="modal__loading__message"
19
+ >
20
+ {{ loading }}
21
+ </div>
22
+ </div>
23
+ </c-card>
24
+ <c-card v-else key="default" data-test="modal">
25
+ <template #header:title>
26
+ <span class="modal__header__title" data-test="modal-title">{{ title }}</span>
27
+ </template>
28
+
29
+ <template #header:append>
30
+ <c-icon-button
31
+ v-if="dismissible"
32
+ data-test="modal-dismiss"
33
+ :icon="faTimes"
34
+ @click="$emit('input', false)"
35
+ />
36
+ </template>
37
+
38
+ <slot />
39
+
40
+ <template #footer>
41
+ <slot name="footer" />
42
+ </template>
43
+ </c-card>
44
+ </v-dialog>
45
+ </template>
46
+
47
+ <script lang="ts">
48
+ import { faSync, faTimes } from '@fortawesome/pro-light-svg-icons';
49
+ import { Component, Vue, Prop } from 'vue-property-decorator';
50
+
51
+ import CCard from '@/components/CCard.vue';
52
+ import CIconButton from '@/components/CIconButton.vue';
53
+
54
+ @Component({ name: 'CModal', components: { CCard, CIconButton } })
55
+ export default class CModal extends Vue {
56
+ faSync = faSync;
57
+ faTimes = faTimes;
58
+
59
+ @Prop({ type: Boolean, default: false }) value!: boolean;
60
+ @Prop(String) title?: string;
61
+ /** Shows loading state + sets loading message if string */
62
+ @Prop([String, Boolean]) loading?: string | boolean;
63
+ /** Allows modal to be dismissed */
64
+ @Prop({ type: Boolean, default: true }) dismissible!: boolean;
65
+
66
+ get hasLoadingMessage(): boolean {
67
+ return typeof this.loading === 'string';
68
+ }
69
+ }
70
+ </script>
71
+
72
+ <style lang="less" scoped>
73
+ @import '~@/styles/variables.less';
74
+
75
+ .modal__header__title {
76
+ .subheadline();
77
+
78
+ vertical-align: -4px;
79
+ }
80
+
81
+ .modal__loading {
82
+ text-align: center;
83
+ }
84
+
85
+ .modal__loading__icon-container {
86
+ padding: 12px 0;
87
+ }
88
+
89
+ .modal__loading__icon {
90
+ color: @color-accent-blue;
91
+ font-size: @font-size-2x-large;
92
+ }
93
+
94
+ .modal__loading__message {
95
+ font-weight: @font-weight-bold;
96
+ }
97
+
98
+ /deep/ .card__footer:not(:empty) {
99
+ margin-top: -12px;
100
+ padding-bottom: 4px;
101
+ }
102
+ </style>
@@ -1,54 +1,16 @@
1
1
  <template>
2
- <v-dialog
3
- data-test="modal-loading"
4
- width="160"
5
- persistent
6
- no-click-animation
7
- :value="value"
8
- @input="(value) => $emit('input', value)"
9
- >
10
- <v-card class="modal-loading__content">
11
- <font-awesome-icon :icon="faSync" class="fa-spin modal-loading__icon" />
12
-
13
- <div data-test="modal-loading-message" class="modal-loading__content__message">
14
- <slot>
15
- {{ message }}
16
- </slot>
17
- </div>
18
- </v-card>
19
- </v-dialog>
2
+ <c-modal :loading="message || true" :value="value" @input="(value) => $emit('input', value)" />
20
3
  </template>
21
4
 
22
5
  <script lang="ts">
23
- import { faSync } from '@fortawesome/pro-light-svg-icons';
24
6
  import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
25
7
  import { Component, Vue, Prop } from 'vue-property-decorator';
26
8
 
27
- @Component({ name: 'CModalLoading', components: { FontAwesomeIcon } })
28
- export default class CModalLoading extends Vue {
29
- faSync = faSync;
9
+ import CModal from '@/components/CModal.vue';
30
10
 
11
+ @Component({ name: 'CModalLoading', components: { FontAwesomeIcon, CModal } })
12
+ export default class CModalLoading extends Vue {
31
13
  @Prop({ type: Boolean, default: false }) value!: boolean;
32
14
  @Prop({ type: String }) message?: string;
33
15
  }
34
16
  </script>
35
-
36
- <style lang="less" scoped>
37
- @import '~@/styles/variables.less';
38
-
39
- .modal-loading__icon {
40
- color: @color-accent-blue;
41
- font-size: @font-size-2x-large;
42
- }
43
-
44
- .modal-loading__content {
45
- border-radius: @border-radius !important; // Override Vuetify styles
46
- padding: 28px 16px 20px;
47
- text-align: center;
48
- }
49
-
50
- .modal-loading__content__message {
51
- font-weight: @font-weight-bold;
52
- margin: 12px 0 0;
53
- }
54
- </style>
@@ -0,0 +1,22 @@
1
+ .button-container() {
2
+ align-items: stretch;
3
+ display: flex;
4
+ flex-direction: column;
5
+
6
+ & /deep/ .button--primary,
7
+ & /deep/ .button--secondary {
8
+ margin-top: 12px;
9
+
10
+ &:last-child {
11
+ margin-bottom: 12px;
12
+ }
13
+ }
14
+
15
+ & /deep/ .button--tertiary {
16
+ margin-top: 8px;
17
+
18
+ &:last-child {
19
+ margin-bottom: 8px;
20
+ }
21
+ }
22
+ }
@@ -98,6 +98,11 @@
98
98
  text-transform: uppercase;
99
99
  }
100
100
 
101
+ // CARDS
102
+ @card-body-v-spacing: 16px;
103
+ @card-h-spacing: 16px;
104
+ @card-header-v-spacing: 12px;
105
+
101
106
  // SKELETON LOADER
102
107
  @skeleton-loader-animation-duration: 3s;
103
108
  @skeleton-loader-animation: skeleton-loader-animation @skeleton-loader-animation-duration infinite;