Skip to content

Commit d823bf2

Browse files
committed
feat(card): Add card component
1 parent c837f0b commit d823bf2

File tree

9 files changed

+385
-3
lines changed

9 files changed

+385
-3
lines changed

src/components/card/card-header.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<ng-content select="[md-card-avatar]"></ng-content>
2+
<div class="md-card-header-text">
3+
<ng-content select="md-card-title, md-card-subtitle"></ng-content>
4+
</div>
5+
<ng-content></ng-content>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div>
2+
<ng-content select="md-card-title, md-card-subtitle"></ng-content>
3+
</div>
4+
<ng-content select="img"></ng-content>
5+
<ng-content></ng-content>

src/components/card/card.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div class="md-card">
2+
<ng-content></ng-content>
3+
</div>

src/components/card/card.scss

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
2+
@import "variables";
3+
@import "shadows";
4+
@import "default-theme"; // TODO: Remove this
5+
6+
$md-card-default-padding: 24px !default;
7+
$md-card-mobile-padding: 24px 16px !default;
8+
$md-card-border-radius: 2px !default;
9+
$md-card-header-size: 40px !default;
10+
11+
md-card {
12+
display: block;
13+
position: relative;
14+
padding: $md-card-default-padding;
15+
border-radius: $md-card-border-radius;
16+
box-shadow: $md-shadow-bottom-z-1;
17+
font-family: $font-family;
18+
background: md-color($md-background, 50); // TODO(kara): use updated background palette
19+
}
20+
21+
md-card:hover {
22+
box-shadow: $md-shadow-bottom-z-2;
23+
transition: $swift-ease-in;
24+
}
25+
26+
.md-card-flat {
27+
box-shadow: none;
28+
}
29+
30+
// base styles for each card section preset (md-card-content, etc)
31+
%md-card-section-base {
32+
display: block;
33+
margin-bottom: 16px;
34+
}
35+
36+
md-card-title {
37+
@extend %md-card-section-base;
38+
font-size: 24px;
39+
font-weight: 400;
40+
}
41+
42+
md-card-subtitle {
43+
@extend %md-card-section-base;
44+
font-size: $md-body-font-size-base;
45+
color: md-color($md-foreground, secondary-text);
46+
}
47+
48+
md-card-content {
49+
@extend %md-card-section-base;
50+
font-size: $md-body-font-size-base;
51+
}
52+
53+
md-card-actions {
54+
@extend %md-card-section-base;
55+
margin-left: -16px;
56+
margin-right: -16px;
57+
padding: 8px 0;
58+
}
59+
60+
[md-card-image] {
61+
width: calc(100% + 48px);
62+
margin: 0 -24px 16px -24px;
63+
}
64+
65+
[md-card-xl-image] {
66+
width: 240px;
67+
height: 240px;
68+
margin: -8px;
69+
}
70+
71+
md-card-footer {
72+
position: absolute;
73+
bottom: 0;
74+
}
75+
76+
md-card-actions {
77+
[md-button], [md-raised-button] {
78+
margin: 0 4px;
79+
}
80+
}
81+
82+
/* HEADER STYLES */
83+
84+
md-card-header {
85+
display: flex;
86+
flex-direction: row;
87+
height: $md-card-header-size;
88+
margin: -8px 0 16px 0;
89+
}
90+
91+
.md-card-header-text {
92+
height: $md-card-header-size;
93+
margin: 0 8px;
94+
}
95+
96+
[md-card-avatar] {
97+
height: $md-card-header-size;
98+
width: $md-card-header-size;
99+
border-radius: 50%;
100+
}
101+
102+
md-card-header md-card-title {
103+
font-size: $md-body-font-size-base;
104+
}
105+
106+
/* TITLE-GROUP STYLES */
107+
108+
// images grouped with title in title-group layout
109+
%md-card-title-img {
110+
margin: -8px 0;
111+
}
112+
113+
md-card-title-group {
114+
display: flex;
115+
justify-content: space-between;
116+
margin: 0 -8px;
117+
}
118+
119+
[md-card-sm-image] {
120+
@extend %md-card-title-img;
121+
width: 80px;
122+
height: 80px;
123+
}
124+
125+
[md-card-md-image] {
126+
@extend %md-card-title-img;
127+
width: 112px;
128+
height: 112px;
129+
}
130+
131+
[md-card-lg-image] {
132+
@extend %md-card-title-img;
133+
width: 152px;
134+
height: 152px;
135+
}
136+
137+
/* MEDIA QUERIES */
138+
139+
@media ($md-xsmall) {
140+
md-card {
141+
padding: $md-card-mobile-padding;
142+
}
143+
144+
[md-card-image] {
145+
width: calc(100% + 32px);
146+
margin: 16px -16px;
147+
}
148+
149+
md-card-title-group {
150+
margin: 0;
151+
}
152+
153+
[md-card-xl-image] {
154+
margin-left: 0;
155+
margin-right: 0;
156+
}
157+
158+
md-card-header {
159+
margin: -8px 0 0 0;
160+
}
161+
162+
}
163+
164+
/* FIRST/LAST CHILD ADJUSTMENTS */
165+
166+
// top els in md-card-content and md-card can't have their default margin-tops (e.g. <p> tags)
167+
// or they'll incorrectly add to card's top padding
168+
.md-card > :first-child, md-card-content > :first-child {
169+
margin-top: 0;
170+
}
171+
172+
// last els in md-card-content and md-card can't have their default margin-bottoms (e.g. <p> tags)
173+
// or they'll incorrectly add to card's bottom padding
174+
.md-card > :last-child, md-card-content > :last-child {
175+
margin-bottom: 0;
176+
}
177+
178+
// if main image is on top, need to place it flush against top
179+
// (by stripping card's default 24px padding)
180+
[md-card-image]:first-child {
181+
margin-top: -24px;
182+
}
183+
184+
// actions panel on bottom should be 8px from bottom of card
185+
// so must strip 16px from default card padding of 24px
186+
.md-card > md-card-actions:last-child {
187+
margin-bottom: -16px;
188+
padding-bottom: 0;
189+
}
190+
191+
// actions panel should always be 8px from sides,
192+
// so the first button in the actions panel can't add its own margins
193+
md-card-actions [md-button]:first-child,
194+
md-card-actions [md-raised-button]:first-child {
195+
margin-left: 0;
196+
margin-right: 0;
197+
}
198+
199+
// should be 12px space between titles and subtitles generally
200+
// default margin-bottom is 16px, so need to move lower title up 4px
201+
md-card-title:not(:first-child), md-card-subtitle:not(:first-child) {
202+
margin-top: -4px;
203+
}
204+
205+
// should be 8px space between titles and subtitles in header
206+
// default margin-bottom is 16px, so need to move subtitle in header up 4px
207+
md-card-header md-card-subtitle:not(:first-child) {
208+
margin-top: -8px;
209+
}
210+
211+
// xl image should always have 16px on top.
212+
// when it's the first el, it'll need to remove 8px from default card padding of 24px
213+
.md-card > [md-card-xl-image]:first-child{
214+
margin-top: -8px;
215+
}
216+
217+
// xl image should always have 16px on bottom
218+
// when it's the last el, it'll need to remove 8px from default card padding of 24px
219+
.md-card > [md-card-xl-image]:last-child {
220+
margin-bottom: -8px;
221+
}

