From 6e5dd124b4f8c3ee1ba9e203b8c0718191c559de Mon Sep 17 00:00:00 2001 From: sendevia Date: Fri, 5 Dec 2025 22:56:33 +0800 Subject: [PATCH] add: MaterialCard component --- .vitepress/theme/components/Card.vue | 90 +++++++++ .vitepress/theme/index.ts | 3 + .vitepress/theme/styles/components/Card.scss | 187 +++++++++++++++++++ 3 files changed, 280 insertions(+) create mode 100644 .vitepress/theme/components/Card.vue create mode 100644 .vitepress/theme/styles/components/Card.scss diff --git a/.vitepress/theme/components/Card.vue b/.vitepress/theme/components/Card.vue new file mode 100644 index 0000000..2fd884e --- /dev/null +++ b/.vitepress/theme/components/Card.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/.vitepress/theme/index.ts b/.vitepress/theme/index.ts index b441d38..3bc7daf 100644 --- a/.vitepress/theme/index.ts +++ b/.vitepress/theme/index.ts @@ -4,6 +4,7 @@ import Layout from "./layouts/Default.vue"; import AppBar from "./components/AppBar.vue"; import Button from "./components/Button.vue"; +import Card from "./components/Card.vue"; import Footer from "./components/Footer.vue"; import Header from "./components/Header.vue"; import ImageViewer from "./components/ImageViewer.vue"; @@ -13,6 +14,7 @@ import ScrollToTop from "./components/ScrollToTop.vue"; import NavBar from "./components/NavBar.vue"; import "./styles/main.scss"; + const pinia = createPinia(); export default { @@ -26,6 +28,7 @@ export default { app.component("ImageViewer", ImageViewer); app.component("MainLayout", Layout); app.component("MaterialButton", Button); + app.component("MaterialCard", Card); app.component("NavBar", NavBar); app.component("PageIndicator", PageIndicator); app.component("PrevNext", PrevNext); diff --git a/.vitepress/theme/styles/components/Card.scss b/.vitepress/theme/styles/components/Card.scss new file mode 100644 index 0000000..d90e524 --- /dev/null +++ b/.vitepress/theme/styles/components/Card.scss @@ -0,0 +1,187 @@ +@use "../mixin"; + +.MaterialCard { + display: flex; + flex-direction: column; + + position: relative; + + text-decoration: none; + + overflow: hidden; + + .content { + display: flex; + flex-direction: column; + + position: relative; + + height: 100%; + width: 100%; + + .impression-area { + z-index: 1; + } + + .supporting-area { + color: var(--md-sys-color-on-surface); + + pointer-events: none; + + h3 { + transition: var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard); + } + } + } + + &.feed { + .content { + display: flex; + flex-direction: column; + gap: 12px; + + padding: 16px; + + .impression-area { + display: flex; + gap: 12px; + flex-direction: column; + + .title-container { + display: flex; + align-items: flex-start; + flex-direction: column; + gap: 12px; + + .title { + h4 { + font-variation-settings: "wdth" 500; + text-transform: uppercase; + } + } + } + + .image-container { + display: grid; + grid-template-columns: 100%; + gap: 6px; + + transition: grid-template-columns var(--md-sys-motion-spring-fast-spatial-duration) + var(--md-sys-motion-spring-fast-spatial); + + &:has(img:nth-child(2)) { + grid-template-columns: calc(90% - 6px) 10%; + } + + &.swapped, + &:hover { + &:has(img:nth-child(2)) { + grid-template-columns: 10% calc(90% - 6px); + } + } + + img { + height: 200px; + width: 100%; + + object-fit: cover; + transition: border-radius var(--md-sys-motion-spring-fast-spatial-duration) + var(--md-sys-motion-spring-fast-spatial); + + &:nth-child(1) { + border-radius: var(--md-sys-shape-corner-extra-large); + } + + &:nth-child(2) { + border-radius: var(--md-sys-shape-corner-medium); + } + } + + &.swapped:hover { + img:nth-child(1) { + border-radius: var(--md-sys-shape-corner-medium); + } + + img:nth-child(2) { + border-radius: var(--md-sys-shape-corner-extra-large); + } + } + } + } + + .supporting-area { + p { + letter-spacing: 0.6rem; + } + } + + .actions-area { + display: flex; + align-items: center; + flex-direction: row; + justify-content: space-between; + + p { + padding: 8px 12px; + + border-radius: var(--md-sys-shape-corner-medium); + } + + div { + display: flex; + flex-direction: row; + gap: 12px; + } + + a { + text-decoration: none; + } + } + } + } + + &::after { + content: ""; + + position: absolute; + top: 0; + left: 0; + + height: 100%; + width: 100%; + + z-index: 0; + } + + &:hover { + &::after { + background-color: var(--md-sys-state-hover-state-layer); + } + } + + &:focus-visible { + @include mixin.focus-ring($thickness: 3, $offset: 2); + } + + &.elevated { + color: var(--md-sys-color-primary); + + background-color: var(--md-sys-color-surface-container-low); + + box-shadow: 0px 1px 3px var(--md-sys-color-shadow); + } + + &.filled { + color: var(--md-sys-color-on-surface); + + border-radius: var(--md-sys-shape-corner-medium); + + background-color: var(--md-sys-color-surface-container-highest); + } + + &.outlined { + color: var(--md-sys-color-on-surface-variant); + + border-color: var(--md-sys-color-outline-variant); + } +}