Blog

Ghost CMS. Podstawy Tworzenia Własnego Tematu. Odsłona Druga

Kolejna część tutoriala, w którym staram się przedstawić zasady rządzące budową własnego tematu dla Ghost CMS.

Ghost CMS. Podstawy Tworzenia Własnego Tematu. Odsłona Druga

Dzisiejsze ćwiczenie zaczniemy od czegoś relatywnie prostego, czyli od utworzenie szablonu dla statycznej strony, która zawierać będzie informacje o naszej skromnej osobie. Oczywiście w tym konkretnym wypadku chodzi o skopiowanie zawartości dostępnej dla motywu Clean Blog (dalej CBT), z którym cały czas pracujemy. W tym celu otwieramy w naszym ulubionym edytorze plik about.hbs i wklejamy następujący fragment kodu:

{{!< default}}
 
<header class="masthead" style="background-image: url('{{asset 'img/about-bg.jpg'}}')">
   <div class="overlay"></div>
   <div class="container">
     <div class="row">
       <div class="col-lg-8 col-md-10 mx-auto">
         <div class="page-heading">
           <h1>About Me</h1>
           <span class="subheading">This is what I do.</span>
         </div>
       </div>
     </div>
   </div>
 </header>
 
 <!-- Main Content -->
 <div class="container">
   <div class="row">
     <div class="col-lg-8 col-md-10 mx-auto">
       <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Saepe nostrum ullam eveniet pariatur voluptates odit, fuga atque ea nobis sit soluta odio, adipisci quas excepturi maxime quae totam ducimus consectetur?</p>
       <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eius praesentium recusandae illo eaque architecto error, repellendus iusto reprehenderit, doloribus, minus sunt. Numquam at quae voluptatum in officia voluptas voluptatibus, minus!</p>
       <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aut consequuntur magnam, excepturi aliquid ex itaque esse est vero natus quae optio aperiam soluta voluptatibus corporis atque iste neque sit tempora!</p>
     </div>
   </div>
 </div>
 
 <hr>

Zwracam uwagę na znajdujący się na samej górze znacznik {{!< default}}, dzięki któremu wskazujemy, z którego szablonu nadrzędnego chcemy skorzystać. Reszta to rzecz jasna odpowiednio wycięta część kodu z przykładowego motywu, którym się podpieramy w naszym projekcie. 

W tym momencie wreszcie możemy odpalić nasze temat i powinniśmy wówczas cokolwiek móc zobaczyć, ale zanim to zrobimy należy jeszcze zmodyfikować plik routes.yaml, który znajduje się w nazwa_projektu/content/setting. Otwieramy go w edytorze i następnie w sekcji routes, która nie powinna mieć na ten moment żadnych wpisów, dodajemy nazwę ścieżki i po dwukropku plik szablonu, do którego powinna się ona odwoływać (pomijamy przy tym rozszerzenie hbs). Całość powinna wyglądać jak niżej:

routes:
 /about/: about
 
 
collections:
 /:
   permalink: /{slug}/
   template: index
 
taxonomies:
 tag: /tag/{slug}/
 author: /author/{slug}/

Zapisujemy zmiany i zamykamy plik, a następnie startujemy naszą instancję Ghost wisująć w konsoli ghost start (musimy być w katalogu głównym projektu). Następnie przechodzimy pod link http://localhost:2368/ghost/. Przy pierwszym logowaniu zostaniemy poproszeni o podanie nazwy i hasła (z tego co pamiętam). Tym właśnie sposobem mamy dostęp do naszego panelu.

Zacznijmy od załadowania naszego motywu. Wymaga to wybrania sekcji Desing w obszarze SETTINGS, gdzie na dole powinny się pojawić wszystkie dostępne lokalnie tematy. Na ten moment aktywny powinien być domyślny motyw, czyli Casper. My oczywiście wybieramy ten przez nas przygotowany i klikamy przycisk “ACTIVATE”. Tym sposobem załaduje się nasz temat, choć przy okazji zapewne Ghost poinformuje nas o kilku błędach związanych z brakiem pewnych elementów. Na ten moment możemy się tym nie przejmować, ale przy okazji tworzenie szablonu odpowiedzialnego za wyświetlenie pojedynczego posta trzeba będzie temu zaradzić. W tej chwili jednak, ponieważ znajdujemy się nadal w sekcji “Desing”, zmodyfikujemy ustawienia naszej nawigacji, tak by finalnie wyglądała jak niżej.

Pozycja Help odwołuje się do strony z dokumentacją dla Ghost. Oczywiście w ramach uznania możemy ją usunąć, ale bez niej nasza nawigacja wyglądała będzie raczej dość biednie, stąd moja decyzja, by ją zostawić.

