forked from github/quartz
feat(bases): migrate from vault to upstream
Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
This commit is contained in:
218
quartz/components/BaseViewSelector.tsx
Normal file
218
quartz/components/BaseViewSelector.tsx
Normal file
@@ -0,0 +1,218 @@
|
||||
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
||||
import { classNames } from "../util/lang"
|
||||
import { resolveRelative } from "../util/path"
|
||||
// @ts-ignore
|
||||
import script from "./scripts/base-view-selector.inline"
|
||||
import baseViewSelectorStyle from "./styles/baseViewSelector.scss"
|
||||
|
||||
const icons = {
|
||||
table: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" />
|
||||
<path d="M3 9h18" />
|
||||
<path d="M3 15h18" />
|
||||
<path d="M9 3v18" />
|
||||
<path d="M15 3v18" />
|
||||
</svg>
|
||||
),
|
||||
list: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="8" x2="21" y1="6" y2="6" />
|
||||
<line x1="8" x2="21" y1="12" y2="12" />
|
||||
<line x1="8" x2="21" y1="18" y2="18" />
|
||||
<line x1="3" x2="3.01" y1="6" y2="6" />
|
||||
<line x1="3" x2="3.01" y1="12" y2="12" />
|
||||
<line x1="3" x2="3.01" y1="18" y2="18" />
|
||||
</svg>
|
||||
),
|
||||
chevronsUpDown: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="m7 15 5 5 5-5" />
|
||||
<path d="m7 9 5-5 5 5" />
|
||||
</svg>
|
||||
),
|
||||
chevronRight: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="m9 18 6-6-6-6" />
|
||||
</svg>
|
||||
),
|
||||
x: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M18 6 6 18" />
|
||||
<path d="m6 6 12 12" />
|
||||
</svg>
|
||||
),
|
||||
map: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
|
||||
</svg>
|
||||
),
|
||||
card: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect width="7" height="7" x="3" y="3" rx="1" />
|
||||
<rect width="7" height="7" x="14" y="3" rx="1" />
|
||||
<rect width="7" height="7" x="14" y="14" rx="1" />
|
||||
<rect width="7" height="7" x="3" y="14" rx="1" />
|
||||
</svg>
|
||||
),
|
||||
}
|
||||
|
||||
const viewTypeIcons: Record<string, JSX.Element> = {
|
||||
table: icons.table,
|
||||
list: icons.list,
|
||||
gallery: icons.card,
|
||||
board: icons.table,
|
||||
calendar: icons.table,
|
||||
map: icons.map,
|
||||
cards: icons.card,
|
||||
}
|
||||
|
||||
const BaseViewSelector: QuartzComponent = ({ fileData, displayClass }: QuartzComponentProps) => {
|
||||
const baseMeta = fileData.basesMetadata
|
||||
|
||||
if (!baseMeta || baseMeta.allViews.length <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
const currentViewName = baseMeta.currentView
|
||||
const allViews = baseMeta.allViews
|
||||
const currentIcon =
|
||||
viewTypeIcons[allViews.find((view) => view.name === currentViewName)?.type ?? ""] ??
|
||||
icons.table
|
||||
|
||||
return (
|
||||
<div class={classNames(displayClass, "bases-toolbar")} data-base-view-selector>
|
||||
<div class="bases-toolbar-item bases-toolbar-views-menu">
|
||||
<span
|
||||
class="text-icon-button"
|
||||
aria-label="Select view"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
role="button"
|
||||
tabindex={0}
|
||||
>
|
||||
<span class="text-button-icon">{currentIcon}</span>
|
||||
<span class="text-button-label">{currentViewName.toLowerCase()}</span>
|
||||
<span class="text-button-icon mod-aux">{icons.chevronsUpDown}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="menu-scroll" data-dropdown>
|
||||
<div class="bases-toolbar-menu-container">
|
||||
<div class="search-input-container">
|
||||
<input type="search" placeholder="Search..." data-search-input />
|
||||
<div class="search-input-clear-button" data-clear-search hidden>
|
||||
{icons.x}
|
||||
</div>
|
||||
</div>
|
||||
<div class="bases-toolbar-items">
|
||||
<div class="suggestion-group" data-group="views" data-view-list>
|
||||
{allViews.map((view) => {
|
||||
const isActive = view.name === currentViewName
|
||||
const icon = viewTypeIcons[view.type] || icons.table
|
||||
const href = resolveRelative(fileData.slug!, view.slug)
|
||||
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
data-slug={view.slug}
|
||||
class={
|
||||
isActive
|
||||
? "suggestion-item bases-toolbar-menu-item mod-active is-selected"
|
||||
: "suggestion-item bases-toolbar-menu-item"
|
||||
}
|
||||
data-view-name={view.name}
|
||||
data-view-type={view.type}
|
||||
>
|
||||
<div class="bases-toolbar-menu-item-info">
|
||||
<div class="bases-toolbar-menu-item-info-icon">{icon}</div>
|
||||
<div class="bases-toolbar-menu-item-name">{view.name.toLowerCase()}</div>
|
||||
</div>
|
||||
<div class="clickable-icon bases-toolbar-menu-item-icon">
|
||||
{icons.chevronRight}
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
BaseViewSelector.css = baseViewSelectorStyle
|
||||
BaseViewSelector.afterDOMLoaded = script
|
||||
|
||||
export default (() => BaseViewSelector) satisfies QuartzComponentConstructor
|
||||
@@ -51,7 +51,9 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
|
||||
ctx,
|
||||
}: QuartzComponentProps) => {
|
||||
const trie = (ctx.trie ??= trieFromAllFiles(allFiles))
|
||||
const slugParts = fileData.slug!.split("/")
|
||||
const baseMeta = fileData.basesMetadata
|
||||
|
||||
const slugParts = (baseMeta ? baseMeta.baseSlug : fileData.slug!).split("/")
|
||||
const pathNodes = trie.ancestryChain(slugParts)
|
||||
|
||||
if (!pathNodes) {
|
||||
@@ -64,14 +66,24 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
|
||||
crumb.displayName = options.rootName
|
||||
}
|
||||
|
||||
// For last node (current page), set empty path
|
||||
if (idx === pathNodes.length - 1) {
|
||||
crumb.path = ""
|
||||
if (baseMeta) {
|
||||
crumb.path = resolveRelative(fileData.slug!, simplifySlug(baseMeta.baseSlug))
|
||||
} else {
|
||||
crumb.path = ""
|
||||
}
|
||||
}
|
||||
|
||||
return crumb
|
||||
})
|
||||
|
||||
if (baseMeta && options.showCurrentPage) {
|
||||
crumbs.push({
|
||||
displayName: baseMeta.currentView.replaceAll("-", " "),
|
||||
path: "",
|
||||
})
|
||||
}
|
||||
|
||||
if (!options.showCurrentPage) {
|
||||
crumbs.pop()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import Content from "./pages/Content"
|
||||
import TagContent from "./pages/TagContent"
|
||||
import FolderContent from "./pages/FolderContent"
|
||||
import BaseContent from "./pages/BaseContent"
|
||||
import BaseViewSelector from "./BaseViewSelector"
|
||||
import NotFound from "./pages/404"
|
||||
import ArticleTitle from "./ArticleTitle"
|
||||
import Darkmode from "./Darkmode"
|
||||
@@ -29,6 +31,8 @@ export {
|
||||
Content,
|
||||
TagContent,
|
||||
FolderContent,
|
||||
BaseContent,
|
||||
BaseViewSelector,
|
||||
Darkmode,
|
||||
ReaderMode,
|
||||
Head,
|
||||
|
||||
22
quartz/components/pages/BaseContent.tsx
Normal file
22
quartz/components/pages/BaseContent.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "../types"
|
||||
import style from "../styles/basePage.scss"
|
||||
import { htmlToJsx } from "../../util/jsx"
|
||||
|
||||
export default (() => {
|
||||
const BaseContent: QuartzComponent = (props: QuartzComponentProps) => {
|
||||
const { fileData, tree } = props
|
||||
|
||||
return (
|
||||
<div class="popover-hint">
|
||||
<article
|
||||
class={["base-content", ...(fileData.frontmatter?.cssclasses ?? [])].join(" ")}
|
||||
>
|
||||
{htmlToJsx(fileData.filePath!, fileData.basesRenderedTree ?? tree)}
|
||||
</article>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
BaseContent.css = style
|
||||
return BaseContent
|
||||
}) satisfies QuartzComponentConstructor
|
||||
139
quartz/components/scripts/base-view-selector.inline.ts
Normal file
139
quartz/components/scripts/base-view-selector.inline.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
let documentClickHandler: ((e: MouseEvent) => void) | null = null
|
||||
|
||||
function setupBaseViewSelector() {
|
||||
const selectors = document.querySelectorAll("[data-base-view-selector]")
|
||||
|
||||
if (selectors.length === 0) return
|
||||
|
||||
if (!documentClickHandler) {
|
||||
documentClickHandler = (e: MouseEvent) => {
|
||||
document.querySelectorAll("[data-base-view-selector]").forEach((selector) => {
|
||||
if (selector.contains(e.target as Node)) return
|
||||
const trigger = selector.querySelector(".text-icon-button") as HTMLElement | null
|
||||
if (trigger?.getAttribute("aria-expanded") === "true") {
|
||||
selector.dispatchEvent(new CustomEvent("close-dropdown"))
|
||||
}
|
||||
})
|
||||
}
|
||||
document.addEventListener("click", documentClickHandler)
|
||||
window.addCleanup(() => {
|
||||
if (documentClickHandler) {
|
||||
document.removeEventListener("click", documentClickHandler)
|
||||
documentClickHandler = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
selectors.forEach((selector) => {
|
||||
if (selector.hasAttribute("data-initialized")) return
|
||||
selector.setAttribute("data-initialized", "true")
|
||||
|
||||
const trigger = selector.querySelector(".text-icon-button") as HTMLElement | null
|
||||
const searchInput = selector.querySelector("[data-search-input]") as HTMLInputElement | null
|
||||
const clearButton = selector.querySelector("[data-clear-search]") as HTMLElement | null
|
||||
const viewList = selector.querySelector("[data-view-list]") as HTMLElement | null
|
||||
|
||||
if (!trigger || !searchInput || !clearButton || !viewList) return
|
||||
|
||||
function toggleDropdown() {
|
||||
if (trigger.getAttribute("aria-expanded") === "true") {
|
||||
closeDropdown()
|
||||
return
|
||||
}
|
||||
openDropdown()
|
||||
}
|
||||
|
||||
function openDropdown() {
|
||||
trigger.setAttribute("aria-expanded", "true")
|
||||
trigger.classList.add("has-active-menu")
|
||||
setTimeout(() => searchInput.focus(), 10)
|
||||
}
|
||||
|
||||
function closeDropdown() {
|
||||
trigger.setAttribute("aria-expanded", "false")
|
||||
trigger.classList.remove("has-active-menu")
|
||||
searchInput.value = ""
|
||||
clearButton.hidden = true
|
||||
filterViews("")
|
||||
}
|
||||
|
||||
function filterViews(query: string) {
|
||||
const items = viewList.querySelectorAll<HTMLElement>(".bases-toolbar-menu-item")
|
||||
const lowerQuery = query.toLowerCase()
|
||||
|
||||
items.forEach((item) => {
|
||||
const viewName = (item.getAttribute("data-view-name") || "").toLowerCase()
|
||||
const viewType = (item.getAttribute("data-view-type") || "").toLowerCase()
|
||||
const matches = viewName.includes(lowerQuery) || viewType.includes(lowerQuery)
|
||||
item.style.display = matches ? "" : "none"
|
||||
})
|
||||
}
|
||||
|
||||
function handleSearchInput() {
|
||||
const query = searchInput.value
|
||||
filterViews(query)
|
||||
clearButton.hidden = query.length === 0
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
searchInput.value = ""
|
||||
clearButton.hidden = true
|
||||
filterViews("")
|
||||
searchInput.focus()
|
||||
}
|
||||
|
||||
const handleTriggerClick = (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
toggleDropdown()
|
||||
}
|
||||
|
||||
const handleTriggerKeydown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault()
|
||||
toggleDropdown()
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearchKeydown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
if (searchInput.value) {
|
||||
clearSearch()
|
||||
} else {
|
||||
closeDropdown()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleClearClick = (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
clearSearch()
|
||||
}
|
||||
|
||||
trigger.addEventListener("click", handleTriggerClick)
|
||||
trigger.addEventListener("keydown", handleTriggerKeydown)
|
||||
searchInput.addEventListener("input", handleSearchInput)
|
||||
searchInput.addEventListener("keydown", handleSearchKeydown)
|
||||
clearButton.addEventListener("click", handleClearClick)
|
||||
|
||||
const viewLinks = viewList.querySelectorAll(".bases-toolbar-menu-item")
|
||||
viewLinks.forEach((link) => {
|
||||
link.addEventListener("click", closeDropdown)
|
||||
window.addCleanup(() => link.removeEventListener("click", closeDropdown))
|
||||
})
|
||||
|
||||
selector.addEventListener("close-dropdown", closeDropdown)
|
||||
|
||||
window.addCleanup(() => {
|
||||
trigger.removeEventListener("click", handleTriggerClick)
|
||||
trigger.removeEventListener("keydown", handleTriggerKeydown)
|
||||
searchInput.removeEventListener("input", handleSearchInput)
|
||||
searchInput.removeEventListener("keydown", handleSearchKeydown)
|
||||
clearButton.removeEventListener("click", handleClearClick)
|
||||
selector.removeEventListener("close-dropdown", closeDropdown)
|
||||
selector.removeAttribute("data-initialized")
|
||||
closeDropdown()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
document.addEventListener("nav", setupBaseViewSelector)
|
||||
299
quartz/components/styles/basePage.scss
Normal file
299
quartz/components/styles/basePage.scss
Normal file
@@ -0,0 +1,299 @@
|
||||
.base-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.base-view {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.base-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.875rem;
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 0.5rem 0.75rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--lightgray);
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 600;
|
||||
color: var(--darkgray);
|
||||
background: var(--light);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background: var(--light);
|
||||
}
|
||||
|
||||
a.internal {
|
||||
color: var(--secondary);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.base-group-header td {
|
||||
font-weight: 600;
|
||||
background: var(--light);
|
||||
color: var(--dark);
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.base-summary-row {
|
||||
background: var(--light);
|
||||
font-weight: 500;
|
||||
|
||||
.base-summary-cell {
|
||||
border-top: 2px solid var(--lightgray);
|
||||
color: var(--darkgray);
|
||||
}
|
||||
}
|
||||
|
||||
.base-checkbox {
|
||||
pointer-events: none;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
accent-color: var(--secondary);
|
||||
}
|
||||
|
||||
.base-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
padding: 0.375rem 0;
|
||||
border-bottom: 1px solid var(--lightgray);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
a.internal {
|
||||
color: var(--secondary);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.base-list-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.base-list-group {
|
||||
.base-list-group-header {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--dark);
|
||||
}
|
||||
}
|
||||
|
||||
.base-list-nested {
|
||||
list-style: none;
|
||||
padding-left: 1rem;
|
||||
margin-top: 0.25rem;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--darkgray);
|
||||
}
|
||||
|
||||
.base-list-meta-label {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.base-card-grid {
|
||||
--base-card-min: 200px;
|
||||
--base-card-aspect: 1.4;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(var(--base-card-min), 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.base-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.base-card-group {
|
||||
.base-card-group-header {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--dark);
|
||||
}
|
||||
}
|
||||
|
||||
.base-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid var(--lightgray);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: var(--light);
|
||||
transition: box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.base-card-image-link {
|
||||
display: block;
|
||||
aspect-ratio: var(--base-card-aspect);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.base-card-content {
|
||||
padding: 0.75rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.base-card-title-link {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
|
||||
&:hover .base-card-title {
|
||||
color: var(--secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.base-card-title {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.base-card-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--darkgray);
|
||||
}
|
||||
|
||||
.base-card-meta-item {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.base-card-meta-label {
|
||||
font-weight: 500;
|
||||
|
||||
&::after {
|
||||
content: ":";
|
||||
}
|
||||
}
|
||||
|
||||
.base-calendar-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.base-calendar-group {
|
||||
.base-calendar-group-header {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--dark);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
|
||||
.base-map {
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
background: var(--light);
|
||||
border: 1px solid var(--lightgray);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--darkgray);
|
||||
|
||||
&::before {
|
||||
content: "Map view requires client-side JavaScript";
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.base-diagnostics {
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffc107;
|
||||
border-radius: 4px;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.base-diagnostics-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.base-diagnostics-meta {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.base-diagnostics-page {
|
||||
font-family: var(--codeFont);
|
||||
}
|
||||
|
||||
.base-diagnostics-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.base-diagnostics-item {
|
||||
background: white;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.base-diagnostics-label {
|
||||
font-weight: 500;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.base-diagnostics-message {
|
||||
color: #664d03;
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.base-diagnostics-source {
|
||||
display: block;
|
||||
font-size: 0.8125rem;
|
||||
color: #6c757d;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
273
quartz/components/styles/baseViewSelector.scss
Normal file
273
quartz/components/styles/baseViewSelector.scss
Normal file
@@ -0,0 +1,273 @@
|
||||
@use "../../styles/variables.scss" as *;
|
||||
|
||||
.bases-toolbar {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 1rem 0;
|
||||
font-family: var(--bodyFont);
|
||||
|
||||
.bases-toolbar-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
&.bases-toolbar-views-menu {
|
||||
.text-icon-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
background: var(--light);
|
||||
border: 1px solid var(--lightgray);
|
||||
border-radius: 6px;
|
||||
color: var(--darkgray);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background: var(--highlight);
|
||||
border-color: var(--gray);
|
||||
}
|
||||
|
||||
&.has-active-menu {
|
||||
border-color: var(--secondary);
|
||||
background: var(--highlight);
|
||||
}
|
||||
|
||||
.text-button-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--gray);
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
&.mod-aux {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.text-button-label {
|
||||
font-size: 0.875rem;
|
||||
color: var(--dark);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-scroll {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.5rem);
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
max-height: 400px;
|
||||
background: var(--light);
|
||||
border: 1px solid var(--lightgray);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
overflow: hidden;
|
||||
min-width: 280px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:has(.text-icon-button.has-active-menu) .menu-scroll {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bases-toolbar-menu-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 400px;
|
||||
|
||||
.search-input-container {
|
||||
position: relative;
|
||||
padding: 0.5rem;
|
||||
border-bottom: 1px solid var(--lightgray);
|
||||
|
||||
input[type="search"] {
|
||||
width: 100%;
|
||||
padding: 0.375rem 0.75rem;
|
||||
padding-right: 2rem;
|
||||
background: var(--light);
|
||||
border: 1px solid var(--secondary);
|
||||
border-radius: 6px;
|
||||
font-size: 0.875rem;
|
||||
color: var(--dark);
|
||||
outline: none;
|
||||
transition: box-shadow 0.15s ease;
|
||||
font-family: var(--bodyFont);
|
||||
|
||||
&::placeholder {
|
||||
color: var(--gray);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2px var(--highlight);
|
||||
}
|
||||
|
||||
&::-webkit-search-cancel-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.search-input-clear-button {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.15s ease;
|
||||
color: var(--gray);
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bases-toolbar-items {
|
||||
overflow-y: auto;
|
||||
max-height: 340px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--lightgray);
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: var(--gray);
|
||||
}
|
||||
}
|
||||
|
||||
.suggestion-group {
|
||||
&[data-group="views"] {
|
||||
padding: 0.25rem 0;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
}
|
||||
|
||||
.suggestion-item {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
|
||||
&.bases-toolbar-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 0.75rem;
|
||||
margin: 0 0.25rem;
|
||||
border-radius: 4px;
|
||||
transition: background 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: var(--lightgray);
|
||||
}
|
||||
|
||||
&.mod-active {
|
||||
font-weight: $semiBoldWeight;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
.bases-toolbar-menu-item-info {
|
||||
.bases-toolbar-menu-item-name {
|
||||
font-weight: 600;
|
||||
color: var(--secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bases-toolbar-menu-item-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex: 1;
|
||||
|
||||
.bases-toolbar-menu-item-info-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--gray);
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.bases-toolbar-menu-item-name {
|
||||
font-size: 0.875rem;
|
||||
color: var(--dark);
|
||||
}
|
||||
}
|
||||
|
||||
.clickable-icon.bases-toolbar-menu-item-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease;
|
||||
color: var(--gray);
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .clickable-icon.bases-toolbar-menu-item-icon {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media all and ($mobile) {
|
||||
.bases-toolbar {
|
||||
.menu-scroll {
|
||||
min-width: 240px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user