Skip to content

Commit 9885991

Browse files
committed
Auto merge of #1897 - DSpeckhals:search-result-page-copy, r=carols10cents
Add Cargo.toml copy button to crate rows To copy the most recent version of a crate to the clipboard, users would have to go to the crate's individual page. However, it would probably be convenient to have the same control on the search results page. To accomplish this, a new component was created to encapsulate the copy control and its notifications (success/failure). This new component was added to the search result page; the crate page was reworked to use it as well. For this first run at the UI, I added the same copy button to the left of the name/link for the result. I'm open to any other ideas too! Here are some screenshots to illustrate the changes: ### Crate Page ![Screenshot from 2019-11-14 12-33-09](https://user-images.githubusercontent.com/3310769/68895522-74884d80-06f7-11ea-9fa4-befbf5f44329.png) ![Screenshot from 2019-11-14 12-32-03](https://user-images.githubusercontent.com/3310769/68895511-6d613f80-06f7-11ea-9d2a-ecdf031325d5.png) ### Results Page ![Screenshot from 2019-11-14 14-24-57](https://user-images.githubusercontent.com/3310769/68895552-836f0000-06f7-11ea-820c-137f772cb2ab.png) Fixes #1587
2 parents 7f03d34 + f24e3b3 commit 9885991

File tree

7 files changed

+130
-61
lines changed

7 files changed

+130
-61
lines changed

app/components/crate-row.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import Component from '@ember/component';
2+
import { computed } from '@ember/object';
23

34
export default Component.extend({
45
classNames: ['crate', 'row'],
6+
crateTomlText: computed('crate.name', 'max_version', function() {
7+
return `${this.get('crate.name')} = "${this.get('crate.max_version')}"`;
8+
}),
59

610
'data-test-crate-row': true,
711
});

app/components/crate-toml-copy.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Component from '@ember/component';
2+
import { later } from '@ember/runloop';
3+
4+
export default Component.extend({
5+
classNames: ['crate-toml-copy'],
6+
copyText: '',
7+
showSuccess: false,
8+
showNotification: false,
9+
toggleClipboardProps(isSuccess) {
10+
this.setProperties({
11+
showSuccess: isSuccess,
12+
showNotification: true,
13+
});
14+
later(
15+
this,
16+
() => {
17+
this.set('showNotification', false);
18+
},
19+
2000,
20+
);
21+
},
22+
actions: {
23+
copySuccess(event) {
24+
event.clearSelection();
25+
this.toggleClipboardProps(true);
26+
},
27+
28+
copyError() {
29+
this.toggleClipboardProps(false);
30+
},
31+
},
32+
});

app/controllers/crate/version.js

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import Controller from '@ember/controller';
44
import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
55
import ArrayProxy from '@ember/array/proxy';
66
import { computed, observer } from '@ember/object';
7-
import { later } from '@ember/runloop';
87
import moment from 'moment';
98

