v0.1.40 홈 피드 및 문서 버전 정리
Made-with: Cursor
This commit is contained in:
@@ -118,6 +118,11 @@ menu {
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.sidebar--left {
|
||||
overflow: hidden;
|
||||
transition: opacity 0.24s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.24s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.sidebar--right {
|
||||
border-right: 0;
|
||||
border-left: 1px solid var(--border);
|
||||
@@ -131,13 +136,24 @@ menu {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sidebar--left .sidebar__inner {
|
||||
transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.24s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
body.left-sidebar-collapsed .site-shell {
|
||||
width: calc(var(--content-column) + var(--sidebar-right));
|
||||
grid-template-columns: minmax(0, var(--content-column)) var(--sidebar-right);
|
||||
grid-template-columns: 0 minmax(0, var(--content-column)) var(--sidebar-right);
|
||||
}
|
||||
|
||||
body.left-sidebar-collapsed .sidebar--left {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
body.left-sidebar-collapsed .sidebar--left .sidebar__inner {
|
||||
opacity: 0;
|
||||
transform: translateX(-14px);
|
||||
}
|
||||
|
||||
.sidebar__inner--right {
|
||||
@@ -247,7 +263,6 @@ body.left-sidebar-collapsed .sidebar--left {
|
||||
gap: 3px;
|
||||
margin-left: 14px;
|
||||
margin-top: 3px;
|
||||
border-left: 1px solid var(--border);
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
@@ -1359,8 +1374,8 @@ body:not(.left-sidebar-collapsed) .topbar__sidebar-toggle-icon--close {
|
||||
|
||||
.post-article {
|
||||
max-width: var(--content-header);
|
||||
margin: 0 auto;
|
||||
padding: 18px 0 10px;
|
||||
margin: 0 auto 3rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.post-header {
|
||||
@@ -1572,6 +1587,40 @@ body:not(.left-sidebar-collapsed) .topbar__sidebar-toggle-icon--close {
|
||||
color: var(--text-soft);
|
||||
}
|
||||
|
||||
.pagination--load-more {
|
||||
justify-content: center;
|
||||
padding-top: 28px;
|
||||
}
|
||||
|
||||
.pagination__load-more {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 96px;
|
||||
min-height: 34px;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid #2f2f2f;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(180deg, #4a4a4a 0%, #242424 100%);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.pagination__load-more:hover {
|
||||
transform: translateY(-1px);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.pagination__load-more:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
.search-modal[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -197,7 +197,7 @@
|
||||
function renderSearchResults(keyword) {
|
||||
var normalized = keyword.trim().toLowerCase();
|
||||
if (!normalized) {
|
||||
searchResults.innerHTML = '<p class="search-modal__hint">Start typing to filter visible posts, tags, and authors in the current page.</p>';
|
||||
searchResults.innerHTML = '<p class="search-modal__hint">현재 페이지에 표시되는 게시물, 태그 및 작성자를 필터링하려면 입력을 시작하세요.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
});
|
||||
|
||||
if (!items.length) {
|
||||
searchResults.innerHTML = '<p class="search-empty">No matching items in the current view.</p>';
|
||||
searchResults.innerHTML = '<p class="search-empty">현재 보기에 일치하는 항목이 없습니다.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -258,4 +258,84 @@
|
||||
toggleSearch(false);
|
||||
}
|
||||
});
|
||||
|
||||
function updateLoadMoreState(pagination, nextUrl, loading) {
|
||||
var trigger = pagination.querySelector("[data-load-more-trigger]");
|
||||
if (!trigger) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nextUrl) {
|
||||
pagination.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
pagination.dataset.nextUrl = nextUrl;
|
||||
trigger.disabled = !!loading;
|
||||
trigger.textContent = loading ? "Loading..." : "Load More";
|
||||
pagination.classList.toggle("is-loading", !!loading);
|
||||
}
|
||||
|
||||
function initializeLoadMore(root) {
|
||||
var pagination = root.querySelector("[data-load-more-pagination]");
|
||||
var list = root.querySelector("[data-load-more-list]");
|
||||
|
||||
if (!pagination || !list || pagination.dataset.bound === "true") {
|
||||
return;
|
||||
}
|
||||
|
||||
var trigger = pagination.querySelector("[data-load-more-trigger]");
|
||||
if (!trigger) {
|
||||
return;
|
||||
}
|
||||
|
||||
pagination.dataset.bound = "true";
|
||||
|
||||
trigger.addEventListener("click", function () {
|
||||
var nextUrl = pagination.dataset.nextUrl;
|
||||
|
||||
if (!nextUrl || pagination.classList.contains("is-loading")) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateLoadMoreState(pagination, nextUrl, true);
|
||||
|
||||
fetch(nextUrl, {
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
}
|
||||
})
|
||||
.then(function (response) {
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load more posts");
|
||||
}
|
||||
|
||||
return response.text();
|
||||
})
|
||||
.then(function (html) {
|
||||
var parser = new DOMParser();
|
||||
var documentFragment = parser.parseFromString(html, "text/html");
|
||||
var nextRoot = documentFragment.querySelector("[data-load-more-root]");
|
||||
var nextList = nextRoot ? nextRoot.querySelector("[data-load-more-list]") : null;
|
||||
var nextPagination = nextRoot ? nextRoot.querySelector("[data-load-more-pagination]") : null;
|
||||
|
||||
if (!nextList) {
|
||||
throw new Error("Post list not found");
|
||||
}
|
||||
|
||||
Array.prototype.forEach.call(nextList.children, function (item) {
|
||||
list.appendChild(item.cloneNode(true));
|
||||
});
|
||||
|
||||
updateLoadMoreState(pagination, nextPagination ? nextPagination.dataset.nextUrl : "", false);
|
||||
})
|
||||
.catch(function () {
|
||||
updateLoadMoreState(pagination, pagination.dataset.nextUrl, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll("[data-load-more-root]").forEach(function (rootNode) {
|
||||
initializeLoadMore(rootNode);
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
@layer components {
|
||||
.prose {
|
||||
color: var(--tw-prose-body);
|
||||
max-width: 65ch;
|
||||
/* max-width: 65ch; */
|
||||
font-size: 1rem;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
27
author.hbs
27
author.hbs
@@ -1,21 +1,20 @@
|
||||
{{!< default}}
|
||||
|
||||
<main class="content-area">
|
||||
<section class="stack-section">
|
||||
<header class="section-header section-header--author">
|
||||
<div class="author-header">
|
||||
{{#if profile_image}}
|
||||
<img class="avatar avatar--large" src="{{img_url profile_image size="s"}}" alt="{{name}}">
|
||||
{{else}}
|
||||
<div class="avatar avatar--large avatar--fallback">A</div>
|
||||
{{/if}}
|
||||
<div>
|
||||
<h1 class="section-title">{{name}}</h1>
|
||||
{{#if bio}}<p class="section-description">{{bio}}</p>{{/if}}
|
||||
<div class="meta-pill">{{plural count.posts empty="No posts" singular="% post" plural="% posts"}}</div>
|
||||
</div>
|
||||
<section class="px-5 sm:px-6 pt-4 sm:pt-5">
|
||||
<div class="max-w-content mx-auto flex items-center flex-col-reverse sm:flex-row gap-3 justify-between border-b border-brd pb-4 sm:pb-5">
|
||||
<div class="flex-1 flex flex-col gap-1">
|
||||
<h1 class="text-lg sm:text-xl font-medium leading-tight">{{name}}</h1>
|
||||
{{#if bio}}<p class="text-sm text-typ-tone max-w-lg text-balance">{{bio}}</p>{{/if}}
|
||||
</div>
|
||||
</header>
|
||||
<div class="meta-pill">{{plural count.posts empty="No posts" singular="% post" plural="% posts"}}</div>
|
||||
|
||||
{{#if profile_image}}
|
||||
<img class="h-16 w-16 shrink-0 self-start rounded-theme object-cover sm:h-20 sm:w-20" src="{{img_url profile_image size="s"}}" alt="{{name}}">
|
||||
{{else}}
|
||||
<div class="flex h-16 w-16 shrink-0 self-start items-center justify-center rounded-theme bg-bgr-tone text-sm font-semibold text-typ-tone sm:h-20 sm:w-20">{{name}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{> "lists/post-feed"}}
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<span class="mt-1 block text-[13px] leading-5 text-[var(--text-soft)]">Posts by {{name}}.</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
<img class="h-4 w-4 shrink-0 opacity-70 transition-opacity group-hover:opacity-100" src="{{asset "icons/arrow_outward.svg"}}" alt="">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-share-3"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M13 4v4c-6.575 1.028 -9.02 6.788 -10 12c-.037 .206 5.384 -5.962 10 -6v4l8 -7l-8 -7"></path></svg>
|
||||
</span>
|
||||
<span class="mt-auto pt-3 text-[13px] font-medium text-[var(--text-soft)]">{{plural count.posts empty="0 posts" singular="% post" plural="% posts"}}</span>
|
||||
</a>
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
{{ghost_head}}
|
||||
</head>
|
||||
<body class="{{body_class}}">
|
||||
<body class="{{body_class}} bg-bgr text-typ antialiased">
|
||||
{{> "site/topbar"}}
|
||||
<div class="left-sidebar-backdrop" data-left-sidebar-backdrop hidden></div>
|
||||
<div class="site-shell-wrap">
|
||||
<div class="site-shell">
|
||||
<div class="site-shell-wrap border-t border-brd bg-bgr">
|
||||
<div class="site-shell mx-auto">
|
||||
{{> "site/sidebar-left"}}
|
||||
<div class="site-main">
|
||||
<div class="site-main min-w-0 bg-bgr">
|
||||
{{{body}}}
|
||||
</div>
|
||||
{{> "site/sidebar-right"}}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 배포 가이드
|
||||
|
||||
## 현재 버전
|
||||
- `v0.1.31`
|
||||
- `v0.1.40`
|
||||
|
||||
## Git 기본 설정
|
||||
- 저장소 작성자 정보는 아래 값으로 통일한다.
|
||||
@@ -65,6 +65,13 @@ npm run build:tailwind
|
||||
- Alpine 결과물은 `assets/built/alpine.js`에 생성된다.
|
||||
- Tailwind 결과물은 `assets/built/tailwind.css`에 생성되고, Ghost 테마에서 `screen.css` 다음에 로드된다.
|
||||
|
||||
## 업로드용 zip 생성
|
||||
```bash
|
||||
npm run zip:version
|
||||
```
|
||||
|
||||
- 현재 `package.json` 버전을 기준으로 `thred-inspired-theme-v0.x.x.zip` 파일을 생성한다.
|
||||
|
||||
## `/tags/`, `/authors/` 연결 방법
|
||||
- 가장 쉬운 방법은 Ghost Admin에서 페이지를 만들고 슬러그를 각각 `tags`, `authors`로 지정한 뒤 템플릿을 연결하는 방식이다.
|
||||
- 페이지 방식 대신 커스텀 라우트를 쓰려면 [routes.yaml.example](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/routes.yaml.example)를 기준으로 Ghost의 `routes.yaml`에 `/tags/`, `/authors/`를 연결한다.
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# 의사결정 이력
|
||||
|
||||
## 2026-04-16 v0.1.40
|
||||
최근 수정이 누적되면서 `update/spec/map/deploy/history` 문서의 버전 표기가 서로 어긋났고, 커밋 메시지도 기존 저장소 패턴과 달라져 추적성이 떨어졌다. 그래서 이번에는 기능 자체를 더 넓게 바꾸기보다, 이미 진행한 홈 히어로/탭 피드/태그 카드 보정 작업을 기준으로 문서 버전 체계를 `v0.1.40`으로 맞추고 기록 형식을 기존 흐름에 맞춰 정리했다. 이렇게 해야 다음 작업자가 문서와 커밋 히스토리만 보고도 현재 상태를 빠르게 파악할 수 있다.
|
||||
|
||||
## 2026-04-14 v0.1.38
|
||||
업로드용 zip을 매번 수동 명령으로 만들면 작업 마무리 단계에서 반복 비용이 계속 생긴다. 그래서 현재 `package.json` 버전을 그대로 파일명에 반영하는 `npm run zip:version` 스크립트를 추가해, 사용자가 별도 옵션 없이도 바로 업로드용 압축 파일을 만들 수 있게 정리했다. 이 방식이면 버전 표기와 파일명이 자연스럽게 맞춰지고, 이후 반복 작업도 훨씬 단순해진다.
|
||||
|
||||
## 2026-04-14 v0.1.37
|
||||
참고 사이트의 목록 UX는 페이지 이동보다 하단 버튼으로 다음 목록을 이어 붙이는 방식이었고, 현재 Ghost 기본 `{{pagination}}` 링크 UI는 그 경험과 다르게 느껴졌다. 그래서 서버 쪽 데이터 구조를 바꾸지 않고, Ghost가 렌더링한 다음 페이지 HTML을 그대로 가져와 목록 부분만 파싱해 append 하는 방식을 선택했다. 이 방식은 기존 템플릿 구조를 크게 해치지 않으면서도, 다음 페이지가 없으면 버튼이 자동으로 사라지는 동작까지 비교적 안전하게 구현할 수 있다.
|
||||
|
||||
## 2026-04-14 v0.1.36
|
||||
`tag.hbs`는 개별 태그 아카이브용인데, 사용자가 기대한 화면은 `/tags/` 태그 목록 인덱스였다. 확인 결과 테마 안의 링크와 템플릿은 이미 준비돼 있었지만, 로컬 Ghost가 실제로 읽는 `.docker/ghost/content/settings/routes.yaml`에는 `/tags/`, `/authors/` 라우트가 빠져 있었다. 그래서 테마 템플릿을 더 손대기보다, 로컬 Ghost 설정 라우트를 예시 파일과 맞추는 쪽이 문제 원인과 해결책이 가장 명확하다고 판단했다.
|
||||
|
||||
## 2026-04-14 v0.1.35
|
||||
Ghost의 `tag.hbs`는 이미 태그 컨텍스트와 페이지네이션 컨텍스트를 함께 제공하는데, 여기에 다시 `{{#tag}}` 블록을 감싸면 내부 partial에서 `{{pagination}}`이 현재 페이징 스코프를 잃을 수 있다. 그래서 태그 템플릿은 블록 헬퍼 없이 현재 컨텍스트를 바로 쓰도록 정리했다. 작성자 템플릿의 아바타는 데이터가 없어서가 아니라 크기 유틸리티가 빠져 실질적으로 보이지 않던 상태였기 때문에, 이미지와 fallback 모두 명시적인 크기를 부여해 화면에 안정적으로 표시되도록 수정했다.
|
||||
|
||||
## 2026-04-14 v0.1.34
|
||||
우측 사이드바는 레이아웃 복구 과정에서 CSS 구조 중심 마크업으로 너무 많이 되돌아가면서, 사용자가 앞서 적용해둔 Tailwind 기반 정리 흐름이 사실상 사라졌다. 그래서 이번에는 우측 사이드바도 좌측/헤더와 같은 기준으로, `sidebar--right`와 기존 블록 클래스는 유지하되 실제 배치와 간격은 Tailwind 유틸리티로 다시 표현하는 방식으로 재정리했다. 이렇게 하면 기존 폭 계산과 스타일 훅은 보존하면서도, 사용자가 직접 이어서 수정하기 쉬운 구조를 다시 확보할 수 있다.
|
||||
|
||||
## 2026-04-14 v0.1.33
|
||||
좌측 사이드바 닫힘 애니메이션이 사라진 직접적인 원인은 데스크톱 접힘 상태에서 `.sidebar--left`를 `display: none`으로 처리한 데 있었다. 이 방식은 레이아웃 정리는 쉽지만 전환 프레임이 모두 사라지기 때문에, 이번에는 그리드 첫 열을 `0`으로 줄이면서 사이드바와 내부 콘텐츠에 `opacity`와 `transform` 전환을 주는 방식으로 바꿨다. 이렇게 하면 기존 셸 폭 계산은 유지하면서도 사용자가 기대하는 열리고 닫히는 움직임을 다시 복원할 수 있다.
|
||||
|
||||
## 2026-04-14 v0.1.32
|
||||
최근 레이아웃 붕괴는 Tailwind 마크업을 유지하려는 수정과, 기존 `screen.css` 및 `theme.js`가 기대하는 구조 클래스가 어긋난 것이 함께 겹치면서 발생했다. 그래서 이번에는 원래 셸 구조를 단순 복원하는 대신, `site-shell`, `topbar__inner`, `sidebar--left`, `sidebar--right`처럼 폭 계산과 토글 동작에 직접 연결된 훅은 유지하고 그 위에만 Tailwind 유틸리티를 다시 얹는 하이브리드 방식으로 정리했다. 이렇게 하면 사용자가 선호하는 Tailwind 중심 수정 흐름을 유지하면서도, 1296px 헤더 정렬과 287px 사이드바 계산 같은 핵심 레이아웃 기준을 다시 안정적으로 보존할 수 있다.
|
||||
|
||||
## 2026-04-14 v0.1.31
|
||||
zip 업로드 없이 로컬 Ghost에서 바로 확인하려면 자동 sync가 필요했지만, `fs.watch` 기반 재귀 watcher는 현재 환경에서 `EMFILE` 오류로 안정적으로 유지되지 않았다. 그래서 별도 의존성을 추가하지 않고, 제외 디렉터리를 뺀 파일 목록의 수정 시간을 주기적으로 비교하는 polling 방식으로 `dev:watch`를 구현했다. 이 방식은 다소 단순하지만 현재 저장소 크기에서는 충분히 가볍고, 사용자가 템플릿을 저장한 뒤 바로 브라우저 새로고침으로 확인할 수 있다는 점이 더 중요하다고 판단했다.
|
||||
|
||||
|
||||
11
docs/map.md
11
docs/map.md
@@ -1,17 +1,17 @@
|
||||
# 파일-화면 매핑 가이드
|
||||
|
||||
## 현재 버전
|
||||
- `v0.1.31`
|
||||
- `v0.1.40`
|
||||
|
||||
## 공통 레이아웃
|
||||
- [default.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/default.hbs): 전체 3열 셸과 공통 자산 로드
|
||||
- [default.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/default.hbs): 전체 3열 셸, 1296px 공통 폭 계산, 공통 자산 로드
|
||||
- [partials/site/sidebar-left.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/site/sidebar-left.hbs): 좌측 탐색/직접 링크형 Tags·Authors 메뉴/카테고리 아코디언/푸터
|
||||
- [page-tags.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/page-tags.hbs): `slug=tags` 페이지용 태그 디렉터리
|
||||
- [page-authors.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/page-authors.hbs): `slug=authors` 페이지용 작성자 디렉터리
|
||||
- [tags-index.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/tags-index.hbs): `/tags/` 커스텀 라우트용 태그 디렉터리
|
||||
- [authors-index.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/authors-index.hbs): `/authors/` 커스텀 라우트용 작성자 디렉터리
|
||||
- [partials/site/topbar.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/site/topbar.hbs): 상단 검색/CTA/다크모드
|
||||
- [partials/site/sidebar-right.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/site/sidebar-right.hbs): 구독/추천/작성자/푸터
|
||||
- [partials/site/topbar.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/site/topbar.hbs): 상단 3열 헤더, 중앙 검색, 좌측 사이드바 토글
|
||||
- [partials/site/sidebar-right.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/site/sidebar-right.hbs): 우측 287px 사이드바, Tailwind 기반 작성자/구독/추천/푸터 구성
|
||||
|
||||
## 홈 및 목록
|
||||
- [home.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/home.hbs): 메인 홈
|
||||
@@ -19,6 +19,7 @@
|
||||
- [partials/home/hero.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/home/hero.hbs): 홈 히어로 영역
|
||||
- [partials/home/tabbed-feed.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/home/tabbed-feed.hbs): Latest/Featured/Updated/Categories 탭과 카테고리 개요 행
|
||||
- [partials/lists/post-items.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/lists/post-items.hbs): Tailwind 기반 리스트형 포스트 카드, 댓글 아이콘, 우측 공유 액션, 메타 정보, 태그 accent 배지
|
||||
- [partials/lists/post-feed.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/lists/post-feed.hbs): 목록 래퍼와 `Load More` 확장형 페이지네이션 연결
|
||||
|
||||
## 상세 및 아카이브
|
||||
- [post.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/post.hbs): 포스트 상세
|
||||
@@ -32,8 +33,10 @@
|
||||
- [assets/built/tailwind.css](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/assets/built/tailwind.css): Tailwind 빌드 결과물
|
||||
- [assets/built/alpine.js](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/assets/built/alpine.js): Alpine.js 로컬 배포 파일
|
||||
- [assets/built/theme.js](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/assets/built/theme.js): 인터랙션 스크립트
|
||||
- [partials/pagination.hbs](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/partials/pagination.hbs): 다음 페이지가 있을 때만 표시되는 `Load More` 버튼
|
||||
- [assets/styles/tailwind.css](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/assets/styles/tailwind.css): Tailwind 입력 파일, `prose` 타이포그래피 규칙, accent/구분선 보조 유틸리티
|
||||
- [tailwind.config.js](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/tailwind.config.js): Tailwind 스캔 경로, 테마 설정, preflight 초기화 설정
|
||||
- [scripts/dev-watch.js](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/scripts/dev-watch.js): 로컬 파일 변경 감지 후 `dev:sync`와 Tailwind watch를 함께 실행하는 개발용 watcher
|
||||
- [routes.yaml.example](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/routes.yaml.example): Ghost 커스텀 라우트 예시
|
||||
- [package.json](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/package.json): Ghost 테마 메타데이터
|
||||
- [package.json](/Users/bicute/Desktop/UGREEN/GHOST%20THEME/package.json): Ghost 테마 메타데이터, `zip:version` 압축 스크립트
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 기술 명세
|
||||
|
||||
## 현재 버전
|
||||
- `v0.1.31`
|
||||
- `v0.1.40`
|
||||
|
||||
## 테마 개요
|
||||
- Ghost `v5` 대응 커스텀 테마
|
||||
@@ -17,13 +17,15 @@
|
||||
- Tailwind 기본 초기화(`preflight`)를 활성화해 브라우저 기본 마진과 폼 스타일을 리셋
|
||||
- Alpine.js 로컬 자산(`assets/built/alpine.js`)을 전역 로드
|
||||
- `npm run dev:watch`는 초기 `dev:prepare` 실행 후 Tailwind `--watch`와 파일 변경 감지 기반 `dev:sync`를 함께 실행함
|
||||
- `npm run zip:version`은 현재 `package.json` 버전명을 기준으로 업로드용 zip을 생성함
|
||||
- 좌측 카테고리 영역은 Alpine.js로 제어되며 `1024px` 이상에서 기본 열림, 미만에서 기본 닫힘
|
||||
- 좌측 네비게이션 마커와 카테고리 마커는 동일한 세로 바 → 원형 hover 패턴 사용
|
||||
- 전역 `ol`, `ul`, `menu` 기본 패딩과 리스트 스타일 리셋 적용
|
||||
- `author.hbs`는 페이지 컨텍스트의 작성자 데이터를 직접 사용
|
||||
- `page-tags.hbs`, `page-authors.hbs`는 각각 `slug=tags`, `slug=authors` 페이지에 연결 가능
|
||||
- 태그/작성자 디렉터리 목록은 현재 `limit="100"` 기준
|
||||
- `tags-index.hbs`, `authors-index.hbs`는 `routes.yaml` 커스텀 라우트로 `/tags/`, `/authors/`에 연결 가능
|
||||
- `tags-index.hbs`, `authors-index.hbs`는 Ghost `routes.yaml` 커스텀 라우트로 `/tags/`, `/authors/`에 연결됨
|
||||
- 로컬 개발 환경의 실제 라우트 설정은 `.docker/ghost/content/settings/routes.yaml`을 기준으로 사용함
|
||||
- 홈 메인 피드는 히어로, 탭형 목록, 카테고리 개요를 원본 비주얼 밀도에 가깝게 재구성
|
||||
- 리스트형 `post-card`는 Tailwind 유틸리티 중심 마크업으로 구성되며, 썸네일은 `aspect-square sm:aspect-video` 비율을 사용
|
||||
- 각 카드 항목은 `border-b border-brd` 구분선을 유지하고, 콘텐츠 래퍼는 `min-w-0` 기준으로 줄바꿈 폭을 제어
|
||||
@@ -31,6 +33,7 @@
|
||||
- 포스트 본문은 `prose prose-theme` 클래스를 사용하며, Typography 플러그인 대신 Tailwind 입력 파일에서 원본 기준 타이포그래피 규칙을 직접 제공함
|
||||
- 본문 `ul`, `ol`은 전역 리스트 리셋과 별개로 `prose` 범위 안에서 실제 마커와 들여쓰기를 다시 적용함
|
||||
- 태그 배지는 `--color-accent` 기반 배경 혼합색(`bg-accent/10`, `hover:bg-accent/5`)을 사용함
|
||||
- 홈 Latest, 기본 index, 태그 아카이브, 작성자 아카이브의 목록 영역은 `Load More` 버튼 기반 확장형 페이지네이션을 사용함
|
||||
|
||||
## 주요 스타일 방향
|
||||
- 밝은 크림톤 배경 + 오렌지 포인트
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
# 업데이트 로그
|
||||
|
||||
## v0.1.40 - 2026-04-16
|
||||
- 문서 버전 표기를 `v0.1.40`으로 정합성 수정.
|
||||
- `docs/history.md` 의사결정 이력 최신 버전 항목 추가.
|
||||
- 홈 히어로/탭 피드/태그 카드 원본 기준 보정 작업 반영 및 형식 정리.
|
||||
|
||||
## v0.1.39 - 2026-04-16
|
||||
- `tags-index.hbs` 태그 카드 목록 마크업을 원본(Thred) 구조 기준으로 변환 수정.
|
||||
- `tags-index.hbs` 태그 카드 좌측 보더/호버 배경이 각 태그 `accent_color`를 항상 사용하도록 수정.
|
||||
- `tags-index.hbs` 태그 카드 호버 시 보더 색 변경을 제거하고 내부 배경만 `accent_color` 25%로 보이도록 수정.
|
||||
- `tags-index.hbs` 태그 카드 좌측 보더 색을 인라인 `border-left-color`로 고정해 클래스 우선순위 영향 없이 항상 액센트 색이 표시되도록 수정.
|
||||
- `tags-index.hbs`에서 `accent_color` 미지정 태그는 컬러 fallback을 제거해 좌측 포인트 컬러가 표시되지 않도록 수정.
|
||||
- `partials/home/hero.hbs` 기존 히어로 섹션을 제거하고 원본 구조 기반 수동 구독 폼으로 교체, 미지원 클래스/Alpine 이벤트를 Ghost 동작 기준으로 정리.
|
||||
- `partials/home/tabbed-feed.hbs` 탭/모바일 피드 선택 UI를 원본 구조 기준 Alpine 마크업으로 재구성하고, 피드/카테고리 데이터 바인딩은 기존 Ghost 헬퍼 흐름으로 유지.
|
||||
|
||||
## v0.1.38 - 2026-04-14
|
||||
- `npm run zip:version` 압축 스크립트 추가.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ghost-theme-thred-clone",
|
||||
"version": "0.1.31",
|
||||
"version": "0.1.40",
|
||||
"private": true,
|
||||
"description": "A Ghost theme inspired by the Thred reference layout.",
|
||||
"keywords": [
|
||||
@@ -86,7 +86,8 @@
|
||||
"dev:ghost:start": "npm run dev:prepare && docker compose up -d && printf '\\nGhost local: http://localhost:2368\\nGhost admin: http://localhost:2368/ghost\\n\\n'",
|
||||
"dev:ghost:restart": "npm run dev:prepare && docker compose restart ghost && printf '\\nGhost local: http://localhost:2368\\nGhost admin: http://localhost:2368/ghost\\n\\n'",
|
||||
"dev:ghost:stop": "docker compose down",
|
||||
"zip": "zip -r theme.zip . -x '*.git*' -x 'node_modules/*' -x 'theme.zip'"
|
||||
"zip": "zip -r theme.zip . -x '*.git*' -x 'node_modules/*' -x 'theme.zip'",
|
||||
"zip:version": "rm -f thred-inspired-theme-v$npm_package_version.zip && git ls-files | zip -q thred-inspired-theme-v$npm_package_version.zip -@"
|
||||
},
|
||||
"devDependencies": {
|
||||
"alpinejs": "^3.14.9",
|
||||
|
||||
2
page.hbs
2
page.hbs
@@ -1,7 +1,7 @@
|
||||
{{!< default}}
|
||||
|
||||
{{#post}}
|
||||
<main class="content-area content-area--post">
|
||||
<main class="px-4 sm:px-[max(2vmin,20px)] mt-6 mb-8">
|
||||
<article class="post-template page-template {{post_class}}">
|
||||
{{#match @page.show_title_and_feature_image}}
|
||||
<header class="post-header">
|
||||
|
||||
@@ -1,15 +1,49 @@
|
||||
<section class="hero home-hero" data-home-hero>
|
||||
<div class="home-hero__inner">
|
||||
<div class="home-hero__content">
|
||||
<h1 class="hero__title">Ideas <em>published</em> for meaningful conversation, <em>discussed</em> and shaped by the community</h1>
|
||||
<section class="home-hero px-5 sm:px-6 py-6 md:py-8 relative" data-home-hero="">
|
||||
<div class="max-w-content mx-auto flex gap-6">
|
||||
<div class="home-hero__content z-2 flex-2 flex flex-col gap-2 items-center justify-center text-center">
|
||||
<h1 class="text-xl md:text-2xl font-semibold text-balance leading-[1.125]">
|
||||
Ideas <em>published</em> for meaningful conversation, <em>discussed</em> and shaped by the community
|
||||
</h1>
|
||||
{{#if @site.description}}
|
||||
<p class="hero__description">{{@site.description}}</p>
|
||||
<p class="text-base text-balance text-typ-tone max-w-md leading-snug">{{@site.description}}</p>
|
||||
{{/if}}
|
||||
{{subscribe_form
|
||||
placeholder="Your email"
|
||||
button_class="button button--light button--subscribe"
|
||||
form_class="subscribe-form subscribe-form--hero"
|
||||
}}
|
||||
<form class="group relative flex w-full max-w-xs flex-col items-start mt-1" data-members-form="subscribe">
|
||||
<fieldset class="w-full flex gap-2 flex-wrap text-sm">
|
||||
<legend class="sr-only">Personal information</legend>
|
||||
<input data-members-email="" class="text-sm bg-bgr-tone border border-brd text-typ flex-2 py-1.5 px-3 rounded-md focus:ring-0 focus:bg-bgr" type="email" autocomplete="email" placeholder="Your email" aria-label="Your email" required="" aria-required="true">
|
||||
<button class="flex-1 px-3 py-1.5 text-bgr font-medium rounded-md hover:opacity-90 bg-gradient-to-b from-typ/75 to-typ/95 border border-typ cursor-pointer" type="submit">
|
||||
<span class="hidden group-[.loading]:flex items-center justify-center">
|
||||
<i class="icon icon-loader size-5 [&_svg]:animate-spin stroke-2" role="presentation">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 3a9 9 0 1 0 9 9"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
<span class="group-[.loading]:hidden">Subscribe</span>
|
||||
</button>
|
||||
</fieldset>
|
||||
<div data-notification="" class="absolute left-0 -bottom-16 z-50 invisible opacity-0 -translate-y-4 transition-all text-[0.8rem] text-left font-medium leading-none flex items-center w-full max-w-md rounded-md gap-2 bg-white text-black p-3 shadow-lg group-[.success]:opacity-100 group-[.success]:visible group-[.success]:translate-y-0 group-[.error]:opacity-100 group-[.error]:visible group-[.error]:translate-y-0">
|
||||
<div class="hidden group-[.success]:flex items-center gap-2 flex-1">
|
||||
<i class="icon icon-success size-6 text-emerald-600 fill-current" role="presentation">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M17 3.34a10 10 0 1 1 -14.995 8.984l-.005 -.324l.005 -.324a10 10 0 0 1 14.995 -8.336zm-1.293 5.953a1 1 0 0 0 -1.32 -.083l-.094 .083l-3.293 3.292l-1.293 -1.292l-.094 -.083a1 1 0 0 0 -1.403 1.403l.083 .094l2 2l.094 .083a1 1 0 0 0 1.226 0l.094 -.083l4 -4l.083 -.094a1 1 0 0 0 -.083 -1.32z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
<p>Great! Check your inbox and click the link.</p>
|
||||
</div>
|
||||
<div class="hidden group-[.error]:flex items-center gap-2 flex-1">
|
||||
<i class="icon icon-error size-6 text-red-600 fill-current" role="presentation">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 1.67c.955 0 1.845 .467 2.39 1.247l.105 .16l8.114 13.548a2.914 2.914 0 0 1 -2.307 4.363l-.195 .008h-16.225a2.914 2.914 0 0 1 -2.582 -4.2l.099 -.185l8.11 -13.538a2.914 2.914 0 0 1 2.491 -1.403zm.01 13.33l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -7a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
<p>Sorry, something went wrong. Please try again.</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
@@ -1,59 +1,97 @@
|
||||
<section class="px-5 sm:px-6 py-4" data-tabs data-home-content>
|
||||
<section class="px-5 sm:px-6 py-4" data-home-content x-data="{ activeFeed: '#latest', postFeedTypeOpen: false }">
|
||||
<div class="max-w-content mx-auto">
|
||||
<div class="flex gap-2 items-center justify-between border-b border-brd pb-2">
|
||||
<div class="tab-row home-feed__tabs" role="tablist" aria-label="Homepage sections">
|
||||
<button class="tab-row__button is-active" type="button" data-tab-trigger="latest">Latest</button>
|
||||
<button class="tab-row__button" type="button" data-tab-trigger="featured">Featured</button>
|
||||
<button class="tab-row__button" type="button" data-tab-trigger="updated">Updated</button>
|
||||
<button class="tab-row__button" type="button" data-tab-trigger="categories">Categories</button>
|
||||
<div class="flex gap-2 items-center justify-between border-b border-brd pb-2">
|
||||
<ul class="hidden md:flex gap-1 text-typ-tone font-medium" data-feed-select="">
|
||||
<li data-feed-select-item="latest">
|
||||
<a href="#latest" class="block text-sm px-3 py-1.5 rounded-theme hover:bg-bgr-tone hover:text-typ relative" :class="activeFeed === '#latest' ? 'text-typ after:absolute after:-bottom-2 after:left-0 after:w-full after:h-0.5 after:bg-typ' : ''" @click.prevent="activeFeed = '#latest'">Latest</a>
|
||||
</li>
|
||||
<li data-feed-select-item="featured">
|
||||
<a href="#featured" class="block text-sm px-3 py-1.5 rounded-theme hover:bg-bgr-tone hover:text-typ relative" :class="activeFeed === '#featured' ? 'text-typ after:absolute after:-bottom-2 after:left-0 after:w-full after:h-0.5 after:bg-typ' : ''" @click.prevent="activeFeed = '#featured'">Featured</a>
|
||||
</li>
|
||||
<li data-feed-select-item="updated">
|
||||
<a href="#updated" class="block text-sm px-3 py-1.5 rounded-theme hover:bg-bgr-tone hover:text-typ relative" :class="activeFeed === '#updated' ? 'text-typ after:absolute after:-bottom-2 after:left-0 after:w-full after:h-0.5 after:bg-typ' : ''" @click.prevent="activeFeed = '#updated'">Updated</a>
|
||||
</li>
|
||||
<li data-feed-select-item="categories">
|
||||
<a href="#categories" class="block text-sm px-3 py-1.5 rounded-theme hover:bg-bgr-tone hover:text-typ relative" :class="activeFeed === '#categories' ? 'text-typ after:absolute after:-bottom-2 after:left-0 after:w-full after:h-0.5 after:bg-typ' : ''" @click.prevent="activeFeed = '#categories'">Categories</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="flex flex-col gap-1 relative text-sm font-medium md:hidden">
|
||||
<button class="px-3 py-1.5 pr-2 rounded-theme bg-bgr hover:bg-bgr-tone relative leading-none cursor-pointer flex gap-0.75 items-center justify-center border border-brd" @click="postFeedTypeOpen = !postFeedTypeOpen" data-feed-type-toggle="" aria-label="Select feed type">
|
||||
<span class="pointer-events-none" x-show="activeFeed === '#latest'">Latest</span>
|
||||
<span class="pointer-events-none" x-show="activeFeed === '#featured'">Featured</span>
|
||||
<span class="pointer-events-none" x-show="activeFeed === '#updated'">Updated</span>
|
||||
<span class="pointer-events-none" x-show="activeFeed === '#categories'">Categories</span>
|
||||
<span class="opacity-75 pointer-events-none">
|
||||
<i class="icon icon-chevron-down stroke-[2.5] size-4" role="presentation">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
<menu class="flex flex-col gap-0.5 absolute top-9 left-0 border border-brd bg-bgr rounded-theme p-1.5 z-10 transition-[transform,opacity,visibility] shadow" :class="postFeedTypeOpen ? 'translate-y-0 opacity-100 visible' : '-translate-y-2 opacity-0 invisible'" @click.outside="postFeedTypeOpen = false">
|
||||
<li class="w-full"><a href="#latest" class="w-full px-2 py-1 flex items-center gap-1.5 hover:bg-bgr-tone rounded-theme cursor-pointer" @click.prevent="activeFeed = '#latest'; postFeedTypeOpen = false">Latest</a></li>
|
||||
<li class="w-full"><a href="#featured" class="w-full px-2 py-1 flex items-center gap-1.5 hover:bg-bgr-tone rounded-theme cursor-pointer" @click.prevent="activeFeed = '#featured'; postFeedTypeOpen = false">Featured</a></li>
|
||||
<li class="w-full"><a href="#updated" class="w-full px-2 py-1 flex items-center gap-1.5 hover:bg-bgr-tone rounded-theme cursor-pointer" @click.prevent="activeFeed = '#updated'; postFeedTypeOpen = false">Updated</a></li>
|
||||
<li class="w-full"><a href="#categories" class="w-full px-2 py-1 flex items-center gap-1.5 hover:bg-bgr-tone rounded-theme cursor-pointer" @click.prevent="activeFeed = '#categories'; postFeedTypeOpen = false">Categories</a></li>
|
||||
</menu>
|
||||
</div>
|
||||
</div>
|
||||
<button class="view-toggle home-feed__view-toggle" type="button" aria-label="Change view">
|
||||
<span class="view-toggle__grid"></span>
|
||||
<span class="view-toggle__chevron">⌄</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-8 mb-8 is-active" data-tab-panel="latest">
|
||||
{{> "lists/post-feed"}}
|
||||
</div>
|
||||
<div class="flex flex-col gap-8 mb-8" x-show="activeFeed === '#latest'" data-feed="latest">
|
||||
{{> "lists/post-feed"}}
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" data-tab-panel="featured">
|
||||
{{#get "posts" filter="featured:true" limit="8" include="authors,tags"}}
|
||||
{{> "lists/post-items" posts=posts}}
|
||||
{{/get}}
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" data-tab-panel="updated">
|
||||
{{#get "posts" order="updated_at desc" limit="8" include="authors,tags"}}
|
||||
{{> "lists/post-items" posts=posts}}
|
||||
{{/get}}
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" data-tab-panel="categories">
|
||||
<div class="category-overview">
|
||||
{{#get "tags" limit="8" include="count.posts" order="count.posts desc"}}
|
||||
{{#foreach tags}}
|
||||
<section class="category-overview__row"{{#if accent_color}} style="--tag-accent: {{accent_color}};"{{/if}}>
|
||||
<div class="category-overview__intro">
|
||||
<h2>{{name}}</h2>
|
||||
{{#if description}}
|
||||
<p>{{description}}</p>
|
||||
{{else}}
|
||||
<p>{{plural count.posts empty="No posts yet" singular="% post in this category" plural="% posts in this category"}}</p>
|
||||
{{/if}}
|
||||
<a class="category-overview__link" href="{{url}}">View all ↗</a>
|
||||
</div>
|
||||
<ol class="category-overview__posts">
|
||||
{{#get "posts" filter=(concat "tag:" slug) limit="5"}}
|
||||
{{#foreach posts}}
|
||||
<li><a href="{{url}}" data-number="{{@number}}. ">{{title}}</a></li>
|
||||
{{/foreach}}
|
||||
{{/get}}
|
||||
</ol>
|
||||
</section>
|
||||
{{/foreach}}
|
||||
<div class="tab-panel" x-show="activeFeed === '#featured'" data-feed="featured">
|
||||
{{#get "posts" filter="featured:true" limit="8" include="authors,tags"}}
|
||||
{{> "lists/post-items" posts=posts}}
|
||||
{{/get}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel **:data-post-card-date-updated:block **:data-post-card-date:hidden" x-show="activeFeed === '#updated'" data-feed="updated">
|
||||
{{#get "posts" order="updated_at desc" limit="8" include="authors,tags"}}
|
||||
{{> "lists/post-items" posts=posts}}
|
||||
{{/get}}
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" x-show="activeFeed === '#categories'" data-feed="categories">
|
||||
<ul class="flex flex-col">
|
||||
{{#get "tags" limit="8" include="count.posts" order="count.posts desc"}}
|
||||
{{#foreach tags}}
|
||||
<li class="p-4 pl-5 sm:pl-6 sm:p-5 flex flex-wrap flex-col gap-2 md:flex-row border-b border-b-brd relative before:absolute before:left-0 before:top-0 before:w-0.75 before:h-full before:bg-accent"{{#if accent_color}} style="--color-accent:{{accent_color}}"{{/if}}>
|
||||
<h2 class="font-medium basis-full leading-tight">{{name}}</h2>
|
||||
<div class="flex-2 flex flex-col gap-1.5 border-b border-brd pb-3 mb-2 md:pb-0 md:border-b-0 md:mr-4 md:mb-0 items-start justify-between">
|
||||
{{#if description}}
|
||||
<p class="text-sm text-typ-tone line-clamp-4 text-ellipsis leading-snug">{{description}}</p>
|
||||
{{else}}
|
||||
<p class="text-sm text-typ-tone line-clamp-4 text-ellipsis leading-snug">{{plural count.posts empty="No posts yet" singular="% post in this category" plural="% posts in this category"}}</p>
|
||||
{{/if}}
|
||||
<a href="{{url}}" class="text-sm text-typ-tone font-semibold leading-snug flex items-center gap-1 hover:opacity-75 mt-0.5">
|
||||
<span>View all</span>
|
||||
<i class="icon icon-arrow-up-right size-3.5 stroke-3" role="presentation">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M17 7l-10 10"></path>
|
||||
<path d="M8 7l9 0l0 9"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</a>
|
||||
</div>
|
||||
<ol class="flex-3 flex flex-col gap-1.5 text-sm text-typ-tone font-medium">
|
||||
{{#get "posts" filter=(concat "tag:" slug) limit="5"}}
|
||||
{{#foreach posts}}
|
||||
<li>
|
||||
<a href="{{url}}" data-number="{{@number}}. " class="line-clamp-1 text-ellipsis before:content-[attr(data-number)] before:font-bold leading-snug hover:opacity-75" title="{{title}}">{{title}}</a>
|
||||
</li>
|
||||
{{/foreach}}
|
||||
{{/get}}
|
||||
</ol>
|
||||
</li>
|
||||
{{/foreach}}
|
||||
{{/get}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
{{#if show_filter}}
|
||||
<div class="section-filter">
|
||||
<span>Latest posts</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{> "lists/post-items" posts=posts}}
|
||||
{{pagination}}
|
||||
<div class="post-feed" data-load-more-root>
|
||||
{{#if show_filter}}
|
||||
<div class="section-filter">
|
||||
<span>Latest posts</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{> "lists/post-items" posts=posts}}
|
||||
{{pagination}}
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<div class="post-list home-post-list flex flex-col divide-y divide-brd">
|
||||
<div class="post-list home-post-list flex flex-col divide-y divide-brd" data-load-more-list>
|
||||
{{#foreach posts}}
|
||||
<article class="post {{post_class}} relative flex flex-row items-start gap-3 text-typ py-4 group overflow-hidden" data-post-card{{#if featured}} data-featured{{/if}}>
|
||||
<a href="{{url}}" data-post-card-media class="flex-1 relative group aspect-square sm:aspect-video min-w-16 ">
|
||||
{{#if feature_image}}
|
||||
<figure class="block rounded-theme overflow-hidden" role="none">
|
||||
<img class="w-full aspect-square sm:aspect-video object-cover rounded-[inherit] hover:opacity-90 transition-all blur-0" src="{{img_url feature_image size="s"}}" alt="{{title}}">
|
||||
<figure class="block rounded-lg overflow-hidden" role="none">
|
||||
<img class="w-full aspect-square sm:aspect-video object-cover hover:opacity-90 transition-all blur-0" src="{{img_url feature_image size="s"}}" alt="{{title}}">
|
||||
</figure>
|
||||
{{else}}
|
||||
<span class="block w-full aspect-square sm:aspect-video rounded-theme bg-bgr-tone text-typ-tone text-xs text-center p-4">{{title}}</span>
|
||||
<span class="block w-full aspect-square sm:aspect-video rounded-lg bg-bgr-tone text-typ-tone text-xs text-center p-4">{{title}}</span>
|
||||
{{/if}}
|
||||
</a>
|
||||
<div class="relative min-w-0 flex-3 md:flex-4 flex flex-col gap-1.5 justify-between " data-post-card-content>
|
||||
<h2 class="text-sm font-medium leading-tight flex flex-wrap gap-y-0.5 gap-x-1.5 items-end max-w-[90%]" data-post-card-title>
|
||||
<a href="{{url}}" class="hover:opacity-75 flex items-start gap-1.5">
|
||||
{{#if featured}}
|
||||
<span data-post-featured class="inline-flex text-brand -mr-0.5 shrink-0">
|
||||
<span data-post-featured class="icon icon-bolt size-4 stroke-1 fill-current5">
|
||||
<img class="size-4 -mt-0.5" src="{{asset "icons/bolt.svg"}}" alt="">
|
||||
</span>
|
||||
{{/if}}
|
||||
@@ -45,7 +45,9 @@
|
||||
</a>
|
||||
</div>
|
||||
<button data-post-share-toggle class="absolute top-0 md:top-auto md:bottom-0 right-0 flex gap-1 items-center hover:opacity-75 cursor-pointer md:opacity-0 md:invisible group-hover:opacity-100 group-hover:visible transition-[opacity,visibility]" type="button" aria-label="Share this post">
|
||||
<img class="size-4 pointer-events-none" src="{{asset "icons/arrow_outward.svg"}}" alt="">
|
||||
<i class="icon icon-share size-4 stroke-2 pointer-events-none" role="presentation">
|
||||
<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" class="icon icon-tabler icons-tabler-outline icon-tabler-share-3"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M13 4v4c-6.575 1.028 -9.02 6.788 -10 12c-.037 .206 5.384 -5.962 10 -6v4l8 -7l-8 -7"></path></svg>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
<nav class="pagination" role="navigation">
|
||||
{{#if prev}}
|
||||
<a class="pagination__link" href="{{page_url prev}}">Newer</a>
|
||||
{{/if}}
|
||||
<span class="pagination__status">Page {{page}} of {{pages}}</span>
|
||||
{{#if next}}
|
||||
<a class="pagination__link" href="{{page_url next}}">Older</a>
|
||||
{{/if}}
|
||||
</nav>
|
||||
{{#if next}}
|
||||
<div class="pagination pagination--load-more" data-load-more-pagination data-next-url="{{page_url next}}">
|
||||
<button class="pagination__load-more" type="button" data-load-more-trigger>Load More</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
<noscript>
|
||||
<nav class="pagination" role="navigation">
|
||||
{{#if prev}}
|
||||
<a class="pagination__link" href="{{page_url prev}}">Newer</a>
|
||||
{{/if}}
|
||||
<span class="pagination__status">Page {{page}} of {{pages}}</span>
|
||||
{{#if next}}
|
||||
<a class="pagination__link" href="{{page_url next}}">Older</a>
|
||||
{{/if}}
|
||||
</nav>
|
||||
</noscript>
|
||||
|
||||
@@ -1,14 +1,32 @@
|
||||
<nav class="post-navigation">
|
||||
<nav class="px-5 sm:px-6 mb-6">
|
||||
<div class="max-w-content mx-auto">
|
||||
<div class="grid md:grid-cols-2 gap-4 text-sm leading-tight font-medium">
|
||||
{{#prev_post}}
|
||||
<a class="post-navigation__link" href="{{url}}">
|
||||
<small>Previous post</small>
|
||||
<strong>{{title}}</strong>
|
||||
<a class="flex flex-col gap-1 items-start hover:opacity-75" href="{{url}}">
|
||||
<small class="uppercase font-medium text-[0.7rem] text-typ-tone opacity-75 flex items-center gap-0.75">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-left" width="14" height="14" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M15 6l-6 6l6 6"></path></svg>
|
||||
Previous post
|
||||
</small>
|
||||
<strong class="text-left flex flex-col gap-1 ml-4">{{title}}</strong>
|
||||
</a>
|
||||
{{/prev_post}}
|
||||
{{#next_post}}
|
||||
<a class="post-navigation__link post-navigation__link--next" href="{{url}}">
|
||||
<small>Next post</small>
|
||||
<strong>{{title}}</strong>
|
||||
<a class="flex flex-col gap-1 items-end hover:opacity-75" href="{{url}}">
|
||||
<small class="uppercase font-medium text-[0.7rem] text-typ-tone opacity-75 flex items-center gap-0.75">
|
||||
Next post
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-right" width="14" height="14" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M9 6l6 6l-6 6"></path></svg>
|
||||
</small>
|
||||
<strong class="text-left flex flex-col gap-1 ml-4">{{title}}</strong>
|
||||
</a>
|
||||
{{/next_post}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<aside class="sidebar sidebar--left">
|
||||
<div class="sidebar__inner">
|
||||
<nav class="menu-groups border-b border-brd pl-4 pr-3 sm:pl-5 xl:pl-0 py-3" data-nav="menu" data-primary-nav x-data="{ homePagesOpen: true, membersOpen: false }">
|
||||
<ul class="menu-groups__list flex flex-col gap-0.75 text-typ text-sm">
|
||||
<li class="menu-group menu-group--nav nav-toggle is-mainitem flex items-center flex-wrap w-full relative group" :class="{ 'is-open': homePagesOpen }" data-label="Home pages" data-slug="home-pages" data-length="10" aria-haspopup="true">
|
||||
@@ -64,7 +63,7 @@
|
||||
</button>
|
||||
<div class="sidebar-card__content sidebar-card__content--categories" x-cloak x-show="categoriesOpen">
|
||||
<ul class="category-grid grid sm:grid-cols-2 gap-x-2 gap-0.5 mt-1 text-typ-tone font-medium text-[0.8rem] -mb-1.5">
|
||||
{{#get "tags" limit="10" include="count.posts"}}
|
||||
{{#get "tags" limit="11" include="count.posts"}}
|
||||
{{#foreach tags}}
|
||||
<li>
|
||||
<a class="category-chip group flex items-center gap-2 leading-tight pl-0 pr-3 py-2 rounded-theme hover:bg-bgr-tone hover:px-3 hover:text-typ transition-[padding]" href="{{url}}" aria-label="{{name}}"{{#if accent_color}} style="--color-accent: {{accent_color}};"{{/if}}>
|
||||
@@ -79,7 +78,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sidebar-card">
|
||||
<section class="px-5 sm:px-6 py-4 sm:py-5 xl:pl-0 pr-3 sm:pr-3 flex flex-col gap-1.5 border-b border-brd">
|
||||
<div class="sidebar-card__header">
|
||||
<h2>Authors</h2>
|
||||
</div>
|
||||
@@ -102,12 +101,15 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="sidebar-footer">
|
||||
<a href="{{@custom.footer_primary_url}}">{{@custom.footer_primary_link}}</a>
|
||||
<a href="{{@custom.footer_secondary_url}}">{{@custom.footer_secondary_link}}</a>
|
||||
<a href="{{@custom.footer_tertiary_url}}">{{@custom.footer_tertiary_link}}</a>
|
||||
<a href="{{@custom.footer_quaternary_url}}">{{@custom.footer_quaternary_link}}</a>
|
||||
<button class="icon-button icon-button--plain" type="button" data-theme-toggle aria-label="Toggle theme">◐</button>
|
||||
<span class="flex-1"></span>
|
||||
|
||||
<nav class="pl-4 pr-3 sm:pl-5 xl:pl-1 py-2 flex items-center justify-between gap-2">
|
||||
<ul class="flex flex-wrap items-center gap-3 text-typ-tone text-xs mb-2">
|
||||
<li><a href="{{@custom.footer_primary_url}}">{{@custom.footer_primary_link}}</a></li>
|
||||
<li><a href="{{@custom.footer_secondary_url}}">{{@custom.footer_secondary_link}}</a></li>
|
||||
<li><a href="{{@custom.footer_tertiary_url}}">{{@custom.footer_tertiary_link}}</a></li>
|
||||
<li><a href="{{@custom.footer_quaternary_url}}">{{@custom.footer_quaternary_link}}</a></li>
|
||||
</ul>
|
||||
<button class="flex items-center self-start gap-1 p-1 size-6 rounded-theme hover:bg-bgr-tone cursor-pointer text-xs font-medium" data-theme-toggle aria-label="Toggle theme">◐</button>
|
||||
</footer>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -1,36 +1,39 @@
|
||||
<aside class="sidebar sidebar--right">
|
||||
<div class="sidebar__inner sidebar__inner--right">
|
||||
{{#is "post"}}
|
||||
{{#post}}
|
||||
{{#primary_author}}
|
||||
<section class="author-feature author-feature--top">
|
||||
{{#if profile_image}}
|
||||
<img class="avatar avatar--large" src="{{img_url profile_image size="s"}}" alt="{{name}}">
|
||||
<section class="px-4 sm:px-5 py-4 sm:py-5 xl:pr-1 flex flex-col gap-1.5 border-b border-brd">
|
||||
<a class="flex gap-2 hover:opacity-80">{{#if profile_image}}
|
||||
<img class="object-cover size-10 sm:size-12 aspect-square" src="{{img_url profile_image size="s"}}" alt="{{name}}">
|
||||
{{else}}
|
||||
<div class="avatar avatar--large avatar--fallback">A</div>
|
||||
<div class="object-cover size-10 sm:size-12 aspect-square avatar--fallback">A</div>
|
||||
{{/if}}
|
||||
<div class="author-feature__body">
|
||||
<h3>{{name}}</h3>
|
||||
{{#if bio}}<p>{{bio}}</p>{{/if}}
|
||||
<div class="flex-1 flex flex-col gap-1">
|
||||
<h3 class="text-sm font-medium leading-tight flex items-center justify-between gap-1">{{name}}</h3>
|
||||
{{#if bio}}<p class="text-xs text-typ-tone leading-tight line-clamp-3 text-overflow-ellipsis">{{bio}}</p>{{/if}}
|
||||
</div>
|
||||
<span class="author-feature__action">↗</span>
|
||||
</a>
|
||||
</section>
|
||||
{{/primary_author}}
|
||||
{{/post}}
|
||||
{{/is}}
|
||||
|
||||
<section class="site-intro">
|
||||
{{#if @site.icon}}
|
||||
<img class="site-icon" src="{{@site.icon}}" alt="{{@site.title}}">
|
||||
{{else}}
|
||||
<div class="site-icon site-icon--fallback">T</div>
|
||||
{{/if}}
|
||||
<div class="about-block">
|
||||
<h2>{{@site.title}}</h2>
|
||||
{{#if @site.description}}
|
||||
<p>{{@site.description}}</p>
|
||||
<section class="px-4 sm:px-5 py-4 sm:py-5 xl:pr-1 flex flex-col gap-3 border-b border-brd ">
|
||||
<div class="flex items-center gap-2.5">
|
||||
{{#if @site.icon}}
|
||||
<img class="w-12 min-h-12 rounded-md h-full relative" src="{{@site.icon}}" alt="{{@site.title}}">
|
||||
{{else}}
|
||||
<div class="w-12 min-h-12 rounded-md h-full relative site-icon--fallback">T</div>
|
||||
{{/if}}
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<h2 class="text-sm md:text-base font-medium leading-tight">{{@site.title}}</h2>
|
||||
{{#if @site.description}}
|
||||
<p class="text-sm text-typ-tone leading-tight">{{@site.description}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
{{subscribe_form
|
||||
@@ -38,57 +41,71 @@
|
||||
button_class="button button--subscribe"
|
||||
form_class="subscribe-form"
|
||||
}}
|
||||
|
||||
|
||||
<section class="sidebar-card sidebar-card--tight">
|
||||
<div class="sidebar-card__header">
|
||||
<h2>Follow</h2>
|
||||
<span class="sidebar-card__action">↗</span>
|
||||
</div>
|
||||
<div class="social-row">
|
||||
{{#if @site.facebook}}<a href="{{social_url type="facebook"}}" aria-label="Facebook">f</a>{{/if}}
|
||||
{{#if @site.twitter}}<a href="{{social_url type="twitter"}}" aria-label="X">x</a>{{/if}}
|
||||
<a href="{{@site.url}}/rss/" aria-label="RSS">rss</a>
|
||||
</div>
|
||||
<section class="px-4 sm:px-5 py-4 sm:py-5 xl:pr-1 flex flex-wrap items-center justify-between gap-1.5 border-b border-brd">
|
||||
<h2 class="uppercase font-medium text-xs text-typ-tone">Follow</h2>
|
||||
<nav class="relative flex flex-wrap items-center gap-1 text-typ text-sm z-10">
|
||||
{{!-- {{#if @site.facebook}}<a href="{{social_url type="facebook"}}" class="hover:opacity-75 p-0.5" aria-label="Facebook">f</a>{{/if}} --}}
|
||||
{{#if @site.twitter}}<a href="{{social_url type="twitter"}}" class="w-5 h-5 hover:opacity-75 p-0.5" aria-label="X">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-x" width="20" height="20" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M4 4l11.733 16h4.267l-11.733 -16z"></path>
|
||||
<path d="M4 20l6.768 -6.768m2.46 -2.46l6.772 -6.772"></path>
|
||||
</svg>
|
||||
</a>{{/if}}
|
||||
<a href="{{@site.url}}/rss/" class="hover:w-5 h-5 opacity-75 p-0.5" aria-label="RSS">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-rss" width="20" height="20" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<circle cx="5" cy="19" r="1"></circle>
|
||||
<path d="M4 4a16 16 0 0 1 16 16"></path>
|
||||
<path d="M4 11a9 9 0 0 1 9 9"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</nav>
|
||||
</section>
|
||||
|
||||
<section class="sidebar-card sidebar-card--tight">
|
||||
<div class="sidebar-card__header">
|
||||
<h2>Recommended</h2>
|
||||
<span class="sidebar-card__action">↗</span>
|
||||
<section class="px-4 sm:px-5 py-4 sm:py-5 xl:pr-1 flex flex-col gap-1.5 border-b border-brd">
|
||||
<div class="flex items-center justify-between gap-2 mb-2">
|
||||
<h2 class="uppercase font-medium text-xs text-typ-tone">Recommended</h2>
|
||||
<button class="text-sm font-medium flex items-center gap-1 rounded-btn group bg-bgr text-typ hover:text-typ-tone cursor-pointer gh-portal-close">↗</button>
|
||||
</div>
|
||||
<ul class="recommended-list">
|
||||
<ul class="flex flex-col gap-1 rounded-theme overflow-hidden">
|
||||
{{#get "posts" filter="featured:true" limit="3" include="tags"}}
|
||||
{{#foreach posts}}
|
||||
<li><a href="{{url}}">{{title}}</a></li>
|
||||
<li><a href="{{url}}" class="py-1 text-[0.8rem] leading-tight flex items-center gap-2 hover:opacity-75">{{title}}</a></li>
|
||||
{{/foreach}}
|
||||
{{else}}
|
||||
<li><a href="{{@site.url}}">{{@site.title}}</a></li>
|
||||
<li><a href="{{@site.url}}" class="py-1 text-[0.8rem] leading-tight flex items-center gap-2 hover:opacity-75">{{@site.title}}</a></li>
|
||||
{{/get}}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="sidebar-card sidebar-card--about">
|
||||
<p>{{@site.title}} is a thoughtfully designed Ghost theme inspired by editorial communities, with flexible settings that let you shape it to your publication.</p>
|
||||
<section class="px-4 sm:px-5 py-4 sm:py-5 xl:pr-1 flex flex-col gap-2.5 border-b border-brd">
|
||||
<p class="text-sm white-space: pre-wrap;">{{@site.title}} is a thoughtfully designed Ghost theme inspired by editorial communities, with flexible settings that let you shape it to your publication.</p>
|
||||
<a class="button button--accent" href="{{@site.url}}">About {{@site.title}}</a>
|
||||
</section>
|
||||
|
||||
{{#is "post"}}
|
||||
{{#post}}
|
||||
<section class="sidebar-card sidebar-card--tight">
|
||||
<div class="sidebar-card__header">
|
||||
<h2>Read next</h2>
|
||||
<section class="px-4 sm:px-5 py-4 sm:py-5 xl:pr-1 flex flex-col gap-1.5 border-b border-brd">
|
||||
<div class="flex items-center justify-between gap-2 mb-1">
|
||||
<h2 class="uppercase font-medium text-xs text-typ-tone">Read next</h2>
|
||||
</div>
|
||||
<ul class="recommended-list">
|
||||
<ul class="flex flex-col gap-0.5 rounded-theme overflow-hidden">
|
||||
{{#get "posts" filter=(concat "id:-" id) limit="4"}}
|
||||
{{#foreach posts}}
|
||||
<li><a href="{{url}}">{{title}}</a></li>
|
||||
<li class="style-none"><a href="{{url}}" class="py-1 text-[0.8rem] leading-tight flex items-center gap-2 hover:opacity-75"><h3 class="font-medium line-clamp-1 text-ellipsis overflow-hidden">{{title}}</h3></a></li>
|
||||
{{/foreach}}
|
||||
{{/get}}
|
||||
</ul>
|
||||
</section>
|
||||
{{/post}}
|
||||
{{/is}}
|
||||
|
||||
<footer class="copyright">©{{date format="YYYY"}} {{@site.title}}. Published with Ghost.</footer>
|
||||
</div>
|
||||
<span class="md:flex-1"></span>
|
||||
<footer class="px-5 sm:px-6 xl:pr-1">
|
||||
<div class="py-3 flex flex-col items-start justify-start text-typ-tone text-xs">
|
||||
©{{date format="YYYY"}} {{@site.title}}. Published with Ghost.
|
||||
</div>
|
||||
</footer>
|
||||
</aside>
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
<header class="topbar">
|
||||
<div class="topbar__inner">
|
||||
<div class="topbar__brand flex items-center gap-3">
|
||||
<button class="topbar__sidebar-toggle" type="button" data-left-sidebar-toggle aria-expanded="true" aria-label="Toggle left sidebar">
|
||||
<header class="topbar border-b border-brd bg-bgr/95 supports-[backdrop-filter]:bg-bgr/80">
|
||||
<div class="topbar__inner mx-auto">
|
||||
<div class="topbar__brand flex h-full items-center gap-3 px-4">
|
||||
<button class="topbar__sidebar-toggle inline-flex items-center justify-center rounded-theme hover:bg-bgr-tone" type="button" data-left-sidebar-toggle aria-expanded="true" aria-label="Toggle left sidebar">
|
||||
<img class="topbar__sidebar-toggle-icon topbar__sidebar-toggle-icon--open" src="{{asset "icons/left_panel_open.svg"}}" alt="">
|
||||
<img class="topbar__sidebar-toggle-icon topbar__sidebar-toggle-icon--close" src="{{asset "icons/left_panel_close.svg"}}" alt="">
|
||||
</button>
|
||||
<a class="brand brand--topbar" href="{{@site.url}}">
|
||||
<a class="brand brand--topbar inline-flex items-center gap-2.5 whitespace-nowrap" href="{{@site.url}}">
|
||||
<span class="brand__name">{{@site.title}}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="topbar__search">
|
||||
<button class="search-trigger" type="button" data-search-open aria-label="Open search">
|
||||
<div class="topbar__search flex h-full items-center justify-center px-4">
|
||||
<button class="search-trigger flex w-full max-w-xs items-center gap-2.5 rounded-xl border border-brd bg-bgr px-3.5 py-2 text-sm text-typ-tone transition-colors hover:bg-bgr-tone hover:text-typ" type="button" data-search-open aria-label="Open search">
|
||||
<img class="search-trigger__icon" src="{{asset "icons/search.svg"}}" alt="">
|
||||
<span>Search</span>
|
||||
<span class="search-shortcut">/</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="topbar__actions flex items-center justify-end gap-2">
|
||||
<button class="icon-button icon-button--search-mobile" type="button" data-search-open aria-label="Open search">
|
||||
<div class="topbar__actions flex h-full items-center justify-end gap-2 px-4">
|
||||
<button class="icon-button icon-button--search-mobile inline-flex items-center justify-center rounded-theme border border-brd bg-bgr hover:bg-bgr-tone" type="button" data-search-open aria-label="Open search">
|
||||
<img class="search-trigger__icon" src="{{asset "icons/search.svg"}}" alt="">
|
||||
</button>
|
||||
{{#if @custom.show_admin_link}}
|
||||
<a class="button button--accent" href="/ghost/">Admin</a>
|
||||
<a class="icon-button icon-button--profile" href="/ghost/" aria-label="Ghost admin"><span></span></a>
|
||||
<a class="button button--accent rounded-theme" href="/ghost/">Admin</a>
|
||||
<a class="icon-button icon-button--profile rounded-full border border-brd bg-bgr hover:bg-bgr-tone" href="/ghost/" aria-label="Ghost admin"><span></span></a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -33,10 +33,10 @@
|
||||
<div class="search-modal__panel">
|
||||
<div class="search-modal__input">
|
||||
<button type="button" class="icon-button icon-button--plain" data-search-close aria-label="Close search">×</button>
|
||||
<input type="search" placeholder="Search posts, tags and authors" data-search-input>
|
||||
<input type="search" placeholder="게시물, 태그, 작성자 검색" data-search-input>
|
||||
</div>
|
||||
<div class="search-modal__body" data-search-results>
|
||||
<p class="search-modal__hint">Start typing to filter visible posts, tags, and authors in the current page.</p>
|
||||
<p class="search-modal__hint">현재 페이지에 표시되는 게시물, 태그 및 작성자를 필터링하려면 입력을 시작하세요.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
43
post.hbs
43
post.hbs
@@ -28,7 +28,10 @@
|
||||
</div>
|
||||
|
||||
<button data-post-share-toggle class="absolute bottom-4 right-0 flex gap-1 items-center hover:opacity-75 cursor-pointer" type="button" aria-label="Share this post">
|
||||
<img class="size-4 pointer-events-none" src="{{asset "icons/arrow_outward.svg"}}" alt="">
|
||||
<i class="icon icon-share size-4 stroke-2 pointer-events-none" role="presentation">
|
||||
<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" class="icon icon-tabler icons-tabler-outline icon-tabler-share-3"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M13 4v4c-6.575 1.028 -9.02 6.788 -10 12c-.037 .206 5.384 -5.962 10 -6v4l8 -7l-8 -7"></path></svg>
|
||||
</i>
|
||||
{{!-- <img class="size-4 pointer-events-none" src="{{asset "icons/arrow_outward.svg"}}" alt=""> --}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -45,9 +48,9 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
<article class="post-article {{post_class}}">
|
||||
<article class="post-article pt-4 px-5 sm:px-[max(2vmin,20px)] mb-12 {{post_class}}">
|
||||
|
||||
<div class="post-body px-4 sm:px-[max(2vmin,20px)]">
|
||||
{{!-- <div class="post-body px-4 sm:px-[max(2vmin,20px)]"> --}}
|
||||
<section class="post-content kg-content ghost-content prose prose-theme">
|
||||
{{content}}
|
||||
</section>
|
||||
@@ -60,37 +63,23 @@
|
||||
</section>
|
||||
{{/unless}}
|
||||
|
||||
<footer class="post-footer">
|
||||
{{#primary_author}}
|
||||
<div class="author-inline-card">
|
||||
{{#if profile_image}}
|
||||
<img class="avatar" src="{{img_url profile_image size="xs"}}" alt="{{name}}">
|
||||
{{else}}
|
||||
<div class="avatar avatar--fallback">A</div>
|
||||
{{/if}}
|
||||
<div>
|
||||
<h3>{{name}}</h3>
|
||||
{{#if bio}}<p>{{bio}}</p>{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/primary_author}}
|
||||
</footer>
|
||||
</div>
|
||||
{{!-- </div> --}}
|
||||
</article>
|
||||
|
||||
{{> "post/post-navigation"}}
|
||||
|
||||
<section class="discussion-panel">
|
||||
<section class="px-5 sm:px-6 mb-6 border-y py-5 border-brd scroll-mt-14 bg-bgr-tone">
|
||||
{{#if comments}}
|
||||
{{comments title="Comments" count=true}}
|
||||
{{else}}
|
||||
<div class="comments-empty">
|
||||
<h3>Join the discussion</h3>
|
||||
<p>Become a member of {{@site.title}} to start commenting.</p>
|
||||
<a class="button" href="#/portal/signup">Sign up now</a>
|
||||
<p>Already a member? <a href="#/portal/signin">Sign in</a></p>
|
||||
<div class="flex flex-col items-center py-6 sm:px-8 sm:py-10">
|
||||
<h3 class="mb-[8px] text-center font-sans text-2xl tracking-tight text-black font-bold">Join the discussion</h3>
|
||||
<p class="mb-[28px] w-full px-0 text-center font-sans text-lg leading-normal text-neutral-600 sm:max-w-screen-sm sm:px-8">Become a member of <span class="font-semibold">{{@site.title}}</span> to start commenting.</p>
|
||||
<a class="text-md mb-[12px] inline-block rounded px-5 py-[14px] font-sans font-medium leading-none text-white transition-all hover:opacity-90 bg-orange-600" href="#/portal/signup">Sign up now</a>
|
||||
<p class="text-md text-center font-sans text-[rgba(0,0,0,0.4)]"><span class="mr-1 inline-block text-[15px]">Already a member?</span> <a href="#/portal/signin" class="rounded-md text-sm text-orange-600 font-semibold transition-all hover:opacity-90">Sign in</a></p>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
|
||||
{{> "post/post-navigation"}}
|
||||
|
||||
</main>
|
||||
{{/post}}
|
||||
|
||||
20
tag.hbs
20
tag.hbs
@@ -1,15 +1,15 @@
|
||||
{{!< default}}
|
||||
|
||||
{{#tag}}
|
||||
<main class="content-area">
|
||||
<section class="stack-section">
|
||||
<header class="section-header">
|
||||
<h1 class="section-title">{{name}}</h1>
|
||||
{{#if description}}
|
||||
<p class="section-description">{{description}}</p>
|
||||
{{/if}}
|
||||
</header>
|
||||
<main class="flex-2 max-w-content">
|
||||
<section class="px-5 sm:px-6 pt-4 sm:pt-5">
|
||||
<div class="max-w-content mx-auto flex flex-col items-center sm:flex-row gap-4 justify-between border-b border-brd pb-4 sm:pb-5">
|
||||
<div class="flex-3 flex flex-col gap-1">
|
||||
<h1 class="text-lg sm:text-xl font-medium leading-tight">{{name}}</h1>
|
||||
{{#if description}}
|
||||
<p class="text-sm text-typ-tone max-w-lg text-balance">{{description}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{> "lists/post-feed"}}
|
||||
</section>
|
||||
</main>
|
||||
{{/tag}}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<ul class="tag-directory max-w-site mx-auto gap-4 sm:gap-5 grid sm:grid-cols-2 lg:grid-cols-3">
|
||||
{{#foreach tags}}
|
||||
<li class="tag-directory__item h-full" data-tag-card="{{slug}}">
|
||||
<a class="tag-directory__card relative h-full flex flex-col gap-2 p-4 border border-brd rounded-theme border-l-[3px] border-l-[var(--color-accent)] rounded-l-none hover:bg-[color-mix(in_srgb,var(--color-accent)_5%,transparent)] hover:border-[color-mix(in_srgb,var(--color-accent)_25%,var(--border))] hover:border-l-[var(--color-accent)]" href="{{url}}"{{#if accent_color}} style="--color-accent: {{accent_color}};"{{else}} style="--color-accent: var(--accent);"{{/if}}>
|
||||
<a class="tag-directory__card relative h-full flex flex-col gap-2 p-4 border border-brd rounded-r-lg border-l-[3px] border-l-transparent rounded-l-none hover:bg-[color-mix(in_srgb,var(--color-accent)_10%,transparent)]" href="{{url}}"{{#if accent_color}} style="--color-accent: {{accent_color}}; border-left-color: var(--color-accent);"{{/if}}>
|
||||
<h2 class="text-sm font-medium leading-tight flex items-center justify-between gap-1">{{name}}</h2>
|
||||
<i class="icon icon-arrow-up-right size-4 stroke-2 absolute top-4 right-4" role="presentation">
|
||||
<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">
|
||||
|
||||
Reference in New Issue
Block a user