kopia lustrzana https://github.com/shoelace-style/shoelace
				
				
				
			Add card component
							rodzic
							
								
									905152a412
								
							
						
					
					
						commit
						66c3de9c3b
					
				|  | @ -12,6 +12,7 @@ | |||
|   - [Avatar](/components/avatar.md) | ||||
|   - [Badge](/components/badge.md) | ||||
|   - [Button](/components/button.md) | ||||
|   - [Card](/components/card.md) | ||||
|   - [Checkbox](/components/checkbox.md) | ||||
|   - [Color Picker](/components/color-picker.md) | ||||
|   - [Details](/components/details.md) | ||||
|  |  | |||
|  | @ -0,0 +1,151 @@ | |||
| # Card | ||||
| 
 | ||||
| [component-header:sl-card] | ||||
| 
 | ||||
| Cards can be used to group related subjects in a container. | ||||
| 
 | ||||
| ```html preview | ||||
| <sl-card class="card-overview"> | ||||
|   <img  | ||||
|     slot="image"  | ||||
|     src="https://images.unsplash.com/photo-1559209172-0ff8f6d49ff7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80"  | ||||
|     alt="A kitten sits patiently between a terracotta pot and decorative grasses." | ||||
|   > | ||||
| 
 | ||||
|   <strong>Mittens</strong><br> | ||||
|   This kitten is as cute as he is playful. Bring him home today!<br> | ||||
|   <small>6 weeks old</small> | ||||
| 
 | ||||
|   <div slot="footer"> | ||||
|     <sl-button type="primary" pill>More Info</sl-button> | ||||
|     <sl-rating></sl-rating> | ||||
|   </div> | ||||
| </sl-card> | ||||
| 
 | ||||
| <style> | ||||
|   .card-overview { | ||||
|     max-width: 300px; | ||||
|   } | ||||
| 
 | ||||
|   .card-overview small { | ||||
|     color: var(--sl-color-gray-60); | ||||
|   } | ||||
| 
 | ||||
|   .card-overview [slot="footer"] { | ||||
|     display: flex;  | ||||
|     justify-content: space-between;  | ||||
|     align-items: center; | ||||
|   } | ||||
| </style> | ||||
| ``` | ||||
| 
 | ||||
| ## Examples | ||||
| 
 | ||||
| ## Basic Card | ||||
| 
 | ||||
| Basic cards aren't very exciting, but they can display any content you want them to. | ||||
| 
 | ||||
| ```html preview | ||||
| <sl-card class="card-basic"> | ||||
|   This is just a basic card. No image, no header, and no footer. Just your content. | ||||
| </sl-card> | ||||
| 
 | ||||
| <style> | ||||
|   .card-basic { | ||||
|     max-width: 300px; | ||||
|   } | ||||
| </style> | ||||
| ``` | ||||
| 
 | ||||
| ## Card with Header | ||||
| 
 | ||||
| Headers can be used to display titles and other card options. | ||||
| 
 | ||||
| ```html preview | ||||
| <sl-card class="card-header"> | ||||
|   <div slot="header"> | ||||
|     Header Title | ||||
| 
 | ||||
|     <sl-dropdown placement="bottom-end"> | ||||
|       <sl-button slot="trigger" type="text"> | ||||
|         <sl-icon slot="suffix" name="pencil"></sl-icon> | ||||
|         Edit | ||||
|       </sl-button> | ||||
|       <sl-menu> | ||||
|         <sl-menu-item>Rename</sl-menu-item> | ||||
|         <sl-menu-item>Duplicate</sl-menu-item> | ||||
|         <sl-menu-divider></sl-menu-divider> | ||||
|         <sl-menu-item>Delete</sl-menu-item> | ||||
|       </sl-menu> | ||||
|     </sl-dropdown> | ||||
|   </div> | ||||
| 
 | ||||
|   This card has a header. You can put all sorts of things in it! | ||||
| </sl-card> | ||||
| 
 | ||||
| <style> | ||||
| .card-header { | ||||
|   max-width: 300px; | ||||
| } | ||||
| 
 | ||||
| .card-header [slot="header"] { | ||||
|   display: flex;  | ||||
|   align-items: center;  | ||||
|   justify-content: space-between; | ||||
| } | ||||
| 
 | ||||
| .card-header h3 { | ||||
|   margin: 0; | ||||
| } | ||||
| </style> | ||||
| ``` | ||||
| 
 | ||||
| ## Card with Footer | ||||
| 
 | ||||
| Footers can be used to display actions, summaries, or other relevant content. | ||||
| 
 | ||||
| ```html preview | ||||
| <sl-card class="card-footer"> | ||||
|   This card has a footer. You can put all sorts of things in it! | ||||
| 
 | ||||
|   <div slot="footer"> | ||||
|     <sl-rating></sl-rating> | ||||
|     <sl-button slot="footer" type="primary">Preview</sl-button> | ||||
|   </div> | ||||
| </sl-card> | ||||
| 
 | ||||
| <style> | ||||
|   .card-footer { | ||||
|     max-width: 300px; | ||||
|   } | ||||
| 
 | ||||
|   .card-footer [slot="footer"] { | ||||
|     display: flex;  | ||||
|     justify-content: space-between;  | ||||
|     align-items: center; | ||||
|   } | ||||
| </style> | ||||
| ``` | ||||
| 
 | ||||
