timmy ha revisionato questo gist 10 months ago. Vai alla revisione
Nessuna modifica
timmy ha revisionato questo gist 10 months ago. Vai alla revisione
Nessuna modifica
timmy ha revisionato questo gist 1 year ago. Vai alla revisione
1 file changed, 229 insertions
timeline_example.html(file creato)
| @@ -0,0 +1,229 @@ | |||
| 1 | + | <!doctype html> | |
| 2 | + | <html lang="zh-Hant"> | |
| 3 | + | <head> | |
| 4 | + | <meta charset="UTF-8" /> | |
| 5 | + | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| 6 | + | <title>年份時間軸 - Lit 元素</title> | |
| 7 | + | <style> | |
| 8 | + | body { | |
| 9 | + | font-family: "Microsoft JhengHei", Arial, sans-serif; | |
| 10 | + | background-color: #f0f0f0; | |
| 11 | + | padding: 20px; | |
| 12 | + | margin: 0; | |
| 13 | + | } | |
| 14 | + | </style> | |
| 15 | + | </head> | |
| 16 | + | <body> | |
| 17 | + | <timeline-element></timeline-element> | |
| 18 | + | ||
| 19 | + | <script type="module"> | |
| 20 | + | import { | |
| 21 | + | html, | |
| 22 | + | css, | |
| 23 | + | LitElement, | |
| 24 | + | } from "https://unpkg.com/lit@2.8.0?module"; | |
| 25 | + | ||
| 26 | + | class TimelineElement extends LitElement { | |
| 27 | + | static styles = css` | |
| 28 | + | :host { | |
| 29 | + | --timeline-width: 4px; | |
| 30 | + | --timeline-color: #ddd; | |
| 31 | + | --event-bg-color: #fff; | |
| 32 | + | --event-shadow: 0 3px 10px rgba(0, 0, 0, 0.1); | |
| 33 | + | --event-hover-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); | |
| 34 | + | --dot-size: 16px; | |
| 35 | + | --dot-border-color: #4caf50; | |
| 36 | + | --dot-bg-color: #fff; | |
| 37 | + | --dot-hover-bg-color: #4caf50; | |
| 38 | + | ||
| 39 | + | display: block; | |
| 40 | + | max-width: 800px; | |
| 41 | + | margin: 0 auto; | |
| 42 | + | position: relative; | |
| 43 | + | } | |
| 44 | + | .timeline { | |
| 45 | + | display: flex; | |
| 46 | + | flex-direction: column; | |
| 47 | + | position: relative; | |
| 48 | + | } | |
| 49 | + | .timeline::before { | |
| 50 | + | content: ""; | |
| 51 | + | position: absolute; | |
| 52 | + | top: 0; | |
| 53 | + | left: 50%; | |
| 54 | + | width: var(--timeline-width); | |
| 55 | + | height: 100%; | |
| 56 | + | background-color: var(--timeline-color); | |
| 57 | + | transform: translateX(-50%); | |
| 58 | + | } | |
| 59 | + | @media (max-width: 768px) { | |
| 60 | + | .timeline::before { | |
| 61 | + | left: 30px; | |
| 62 | + | } | |
| 63 | + | } | |
| 64 | + | `; | |
| 65 | + | ||
| 66 | + | render() { | |
| 67 | + | return html` | |
| 68 | + | <div class="timeline" role="list"> | |
| 69 | + | ${this.events.map( | |
| 70 | + | (event, index) => html` | |
| 71 | + | <event-element | |
| 72 | + | .title=${event.title} | |
| 73 | + | .description=${event.description} | |
| 74 | + | ?is-odd=${index % 2 === 0} | |
| 75 | + | role="listitem" | |
| 76 | + | ></event-element> | |
| 77 | + | `, | |
| 78 | + | )} | |
| 79 | + | </div> | |
| 80 | + | `; | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | static properties = { | |
| 84 | + | events: { type: Array }, | |
| 85 | + | }; | |
| 86 | + | ||
| 87 | + | constructor() { | |
| 88 | + | super(); | |
| 89 | + | this.events = [ | |
| 90 | + | { title: "1989", description: "這是 1989 年的事件。" }, | |
| 91 | + | { title: "1995", description: "這是 1995 年的重要事件。" }, | |
| 92 | + | { title: "2001", description: "2001 年的事件發生了顯著影響。" }, | |
| 93 | + | { title: "2010", description: "2010 年的事件標誌著新的時代開始。" }, | |
| 94 | + | ]; | |
| 95 | + | } | |
| 96 | + | } | |
| 97 | + | ||
| 98 | + | class EventElement extends LitElement { | |
| 99 | + | static styles = css` | |
| 100 | + | :host { | |
| 101 | + | display: flex; | |
| 102 | + | width: 100%; | |
| 103 | + | margin: 20px 0; | |
| 104 | + | position: relative; | |
| 105 | + | justify-content: flex-end; | |
| 106 | + | } | |
| 107 | + | :host([is-odd]) { | |
| 108 | + | justify-content: flex-start; | |
| 109 | + | } | |
| 110 | + | .event-content { | |
| 111 | + | width: 40%; | |
| 112 | + | padding: 15px; | |
| 113 | + | background-color: var(--event-bg-color); | |
| 114 | + | border-radius: 10px; | |
| 115 | + | box-shadow: var(--event-shadow); | |
| 116 | + | position: relative; | |
| 117 | + | transition: all 0.3s ease; | |
| 118 | + | } | |
| 119 | + | :host([is-odd]) .event-content { | |
| 120 | + | margin-right: 1%; | |
| 121 | + | } | |
| 122 | + | :host(:not([is-odd])) .event-content { | |
| 123 | + | margin-left: 1%; | |
| 124 | + | } | |
| 125 | + | .event-content:hover { | |
| 126 | + | transform: translateY(-5px); | |
| 127 | + | box-shadow: var(--event-hover-shadow); | |
| 128 | + | } | |
| 129 | + | .event-content::before { | |
| 130 | + | content: ""; | |
| 131 | + | position: absolute; | |
| 132 | + | top: 20px; | |
| 133 | + | width: 0; | |
| 134 | + | height: 0; | |
| 135 | + | border-style: solid; | |
| 136 | + | transition: all 0.3s ease; | |
| 137 | + | } | |
| 138 | + | :host([is-odd]) .event-content::before { | |
| 139 | + | right: -10px; | |
| 140 | + | border-width: 10px 0 10px 10px; | |
| 141 | + | border-color: transparent transparent transparent var(--event-bg-color); | |
| 142 | + | } | |
| 143 | + | :host(:not([is-odd])) .event-content::before { | |
| 144 | + | left: -10px; | |
| 145 | + | border-width: 10px 10px 10px 0; | |
| 146 | + | border-color: transparent var(--event-bg-color) transparent transparent; | |
| 147 | + | } | |
| 148 | + | .event-content:hover::before { | |
| 149 | + | border-color: transparent transparent transparent #f8f8f8; | |
| 150 | + | } | |
| 151 | + | :host(:not([is-odd])) .event-content:hover::before { | |
| 152 | + | border-color: transparent #f8f8f8 transparent transparent; | |
| 153 | + | } | |
| 154 | + | h3 { | |
| 155 | + | margin-top: 0; | |
| 156 | + | color: #333; | |
| 157 | + | } | |
| 158 | + | :host::after { | |
| 159 | + | content: ""; | |
| 160 | + | position: absolute; | |
| 161 | + | top: 20px; | |
| 162 | + | width: var(--dot-size); | |
| 163 | + | height: var(--dot-size); | |
| 164 | + | background-color: var(--dot-bg-color); | |
| 165 | + | border: 4px solid var(--dot-border-color); | |
| 166 | + | border-radius: 50%; | |
| 167 | + | left: 50%; | |
| 168 | + | transform: translateX(-50%); | |
| 169 | + | transition: all 0.3s ease; | |
| 170 | + | } | |
| 171 | + | :host(:hover)::after { | |
| 172 | + | background-color: var(--dot-hover-bg-color); | |
| 173 | + | } | |
| 174 | + | @media (max-width: 768px) { | |
| 175 | + | :host, | |
| 176 | + | :host([is-odd]) { | |
| 177 | + | justify-content: flex-start; | |
| 178 | + | } | |
| 179 | + | .event-content { | |
| 180 | + | width: calc(100% - 60px); | |
| 181 | + | margin-left: 60px !important; | |
| 182 | + | margin-right: 0 !important; | |
| 183 | + | } | |
| 184 | + | :host::after { | |
| 185 | + | left: 30px; | |
| 186 | + | } | |
| 187 | + | .event-content::before { | |
| 188 | + | left: -10px !important; | |
| 189 | + | border-width: 10px 10px 10px 0 !important; | |
| 190 | + | border-color: transparent var(--event-bg-color) transparent transparent !important; | |
| 191 | + | } | |
| 192 | + | .event-content:hover::before { | |
| 193 | + | border-color: transparent #f8f8f8 transparent transparent !important; | |
| 194 | + | } | |
| 195 | + | } | |
| 196 | + | `; | |
| 197 | + | ||
| 198 | + | static properties = { | |
| 199 | + | title: { type: String }, | |
| 200 | + | description: { type: String }, | |
| 201 | + | isOdd: { type: Boolean, reflect: true, attribute: "is-odd" }, | |
| 202 | + | }; | |
| 203 | + | ||
| 204 | + | render() { | |
| 205 | + | return html` | |
| 206 | + | <div class="event-content" tabindex="0" @click=${this._handleClick}> | |
| 207 | + | <h3>${this.title}</h3> | |
| 208 | + | <p>${this.description}</p> | |
| 209 | + | </div> | |
| 210 | + | `; | |
| 211 | + | } | |
| 212 | + | ||
| 213 | + | _handleClick() { | |
| 214 | + | this.dispatchEvent(new CustomEvent('event-click', { | |
| 215 | + | bubbles: true, | |
| 216 | + | composed: true, | |
| 217 | + | detail: { | |
| 218 | + | title: this.title, | |
| 219 | + | description: this.description | |
| 220 | + | } | |
| 221 | + | })); | |
| 222 | + | } | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | customElements.define("timeline-element", TimelineElement); | |
| 226 | + | customElements.define("event-element", EventElement); | |
| 227 | + | </script> | |
| 228 | + | </body> | |
| 229 | + | </html> | |