src/components/card/card.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import {Component, View, ViewEncapsulation} from 'angular2/core';
2+
import {CONST_EXPR, Type} from 'angular2/src/facade/lang';
3+
4+
/*
5+
6+
<md-card> is a basic content container component that adds the styles of a material design card.
7+
8+
While you can use this component alone, it also provides a number of preset styles for common card sections, including:
9+
- md-card-title
10+
- md-card-subtitle
11+
- md-card-content
12+
- md-card-actions
13+
- md-card-footer
14+
15+
You can see some examples of cards here:
16+
http://embed.plnkr.co/s5O4YcyvbLhIApSrIhtj/
17+
18+
TODO(kara): update link to demo site when it exists
19+
20+
*/
21+
22+
@Component({
23+
selector: 'md-card',
24+
templateUrl: './components/card/card.html',
25+
styleUrls: ['./components/card/card.css'],
26+
encapsulation: ViewEncapsulation.None
27+
})
28+
export class MdCard {}
29+
30+
31+
/* The following components don't have any behavior. They simply use content projection to wrap user content
32+
for flex layout purposes in <md-card> (and thus allow a cleaner, boilerplate-free API).
33+
34+
35+
<md-card-header> is a component intended to be used within the <md-card> component.
36+
It adds styles for a preset header section (i.e. a title, subtitle, and avatar layout).
37+
38+
You can see an example of a card with a header here:
39+
http://embed.plnkr.co/tvJl19z3gZTQd6WmwkIa/
40+
41+
TODO(kara): update link to demo site when it exists
42+
*/
43+
44+
@Component({
45+
selector: 'md-card-header',
46+
templateUrl: '/components/card/card-header.html',
47+
encapsulation: ViewEncapsulation.None
48+
})
49+
export class MdCardHeader {}
50+
51+
/*
52+
53+
<md-card-title-group> is a component intended to be used within the <md-card> component.
54+
It adds styles for a preset layout that groups an image with a title section.
55+
56+
You can see an example of a card with a title-group section here:
57+
http://embed.plnkr.co/EDfgCF9eKcXjini1WODm/
58+
59+
TODO(kara): update link to demo site when it exists
60+
*/
61+
62+
@Component({
63+
selector: 'md-card-title-group',
64+
templateUrl: './components/card/card-title-group.html',
65+
encapsulation: ViewEncapsulation.None
66+
})
67+
export class MdCardTitleGroup {}
68+
69+
export const MD_CARD_DIRECTIVES: Type[] =
70+
CONST_EXPR([MdCard, MdCardHeader, MdCardTitleGroup]);
71+