W tym momencie możemy podziwiać naszą witrynę, ale niestety nie uświadczymy na niej najważniejszego, czyli naszych wpisów blogowych. I dalsza część dzisiejszej odsłony w całości skupi się na tej kwestii.

Tworzenie karty dla wpisów

Na początek zajmiemy się tym, by strona główna zawierała listę czy właściwie zestawienie ostatnio opublikowanych postów. Przy tworzeniu pliku package.json ustawiliśmy, że będzie to liczba 10 postów per strona. Domyślnie Ghost instaluje się zaledwie z 7 spreparowanymi wpisami, więc na ten moment może tak to zostać. 

Ponieważ nie interesuje nas – a przynajmniej mnie osobiście – prosta lista następujących po sobie wpisów, w celu nadania bardziej profesjonalnej formy przygotujemy siatkę kart będących odnośnikami do odpowiednich tekstów. W tym celu w katalogu partials tworzymy nowy plik, który będzie odpowiadał za wygenerowanie karty dla naszego blogowego wpisu. Nazwiemy go blog-post.hbs. Oczywiście z powodu lenistwa i ograniczonych zdolności skorzystamy z gotowego komponentu, spośród tych dostępnych na stronie, z której wcześniej pobraliśmy cały temat, a następnie w odpowiedni ją podrasujemy pod reguły rządzące Ghost. Całość powinna wyglądać jak niżej, zaś dalej wyjaśniam, o co w tym wszystkim chodzi.

 <div class="col-md-4">
   <div class="card equal mb-4">
     <img class="card-img-top"
       src="{{img_url feature_image size="m"}}"
       alt="{{title}}">
     <div class="card-body">
       <h2 class="card-title">{{title}}</h2>
       <p class="card-text">{{excerpt words="25"}}</p>
       <a href="{{url}}" class="btn btn-primary">Read more</a>
     </div>
   </div>
 </div>

W tym szablonie wykorzystujemy kilka tagów, które Ghost udostępnia dla kontekstu “post”. Jakby ktoś chciał bardziej pogłębić ten temat, to zapraszam do lektury dokumentacji na oficjalnej stronie projektu.

Ja w tym miejscu pozwolę sobie przytoczyć listę wszystkich “obiektów” jakie są w tym zakresie, ze szczególnym wyróżnieniem, tych których używaliśmy przed momentem.

{
 "name": "borciu(du)szek",
 "description": "Przykładowy temacik od mości Borciugnera",
 "version": "0.0.1",
 "engines": {
     "ghost-api": "v3"
 },
 "license": "MIT",
 "author": {
     "email": "borciugner@gmail.com"
 },
 "config": {
     "posts_per_page": 10,
     "image_sizes": {
       "xxs": {
           "width": 30
       },
       "xs": {
           "width": 100
       },
       "s": {
           "width": 300
       },
       "m": {
           "width": 600
       },
       "l": {
           "width": 1000
       },
       "xl": {
           "width": 2000
       }
   }
 }
}

W tym momencie jedyne co nam zostaje to odpowiednio zmodyfikować plik index.hbs poprzez dodanie odpowiedniej pętli, która wyświetli listę tych postów w formie siatki. Do tego celu użyjemy znaną nam strukturę “foreach”. Całość wyglądała będzie bardzo prosto, czyli najpierw umieszczamy nagłówek z pliku index.html dla wcześniej pobranego tematu CBT, a potem dopisujemy prostą pętlę, która dla każdego wpisu (a ściślej ostatnich 10-ciu) wyświetli odpowiednia skonstruowaną kartę na bazie szablonu blog-post.hbs.

{{!< default}}
 
<!-- Page Header -->
 <header class="masthead" style="background-image: url('{{asset 'img/home-bg.jpg'}}')">
   <div class="overlay"></div>
   <div class="container">
     <div class="row">
       <div class="col-lg-8 col-md-10 mx-auto">
         <div class="site-heading">
           <h1>Clean Blog</h1>
           <span class="subheading">A Blog Theme by Start Bootstrap</span>
         </div>
       </div>
     </div>
   </div>
 </header>
 
 <div class="row">
               {{#foreach posts}}
                 {{> "blog-post"}}
              {{/foreach}}
 </div>

Tym sposobem mamy dwie funkcjonalne strony, przy czym jedna z nich to statyczna treść umieszczona wprost w jednym z szablonów (about), a druga prezentuje dynamicznie generowaną zawartość na bazie już utworzonych wpisów blogowych. Niestety w przypadku tych ostatnich nadal nie zobaczymy całości posta, ponieważ nie przygotowaliśmy jeszcze szablonu odpowiedzialnego za renderowanie widoków dla poszczególnych tekstów. Łatwo się o tym przekonać klikając na przycisk “Read more”. Zaradzić się temu postaramy jednak przy okazji kolejnej odsłony niniejszego cyklu.