| ## Images | ||||
| 
 | ||||
| Cards accept an `image` slot. The image is displayed atop the card and stretches to fit. | ||||
| 
 | ||||
| ```html preview | ||||
| <sl-card class="card-image"> | ||||
|   <img  | ||||
|     slot="image"  | ||||
|     src="https://images.unsplash.com/photo-1547191783-94d5f8f6d8b1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=80"  | ||||
|     alt="A kitten walks towards camera on top of pallet." | ||||
|   > | ||||
|   This is a kitten, but not just any kitten. This kitten likes walking along pallets. | ||||
| </sl-card> | ||||
| 
 | ||||
| <style> | ||||
|   .card-image { | ||||
|     max-width: 300px; | ||||
|   } | ||||
| </style> | ||||
| ``` | ||||
| 
 | ||||
| [component-metadata:sl-card] | ||||
|  | @ -106,6 +106,8 @@ export namespace Components { | |||
|          */ | ||||
|         "value": string; | ||||
|     } | ||||
|     interface SlCard { | ||||
|     } | ||||
|     interface SlCheckbox { | ||||
|         /** | ||||
|           * Set to true to draw the checkbox in a checked state. | ||||
|  | @ -904,6 +906,12 @@ declare global { | |||
|         prototype: HTMLSlButtonElement; | ||||
|         new (): HTMLSlButtonElement; | ||||
|     }; | ||||
|     interface HTMLSlCardElement extends Components.SlCard, HTMLStencilElement { | ||||
|     } | ||||
|     var HTMLSlCardElement: { | ||||
|         prototype: HTMLSlCardElement; | ||||
|         new (): HTMLSlCardElement; | ||||
|     }; | ||||
|     interface HTMLSlCheckboxElement extends Components.SlCheckbox, HTMLStencilElement { | ||||
|     } | ||||
|     var HTMLSlCheckboxElement: { | ||||
|  | @ -1071,6 +1079,7 @@ declare global { | |||
|         "sl-avatar": HTMLSlAvatarElement; | ||||
|         "sl-badge": HTMLSlBadgeElement; | ||||
|         "sl-button": HTMLSlButtonElement; | ||||
|         "sl-card": HTMLSlCardElement; | ||||
|         "sl-checkbox": HTMLSlCheckboxElement; | ||||
|         "sl-color-picker": HTMLSlColorPickerElement; | ||||
|         "sl-details": HTMLSlDetailsElement; | ||||
|  | @ -1209,6 +1218,8 @@ declare namespace LocalJSX { | |||
|          */ | ||||
|         "value"?: string; | ||||
|     } | ||||
|     interface SlCard { | ||||
|     } | ||||
|     interface SlCheckbox { | ||||
|         /** | ||||
|           * Set to true to draw the checkbox in a checked state. | ||||
|  | @ -2074,6 +2085,7 @@ declare namespace LocalJSX { | |||
|         "sl-avatar": SlAvatar; | ||||
|         "sl-badge": SlBadge; | ||||
|         "sl-button": SlButton; | ||||
|         "sl-card": SlCard; | ||||
|         "sl-checkbox": SlCheckbox; | ||||
|         "sl-color-picker": SlColorPicker; | ||||
|         "sl-details": SlDetails; | ||||
|  | @ -2111,6 +2123,7 @@ declare module "@stencil/core" { | |||
|             "sl-avatar": LocalJSX.SlAvatar & JSXBase.HTMLAttributes<HTMLSlAvatarElement>; | ||||
|             "sl-badge": LocalJSX.SlBadge & JSXBase.HTMLAttributes<HTMLSlBadgeElement>; | ||||
|             "sl-button": LocalJSX.SlButton & JSXBase.HTMLAttributes<HTMLSlButtonElement>; | ||||
|             "sl-card": LocalJSX.SlCard & JSXBase.HTMLAttributes<HTMLSlCardElement>; | ||||
|             "sl-checkbox": LocalJSX.SlCheckbox & JSXBase.HTMLAttributes<HTMLSlCheckboxElement>; | ||||
|             "sl-color-picker": LocalJSX.SlColorPicker & JSXBase.HTMLAttributes<HTMLSlColorPickerElement>; | ||||
|             "sl-details": LocalJSX.SlDetails & JSXBase.HTMLAttributes<HTMLSlDetailsElement>; | ||||
|  |  | |||
|  | @ -0,0 +1,65 @@ | |||
| @import 'component'; | ||||
| 
 | ||||
| /** | ||||
|  * @prop --border-color: The card's border color, including borders that occur inside the card. | ||||
|  * @prop --border-radius: The border radius for card edges. | ||||
|  * @prop --border-width: The width of card borders. | ||||
|  * @prop --padding: The padding to use for card sections. | ||||
|  */ | ||||
| :host { | ||||
|   --border-color: var(--sl-color-gray-90); | ||||
|   --border-radius: var(--sl-border-radius-medium); | ||||
|   --border-width: 1px; | ||||
|   --padding: var(--sl-spacing-large); | ||||
| 
 | ||||
|   display: inline-block; | ||||
| } | ||||
| 
 | ||||
| .card { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   background-color: var(--sl-color-white); | ||||
|   box-shadow: var(--sl-shadow-x-small); | ||||
|   border: solid var(--border-width) var(--border-color); | ||||
|   border-radius: var(--border-radius); | ||||
| } | ||||
| 
 | ||||
| .card__image { | ||||
|   border-top-left-radius: calc(var(--border-radius) - var(--border-width)); | ||||
|   border-top-right-radius: calc(var(--border-radius) - var(--border-width)); | ||||
|   border-top-left-radius: var(--border-radius); | ||||
|   border-top-right-radius: var(--border-radius); | ||||
|   margin: calc(-1 * var(--border-width)); | ||||
|   overflow: hidden; | ||||
| 
 | ||||
|   ::slotted(img) { | ||||
|     display: block; | ||||
|     width: 100%; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .card:not(.card--has-image) .card__image { | ||||
|   display: none; | ||||
| } | ||||
| 
 | ||||
| .card__header { | ||||
|   border-bottom: solid var(--border-width) var(--border-color); | ||||
|   padding: calc(var(--padding) / 2) var(--padding); | ||||
| } | ||||
| 
 | ||||
| .card:not(.card--has-header) .card__header { | ||||
|   display: none; | ||||
| } | ||||
| 
 | ||||
| .card__body { | ||||
|   padding: var(--padding); | ||||
| } | ||||
| 
 | ||||
| .card--has-footer .card__footer { | ||||
|   border-top: solid var(--border-width) var(--border-color); | ||||
|   padding: var(--padding); | ||||
| } | ||||
| 
 | ||||
| .card:not(.card--has-footer) .card__footer { | ||||
|   display: none; | ||||
| } | ||||
|  | @ -0,0 +1,76 @@ | |||
| import { Component, Element, State, h } from '@stencil/core'; | ||||
| import { hasSlot } from '../../utilities/slot'; | ||||
| 
 | ||||
| /** | ||||
|  * @since 2.0 | ||||
|  * @status stable | ||||
|  * | ||||
|  * @slot - The card's body. | ||||
|  * @slot header - The card's header. | ||||
|  * @slot footer - The card's footer. | ||||
|  * @slot image - The card's image. | ||||
|  * | ||||
|  * @part base - The component's base wrapper. | ||||
|  * @part image - The card's image, if present. | ||||
|  * @part header - The card's header, if present. | ||||
|  * @part body - The card's body. | ||||
|  * @part footer - The card's footer, if present. | ||||
|  */ | ||||
| 
 | ||||
| @Component({ | ||||
|   tag: 'sl-card', | ||||
|   styleUrl: 'card.scss', | ||||
|   shadow: true | ||||
| }) | ||||
| export class Card { | ||||
|   @Element() host: HTMLSlCardElement; | ||||
| 
 | ||||
|   @State() hasFooter = false; | ||||
|   @State() hasImage = false; | ||||
|   @State() hasHeader = false; | ||||
| 
 | ||||
|   componentWillLoad() { | ||||
|     this.updateSlots(); | ||||
|     this.host.shadowRoot.addEventListener('slotchange', this.updateSlots); | ||||
|   } | ||||
| 
 | ||||
|   componentDidUnload() { | ||||
|     this.host.shadowRoot.removeEventListener('slotchange', this.updateSlots); | ||||
|   } | ||||
| 
 | ||||
|   updateSlots() { | ||||
|     this.hasFooter = hasSlot(this.host, 'footer'); | ||||
|     this.hasImage = hasSlot(this.host, 'image'); | ||||
|     this.hasHeader = hasSlot(this.host, 'header'); | ||||
|   } | ||||
| 
 | ||||
|   render() { | ||||
|     return ( | ||||
|       <div | ||||
|         part="base" | ||||
|         class={{ | ||||
|           card: true, | ||||
|           'card--has-footer': this.hasFooter, | ||||
|           'card--has-image': this.hasImage, | ||||
|           'card--has-header': this.hasHeader | ||||
|         }} | ||||
|       > | ||||
|         <div part="image" class="card__image"> | ||||
|           <slot name="image" /> | ||||
|         </div> | ||||
| 
 | ||||
|         <div part="header" class="card__header"> | ||||
|           <slot name="header" /> | ||||
|         </div> | ||||
| 
 | ||||
|         <div part="body" class="card__body"> | ||||
|           <slot /> | ||||
|         </div> | ||||
| 
 | ||||
|         <div part="footer" class="card__footer"> | ||||
|           <slot name="footer" /> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
		Ładowanie…
	
		Reference in New Issue
	
	 Cory LaViska
						Cory LaViska