src/core/style/_variables.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
// Typography
55
$md-body-font-size-base: rem(1.400) !default;
6+
$font-family: Roboto, 'Helvetica Neue', sans-serif !default;
7+
8+
// Media queries
9+
$md-xsmall: "max-width: 600px";
610

711
// z-index master list
812
$z-index-fab: 20 !default;

src/demo-app/demo-app.html

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
11
<p>
22
material2 Works!
3-
43
<button md-button>HELLO</button>
54
<button md-raised-button class="md-primary">HELLO</button>
65
<button md-fab class="md-accent">HI</button>
76
</p>
7+
<div class="card-container">
8+
9+
<md-card>
10+
<md-card-title-group>
11+
<md-card-title>Card with title</md-card-title>
12+
<md-card-subtitle>Subtitle</md-card-subtitle>
13+
<img md-card-md-image>
14+
</md-card-title-group>
15+
</md-card>
16+
17+
<md-card>
18+
<md-card-subtitle>Subtitle</md-card-subtitle>
19+
<md-card-title>Card with title</md-card-title>
20+
<md-card-content>
21+
<p>This is supporting text.</p>
22+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
23+
</md-card-content>
24+
<md-card-actions>
25+
<button md-button>LIKE</button>
26+
<button md-button>SHARE</button>
27+
</md-card-actions>
28+
</md-card>
29+
30+
<md-card>
31+
<img md-card-image src="https://material.angularjs.org/latest/img/washedout.png">
32+
<md-card-title>Content Title</md-card-title>
33+
<md-card-content>
34+
<p>Here is some content</p>
35+
</md-card-content>
36+
</md-card>
37+
38+
<md-card>
39+
<md-card-header>
40+
<img md-card-avatar>
41+
<md-card-title>Header title</md-card-title>
42+
<md-card-subtitle>Header subtitle</md-card-subtitle>
43+
</md-card-header>
44+
<img md-card-image src="https://material.angularjs.org/latest/img/washedout.png">
45+
<md-card-content>
46+
<p>Here is some content</p>
47+
</md-card-content>
48+
</md-card>
49+
50+
<md-card class="blue md-card-flat">
51+
<md-card-title>Easily customizable</md-card-title>
52+
<md-card-actions>
53+
<button md-button>First</button>
54+
<button md-button>Second</button>
55+
</md-card-actions>
56+
</md-card>
57+
</div>

0 commit comments

Comments
 (0)