Skip to content

Commit 0f18653

Browse files
authored
Merge pull request #7413 from nextcloud-libraries/backport/7398/stable8
[stable8] feat(NcAssistant*): provide components to for consistant integrations design
2 parents 696388a + d956c46 commit 0f18653

File tree

8 files changed

+407
-0
lines changed

8 files changed

+407
-0
lines changed
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<docs>
7+
```vue
8+
<template>
9+
<div class="wrapper">
10+
<!-- Style selector -->
11+
<div class="grid grid-3">
12+
<NcCheckboxRadioSwitch v-model="style" value="icon" name="style" type="radio">Icon only</NcCheckboxRadioSwitch>
13+
<NcCheckboxRadioSwitch v-model="style" value="icontext" name="style" type="radio">Icon and text</NcCheckboxRadioSwitch>
14+
<NcCheckboxRadioSwitch v-model="disabled" type="checkbox">Disabled</NcCheckboxRadioSwitch>
15+
</div>
16+
17+
<h5>Standard buttons</h5>
18+
<div class="grid">
19+
<p>Secondary</p>
20+
<p>Primary</p>
21+
<NcAssistantButton
22+
aria-label="Generate content"
23+
:disabled="disabled"
24+
:text="text">
25+
</NcAssistantButton>
26+
<NcAssistantButton
27+
aria-label="Generate content"
28+
:disabled="disabled"
29+
:text="text"
30+
variant="primary">
31+
</NcAssistantButton>
32+
</div>
33+
</div>
34+
35+
</template>
36+
<script>
37+
import Video from 'vue-material-design-icons/Video.vue'
38+
39+
export default {
40+
components: {
41+
Video,
42+
},
43+
data() {
44+
return {
45+
disabled: false,
46+
style: 'icontext',
47+
}
48+
},
49+
computed: {
50+
text() {
51+
if (this.style.includes('text')) {
52+
return 'Generate content'
53+
}
54+
},
55+
},
56+
}
57+
</script>
58+
59+
<style lang="scss" scoped>
60+
.wrapper {
61+
padding: 0 12px;
62+
}
63+
64+
.grid {
65+
display: grid;
66+
gap: 12px;
67+
grid-template-columns: 1fr 1fr;
68+
grid-template-rows: repeat(auto-fill, auto);
69+
justify-items: center;
70+
position: relative;
71+
margin: 12px 0;
72+
}
73+
74+
.grid-3 {
75+
grid-template-columns: 1fr 1fr 1fr;
76+
}
77+
78+
h5 {
79+
font-weight: bold;
80+
margin: 40px 0 20px 0;
81+
}
82+
83+
p {
84+
text-align: center;
85+
margin: 4px 0 12px 0;
86+
color: var(--color-text-maxcontrast)
87+
}
88+
89+
button {
90+
margin: auto;
91+
}
92+
</style>
93+
```
94+
</docs>
95+
96+
<script setup>
97+
import { mdiCreation } from '@mdi/js'
98+
import NcAssistantIcon from '../NcAssistantIcon/NcAssistantIcon.vue'
99+
import NcButton from '../NcButton/NcButton.vue'
100+
import NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'
101+
102+
defineProps({
103+
/**
104+
* Toggles the disabled state of the button on and off.
105+
*/
106+
disabled: {
107+
type: Boolean,
108+
default: false,
109+
},
110+
111+
/**
112+
* The readable text of the button.
113+
* Can be overriden by using the `default` slot.
114+
*
115+
* If neither this is set nor the `default` slot is used, you will have to set at least `aria-label` or `aria-labelledby`.
116+
*/
117+
text: {
118+
type: String,
119+
default: '',
120+
},
121+
122+
/**
123+
* The button variant.
124+
* In most cases the `secondary` style should be used.
125+
*/
126+
variant: {
127+
type: String,
128+
default: 'secondary',
129+
},
130+
})
131+
132+
defineEmits([
133+
/**
134+
* The mouse click event when the button is triggered.
135+
*/
136+
'click',
137+
])
138+
</script>
139+
140+
<template>
141+
<div :class="[{
142+
[$style.assistantButton_disabled]: disabled,
143+
[$style.assistantButton_primary]: variant === 'primary',
144+
}, $style.assistantButton]">
145+
<NcButton :class="$style.assistantButton__button"
146+
:disabled="disabled"
147+
variant="tertiary"
148+
@click="$emit('click', $event)">
149+
<template #icon>
150+
<NcIconSvgWrapper v-if="variant === 'primary'"
151+
:class="$style.assistantButton__icon"
152+
:path="mdiCreation" />
153+
<NcAssistantIcon v-else />
154+
</template>
155+
<template v-if="text || $scopedSlots.default" #default>
156+
<div :class="$style.assistantButton__text">
157+
<slot>{{ text }}</slot>
158+
</div>
159+
</template>
160+
</NcButton>
161+
</div>
162+
</template>
163+
164+
<style module lang="scss">
165+
.assistantButton {
166+
--assistant-button-color: var(--color-element-assistant, linear-gradient(238deg, #A569D3 12%, #00679E 39%, #422083 86%));
167+
--assistant-button-background-color: var(--color-background-assistant, #F6F5FF);
168+
background-image: var(--color-border-assistant, linear-gradient(125deg, #7398FE 50%, #6104A4 125%));
169+
border-radius: var(--border-radius-element);
170+
height: var(--default-clickable-area);
171+
width: fit-content;
172+
padding-inline: 1px;
173+
padding-block: 1px 2px;
174+
175+
&_disabled {
176+
filter: saturate(0.5);
177+
opacity: 0.5;
178+
}
179+
180+
&_primary {
181+
--assistant-button-color: white;
182+
--assistant-button-background-color: var(--color-element-assistant,linear-gradient(238deg, #A569D3 12%, #00679E 39%, #422083 86%));
183+
184+
.assistantButton__icon,
185+
.assistantButton__text {
186+
color: white !important;
187+
}
188+
}
189+
190+
&__button {
191+
--button-size: calc(var(--default-clickable-area) - 3px) !important;
192+
background-color: var(--assistant-button-background-color) !important;
193+
background-image: var(--assistant-button-background-color) !important;
194+
border: none !important;
195+
196+
&:hover {
197+
filter: brightness(120%);
198+
}
199+
}
200+
201+
&__text {
202+
background-image: var(--assistant-button-color);
203+
color: transparent !important;
204+
background-clip: text;
205+
}
206+
}
207+
</style>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
export { default } from './NcAssistantButton.vue'
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<docs>
7+
```vue
8+
<template>
9+
<NcAssistantContent>
10+
<div class="container">
11+
<NcAssistantIcon />
12+
<div class="content">
13+
<h3 class="heading">
14+
Summary of the last 123 messages
15+
</h3>
16+
<p>
17+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
18+
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
19+
no sea takimata sanctus est Lorem ipsum dolor sit amet.
20+
</p>
21+
</div>
22+
</div>
23+
</NcAssistantContent>
24+
</template>
25+
26+
<style scoped>
27+
.container {
28+
display: flex;
29+
align-items: start;
30+
flex-direction: row;
31+
}
32+
33+
.content {
34+
display: flex;
35+
flex-direction: column;
36+
}
37+
38+
.heading {
39+
margin-top: 0;
40+
font-size: var(--default-font-size);
41+
}
42+
</style>
43+
```
44+
</docs>
45+
46+
<script setup>
47+
48+
defineProps({
49+
/**
50+
* Classes to assign to the content container
51+
*/
52+
contentClasses: {
53+
type: [String, Array, Object],
54+
default: '',
55+
},
56+
})
57+
</script>
58+
59+
<template>
60+
<div :class="$style.assistantContent">
61+
<div :class="[$style.assistantContent__inner, contentClasses]">
62+
<!-- @slot The content to be shown. -->
63+
<slot />
64+
</div>
65+
</div>
66+
</template>
67+
68+
<style module lang="scss">
69+
.assistantContent {
70+
background-image: var(--color-border-assistant, linear-gradient(125deg, #7398FE 50%, #6104A4 125%));
71+
border-radius: var(--border-radius-container);
72+
padding: 2px;
73+
74+
&__inner {
75+
background-color: var(--color-background-assistant, #F6F5FF);
76+
border-radius: calc(var(--border-radius-container) - 1px);
77+
color: var(--color-main-text);
78+
padding: calc(var(--border-radius-container) - 1px);
79+
80+
height: 100%;
81+
width: 100%;
82+
}
83+
}
84+
</style>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
export { default } from './NcAssistantContent.vue'
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<docs>
7+
```vue
8+
<template>
9+
<NcAssistantIcon />
10+
</template>
11+
```
12+
13+
### Usage as inline icon
14+
```vue
15+
<template>
16+
<p>
17+
Lorem ipsum dolor sit amet <NcAssistantIcon inline /> consetetur sadipscing elitr.
18+
</p>
19+
</template>
20+
```
21+
</docs>
22+
23+
<script setup>
24+
import { mdiCreation } from '@mdi/js'
25+
import { computed } from 'vue'
26+
27+
const props = defineProps({
28+
/**
29+
* Set if the icon should be used as inline content e.g. within text.
30+
* By default the icon is made a block element for use inside `icon`-slots.
31+
*/
32+
inline: {
33+
type: Boolean,
34+
default: false,
35+
},
36+
37+
/**
38+
* Size of the icon.
39+
* Defaults to the proper size to be used in buttons and other interactive elements
40+
* like all `Nc*` components with an icon slot.
41+
*/
42+
size: {
43+
type: Number,
44+
default: 20,
45+
},
46+
})
47+
48+
const sizePx = computed(() => `${props.size}px`)
49+
</script>
50+
51+
<template>
52+
<span aria-hidden="true"
53+
:class="[$style.assistantIcon, inline && $style.assistantIcon_inline]"
54+
role="img">
55+
<svg :class="$style.assistantIcon__svg" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
56+
<defs>
57+
<linearGradient id="AssistantGradient" gradientTransform="rotateX(285)">
58+
<stop offset="15%" stop-color="#9669D3" />
59+
<stop offset="40%" stop-color="#00679E" />
60+
<stop offset="80%" stop-color="#492083" />
61+
</linearGradient>
62+
</defs>
63+
<path :d="mdiCreation" fill="url('#AssistantGradient')" />
64+
</svg>
65+
</span>
66+
</template>
67+
68+
<style module lang="scss">
69+
.assistantIcon {
70+
display: inline-flex;
71+
align-items: center;
72+
justify-content: center;
73+
74+
&:not(&_inline) {
75+
display: flex;
76+
min-height: var(--default-clickable-area);
77+
min-width: var(--default-clickable-area);
78+
}
79+
80+
&__svg {
81+
display: inline-block;
82+
width: v-bind('sizePx');
83+
height: v-bind('sizePx');
84+
max-width: v-bind('sizePx');
85+
max-height: v-bind('sizePx');
86+
}
87+
}
88+
</style>

0 commit comments

Comments
 (0)