109
const NUM_VERSIONS = 5;
@@ -25,6 +24,9 @@ export default Controller.extend({
2524
fetchingFollowing: true,
2625
following: false,
2726
currentVersion: alias('model'),
27+
crateTomlText: computed('crate.name', 'currentVersion.num', function() {
28+
return `${this.get('crate.name')} = "${this.get('currentVersion.num')}"`;
29+
}),
2830
requestedVersion: null,
2931
keywords: alias('crate.keywords'),
3032
categories: alias('crate.categories'),
@@ -152,30 +154,7 @@ export default Controller.extend({
152154
return data;
153155
}),
154156

155-
toggleClipboardProps(isSuccess) {
156-
this.setProperties({
157-
showSuccess: isSuccess,
158-
showNotification: true,
159-
});
160-
later(
161-
this,
162-
() => {
163-
this.set('showNotification', false);
164-
},
165-
2000,
166-
);
167-
},
168-
169157
actions: {
170-
copySuccess(event) {
171-
event.clearSelection();
172-
this.toggleClipboardProps(true);
173-
},
174-
175-
copyError() {
176-
this.toggleClipboardProps(false);
177-
},
178-
179158
toggleFollow() {
180159
this.set('fetchingFollowing', true);
181160

app/styles/crate.scss

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,28 @@
8888
}
8989
}
9090

91+
.crate-toml-copy {
92+
button, button:active {
93+
background-color: #FFFFFF;
94+
border: none;
95+
cursor: pointer;
96+
position: relative;
97+
}
98+
99+
.copy-notification {
100+
font-size: 70%;
101+
font-weight: bold;
102+
position: absolute;
103+
104+
&.copy-success {
105+
color: $link-color;
106+
}
107+
&.copy-failure {
108+
color: red;
109+
}
110+
}
111+
}
112+
91113
#results {
92114
width: 100%;
93115
@include display-flex;
@@ -132,6 +154,35 @@
132154
width: 75%;
133155
}
134156

157+
.crate-toml-copy {
158+
display: inline-block;
159+
160+
button, button:active {
161+
padding: 0 .2rem;
162+
outline: 0;
163+
164+
&:hover {
165+
background: inherit;
166+
}
167+
168+
svg {
169+
height: 1rem;
170+
width: 1rem;
171+
}
172+
173+
.copy-notification {
174+
top: -1.25rem;
175+
left: 0;
176+
padding: 0;
177+
text-align: left;
178+
width: 4rem;
179+
180+
&.copy-failure {
181+
width: 15rem;
182+
}
183+
}
184+
}
185+
}
135186
.info a {
136187
color: $main-color;
137188
font-weight: bold;
@@ -300,33 +351,36 @@
300351
color: white;
301352
padding: 20px;
302353
}
303-
button, button:active {
304-
padding: 5px 0;
305-
background-color: #FFFFFF;
306-
border: none;
307-
width: 60px;
308-
cursor: pointer;
309-
}
310-
button:hover {
311-
background: #edebdd;
312-
}
313354
@media only screen and (min-width: 500px) {
314355
.action { @include flex(2); display: block; }
315356
code { @include flex(8); }
316357
}
317-
}
318-
.copy-result {
319-
text-align: right;
358+
.crate-toml-copy {
359+
display: flex;
320360

321-
span {
322-
font-size: 80%;
323-
font-weight: bold;
324-
}
325-
.copy-success {
326-
color: $link-color;
327-
}
328-
.copy-failure {
329-
color: red;
361+
button, button:active {
362+
padding: 5px 0;
363+
width: 60px;
364+
cursor: pointer;
365+
position: relative;
366+
}
367+
button:hover {
368+
background: #edebdd;
369+
}
370+
371+
.copy-notification {
372+
&.copy-success {
373+
width: 100%;
374+
text-align: center;
375+
}
376+
377+
&.copy-failure {
378+
bottom: -2rem;
379+
right: 0;
380+
width: 18rem;
381+
text-align: right;
382+
}
383+
}
330384
}
331385
}
332386
.crate-readme {

app/templates/components/crate-row.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<div class='desc'>
22
<div class='info'>
33
{{#link-to 'crate' crate.id data-test-crate-link}}{{ crate.name }}{{/link-to}}
4+
{{crate-toml-copy copyText=crateTomlText}}
45
{{crate-badge crate=crate}}
56
{{#each crate.annotated_badges as |badge|}}
67
{{component badge.component_name badge=badge data-test-badge=badge.badge_type}}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{{#copy-button clipboardText=copyText success=(action 'copySuccess') error=(action 'copyError') title="Copy Cargo.toml snippet to clipboard"}}
2+
{{svg-jar "copy" alt="Copy Cargo.toml snippet to clipboard"}}
3+
<div class="copy-notification {{if showSuccess "copy-success" "copy-failure"}}">
4+
{{#if showNotification}}
5+
{{#if showSuccess}}
6+
Copied!
7+
{{else}}
8+
An error occured. Please use CTRL+C.
9+
{{/if}}
10+
{{/if}}
11+
</div>
12+
{{/copy-button}}

app/templates/crate/version.hbs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,24 +65,11 @@
6565
{{else}}
6666
<div class='install'>
6767
<div class='action'>Cargo.toml</div>
68-
<code id="crate-toml">{{ crate.name }} = "{{ currentVersion.num }}"</code>
68+
<code id="crate-toml">{{ crateTomlText }}</code>
6969
{{#if (is-clipboard-supported)}}
70-
{{#copy-button clipboardTarget="#crate-toml" success=(action 'copySuccess') error=(action 'copyError') title="Copy to clipboard"}}
71-
{{svg-jar "copy" alt="Copy to clipboard"}}
72-
{{/copy-button}}
70+
{{crate-toml-copy copyText=crateTomlText}}
7371
{{/if}}
7472
</div>
75-
<div class="copy-result">
76-
<span id="copy-notification" class="{{if showSuccess "copy-success" "copy-failure"}}">
77-
{{#if showNotification}}
78-
{{#if showSuccess}}
79-
Copied!
80-
{{else}}
81-
An error occured. Please use CTRL+C.
82-
{{/if}}
83-
{{/if}}
84-
</span>
85-
</div>
8673
{{#if crate.readme}}
8774
<section class="crate-readme" aria-label="Readme">
8875
{{crate-readme rendered=crate.readme}}

0 commit comments

Comments
 (0)