Önceki bölümü okumadan buraya geldiyseniz hiç kasmayın geri dönün
- ORTA SEVİYE BİR RAİLS TUTORIAL - 1 (Kurulum, ilk stiller)
- ORTA SEVİYE BİR RAİLS TUTORIAL - 2 (Kullanıcı girişi - Bootstrap CSS)
- ORTA SEVİYE BİR RAİLS TUTORIAL - 3 (Blog altyapısı)
JavaScript Stiller
Ana sayfamız hala sade bir görüntüye sahip. Biraz kontrast yaratmak için gönderileri renklendireceğiz. Fakat CSS yardımıyla sabit renk vermek yerine sayfa her yenilendiğinde başka renk paterni alması için JavaScript kullanacağız (ki öğrenmiş olalım).
assets
klasörü altındaki javascripts
klasörü içine posts
adında bir alt klasör ekleyelim ve içine style.js
adında bir yeni dosya ekleyelim. Ayrıca javascripts
klasöründeki default .coffee
dosyalarını da silebiliriz çünkü kullanmayacağız.
app/assets/javascripts/posts/style.js
$(document).on("turbolinks:load", function() { if ($(".single-post-card").length) { // arkaplana sabit renk if (mode == 1) { $(".single-post-card").each( function() { $(this).addClass("solid-color-mode"); $(this).css("background-color", randomColor()); }); } // etraf çizgi rengi stili else { $(".single-post-card").each( function() { $(this).addClass("border-color-mode"); $(this).css("border", "5px solid" + randomColor()); }); } } $(#feed).on("mouseenter", ".single-post-list", function() { $(this).css("border-color", randomColor()); }); $(#feed).on("mouseleave", ".single-post-list", function() { $(this).css("border-color", "rgba(0,0,0, 0.05)"); }); }); var colorSet = randomColorSet(); var mode = Math.floor(Math.random() * 2); // Rastgele bir renk şeması döner function randomColorSet() { var colorSet1 = ["#45ccff", "#49e83e", "#ffd432", "#e84830", "#8243ff"]; var colorSet2 = ['#FF6138', '#FFFF9D', '#BEEB9F', '#79BD8F', '#79BD8F']; var colorSet3 = ['#FCFFF5', '#D1DBBD', '#91AA9D', '#3E606F', '#193441']; var colorSet4 = ['#004358', '#1F8A70', '#BEDB39', '#FFE11A', '#FD7400']; var colorSet5 = ['#105B63', '#FFFAD5', '#FFD34E', '#DB9E36', '#BD4932']; var colorSet6 = ['#04BFBF', '#CAFCD8', '#F7E967', '#A9CF54', '#588F27']; var colorSet7 = ['#405952', '#9C9B7A', '#FFD393', '#FF974F', '#F54F29']; var randomSet = [colorSet1, colorSet2, colorSet3, colorSet4, colorSet5, colorSet6, colorSet7]; return randomSet[Math.floor(Math.random() * randomSet.length)]; } // bir renk şemasından rastgele renk döner function randomColor() { var color = colorSet[Math.floor(Math.random() * colorSet.length)]; return color; }
Not: Sayfayı yenilediğinizde renklenme olmadıysa jQuery en başta yüklenmemiş olabilir.
application.js
içinde jQuery çağıran satırı en önceye alın, aşağıdaki gibi.
//= require jquery
//= require rails-ujs
//= require turbolinks
//= require_tree .
//= require bootstrap-sprockets
Yukarıdaki koda kısaca bakarsak, her sayfa yenilenişinde iki değişik renklendirme modundan biri seçiliyor. Stilin birinde sadece sınır çizgileri renkleniyor, diğerinde gönderi komple renkleniyor.mouseenter
ve mouseleave
işleyicileri ise daha sonra kullanılacak, ana sayfadan farklı gönderi gösterimleri olacak, onlarda alttaki sınır çizgi rengi yavaşça değişecek.
posts.scss
dosyasını açalım ve birkaç stil ekleyelim.
app/assets/stylesheets/partials/posts.scss
... .solid-color-mode, .border-color-mode { .post-text { text-align: center; } } .solid-color-mode { .post-text { padding: 10px; background-color: white; border-radius: 25px; } } .border-color-mode { background-color: white; }
Ayrıca
mobile.scss
içine uzun yazıların sıkıntısı için şunu ekleyelim
app/assets/stylesheets/responsive/mobile.scss
... @media screen and (max-width: 767px) { .solid-color-mode, .border-color-mode { .post-text { font-size: 16px; } } }
Ana sayfayı yeniledikçe şimdi şunlara benzer görüntüler alacağız.
Modal penceresi
Sayfadaki gönderilerden birine tıkladığımızda başka sayfaya geçmeden gönderinin tamamını görnek istiyoruz. Bunu yapmak için Bootstrap’ın modal elemanını kullanacağız.
posts
klasörü içine _modal.html.erb
parça görseli dosyasını ekleyelim ve şu kodu yazalım:
app/views/posts/_modal.html.erb
<!-- Modal --> <div class="modal myModal" tabindex="-1" role="dialog" arialabelledby="myModalLabel"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <span class="posted-by"></span> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="loaded-data"> <h3></h3> <p></p> <div class="interested"><a href="">İlgimi çekti</a></div> </div><!-- loaded-data --> </div><!-- modal-body --> </div> </div> </div>
Bu Bootstrap dökümanından biraz değiştirilmiş bir görsel. Şimdi bunu ana sayfa görsel dosyasının en üstünde yayınlayalım.
app/views/pages/index.html.erb
<%= render "posts/modal" %> ...
Bu modal pencerenin çalışması için biraz JavaScript eklememiz gerekiyor.
posts
klasörü içinde modal.js
adında yeni bir dosya ekleyelim ve içine şunları yazalım:
app/assets/javascripts/posts/modal.js
$(document).on("turbolinks:load", function() { // gönderi tıklandığında tüm içeriğini modal pencerede göster $("body").on("click", ".single-post-card, .single-post-list", function() { var posted_by = $(this).find(".post-content .posted-by").html(); var post_heading = $(this).find(".post-content h3").html(); var post_content = $(this).find(".post-content p").html(); var interested = $(this).find(".post-content .interested").attr("href"); $(".modal-header .posted-by").text(posted_by); $(".loaded-data h3").text(post_heading); $(".loaded-data p").text(post_content); $(".loaded-data .interested a").attr("href", interested); $(".myModal").modal("show"); }); });
Sayfaya daha önce koyduğumuz sonra CSS ile görünmez yaptığımız verileri önce değişkenlere alıyoruz. Sonra modal penceresinde ait oldukları tere koyuyoruz. En son olarak da modal penceresini görünür yapıyoruz.
Modal pencerenin stilini biraz değiştireceğiz. Ama önce biraz düzenleme yapalım. Stillerin içindeki
partials
klasöründe posts
adında bir alt klasör tanımlayalım. posts
klasörü altında bir home_page.scss
dosyası yapalım ve daha önce posts.scss
içine yazdığımız tüm stil kodlarını buraya kopyalayıp eski posts.scss
dosyasını silelim. Kafa karışmaması için bu daha düzenli olacak.
posts
klasörü içine modal.scss
dosyasını ekleyelim ve içine şu kodu yazalım:
app/assets/stylesheets/partials/posts/modal.scss
.modal-content { h3 { text-align: center; } p { margin: 50px 0; } .posted-by { color: rgba(0,0,0, 0.5); } } .modal-content { .loaded-data { h3, p { overflow: hidden; } padding: 0 10px; .posted-by { margin: 0; } } } .interested { text-align: center; a { background-color: $navbarColor; padding: 10px; color: white; border-radius: 10px; &:hover { background-color: black; color: white; } } }
Tabii bu dosyaları
application.scss
içinde import etmemiz gerekiyor.
app/assets/stylesheets/application.scss
... // Parça dosyalar @import "partials/*"; @import "partials/layout/*"; @import "partials/posts/*"; ...
Modal pencere artık böyle görünüyor:
Tek Gönderi Gösterimi
Eğer
İlgimi çekti
düğmesine tıklarsak bir hata mesajı alırız. Henüz show.html.erb
görsel kalıbını oluşturmadık. Ayrıca PostController
içinde show
aksiyonunu da tanımlamadık.
PostController
içinde show
aksiyonunu tanımlayalım ve içine istenen gönderiyi seçen bir kod yazalım.
app/controllers/posts.controller.rb
class PostsController < ApplicationController def show @post = Post.find(params[:id]) end end
İlgimi çekti
butonu tıklayınca bizi /posts/1
adresi benzeri bir adrese gönderdi. Bu bir GET işlemi olduğu için PostController
kontrolörünün show
aksiyonuna id
parametre değeri 1
olarak yönlendirir. Nereden mi biliyoruz? Konsolda
rails routes
yazınca yollardan biri aynen şunu yazıyorpost GET /posts/:id(.:format) posts#show
Şimdi posts
klasörü altında show.html.erb
görsel kalıp dosyasını oluşturalım ve içine şu kodu yazalım:
app/views/posts/show.html.erb
<div id="single-post-content" class="container"> <div class="row"> <div class="col-sm-6 col-sm-offset-3"> <div class="posted-by">Posted by <%= @post.user.name %></div> <h3><%= @post.title %></h3> <p><%= @post.content %></p> </div> </div><!-- row --> </div>
Bu sayfa için bir de stil sayfası oluşturalım.
app/assets/stylesheets/partials/posts/show.scss
#single-post-content { background: white; height: calc(100vh - 50px); h3 { text-align: center; } p { margin: 50px 0; } .posted-by { font-size: 12px; font-size: 1.2rem; margin: 20px 0; color: rgba(0,0,0, 0.5); } }
Burada
100vh - 50px
hesabıyla tüm görünen alan yüksekliğinden 50 piksel düşük bir yükseklik ifade ediliyor. Niye 50 piksel? Çünkü daha önce içerik gezinti bar altında kalmasın diye 50 piksel aşağı kaydırmıştık. Eğer sadece 100vh deseydik tüm yükseklikten aşağı kaymış olacaktık ve içerik sayfayı doldurmamış olsa bile yanda scroll bar çıkacaktı. Bu stil ile içerik kısa da olsa tüm sayfa arka plan rengini beyaz yapıyoruz.
Daha sonra görsel dosyamıza başka özellikler de ekleyeceğiz.
Özel Kolleksiyonlar
Ana Sayfa kenar menüsü
index.html.erb
görselinde kenarda bu kolleksiyonlara ait linkler yerleştirerek başlayalım.
#side-menu
elemanı içine linkleri yerleştireceğiz. Ortalık karışmasın diye #side-menu
ve #main-content
elemanlarını kesip ayrı parça görseller içine yerleştirelim. pages
klasörü altında index
adında bir alt klasör oluşturalım ve içine şu parça görselleri koyalım:
app/views/pages/index/_side_menu.html.erb
<div id="side-menu" class="col-sm-3"> </div><!-- sol kenar menü -->
app/views/pages/index/_main_content.html.erb
<div id="main-content" class="col-sm-9"> <%= render @posts %> </div><!-- ana içerik -->
Şimdi ana sayfa görselinde bu parça görselleri yayınlayalım.
app/views/pages/index.html.erb
<%= render "posts/modal" %> <div class="container"> <div class="row"> <%= render "pages/index/side_menu" %> <%= render "pages/index/main_content" %> </div><!-- row --> </div><!-- container -->
Kenar menü görseli içine yeni linkler ekleyelim.
app/views/pages/index/_side_menu.html.erb
<div id="side-menu" class="col-sm-3"> <ul id="links-list"> <%= render "/pages/index/side_menu/no_login_required_links" %> </ul> </div><!-- sol kenar menü -->
Sırasız bir liste ekledik ve liste içinde de başka bir parça görsel çağırdık. Bunlar kullanıcı girişi yapmadan tüm kullanıcıların görebileceği sayfalara olan linkler. Parça görsel dosyasını oluşturalım ve içine linkleri ekleyelim.
index
klasöründe side_menu
adında bir alt klasör oluşturalım ve içine _no_login_required_links.html.erb
dosyasını koyalım.
app/views/pages/index/side_menu/_no_login_required_links.html.erb
<li id="hobby"> <%= link_to hobby_posts_path do %> <i class="fa fa-user-circle-o" aria-hidden="true"></i> Bir hobi arkadaşı bulun <% end %> </li> <li id="study"> <%= link_to study_posts_path do %> <i class="fa fa-graduation-cap" aria-hidden="true"></i> Bir çalışma arkadaşı bulun <% end %> </li> <li id="team"> <%= link_to team_posts_path do %> <i class="fa fa-users" aria-hidden="true"></i> Bir takım üyesine ulaşın <% end %> </li>
Gönderilerin özel kolleksiyonları için linkler ekledik.
hobby_posts_path
değişkeni nasıl tanımlandı? routes.rb
içinde resources :posts
standart link listesine ilaveten bu 3 linki de tanımlamıştık hatırlarsanız.
i
elemanının özelliklerine bakarsak fa
sınıf dikkatimizi çeker. Bu sınıf ile Font Awesome ikonlarını deklare ediyoruz. Henüz bu kütüphaneyi eklemedik, ama çok kolay. Ana görsel yerleşimi olan application.html.erb
dosyasında head
elemanı içine şu satırı ekleyelim:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
Kenar menü artık şöyle görünecek:
767 ve 1000 piksel arası genişlikte olan ekranlarda Bootstrap container çok sıkışık görünüyor (yanlarda boş bantlar sıkıştırıyor). bunu düzenlemek için
mobile.scss
dosyası içine şu tanımı da ekleyelim:
app/stylesheets/responsive/mobile.scss
... @media only screen and (min-width: 767px) and (max-width: 1000px) { .container { width: 100% !important; } }
Kolleksiyon sayfası
Eğer kenar menüde linklerden birine tıklarsak bir hata mesajı alırız. Ne
PostController
içinde aksiyon tanımladık ne de bir görsel kalıbımız var. PostController
içinde hobby
, study
ve team
aksiyonlarını tanımlayalım:
app/controllers/posts_controller.rb
... def hobby posts_for_branch(params[:action]) end def study posts_for_branch(params[:action]) end def team posts_for_branch(params[:action]) end end
Her aksiyon içinde
posts_for_branch
metodu çağırılıyor. Bu metod aksiyon ismine göre sayfaya özel kayıtları dönecek. Bu metodu private
bölümünde tanımlayalım.
app/controllers/posts_controller.rb
... private def posts_for_branch(branch) @categories = Category.where(branch: branch) @posts = get_posts.paginate(page: params[:page]) end end
@categories
oluşum değişkeni belirtilen kolleksiyona ait kategorileri içeriyor. Gönderileri @posts
oluşum değişkenine koymak için get_posts
metodu kullanılıyor ve sonra paginate
metodu ile düzenleniyor. paginate
metodu will paginate gem’inden geliyor. PostController
içindeki private
bölümünde get_posts
metodunu tanımlayarak başlayalım:
app/controllers/posts_controller.rb
... def get_posts Post.limit(30) end ...
Metod şu anda sadece sıradan 30 tane kaydı alıyor. Daha ileride bunu geliştirebiliriz. Yakında bu metoda geri dönecğiz.
Pagination için az evvel bahsi geçen gem’i Gemfile’a ekleyelim
gem "will_paginate", "~> 3.1.0"
tabii ki arkasındanbundle
Geride tek eksiğimiz kaldı, görsel kalıpları. Tüm kolleksiyonlarda görseller birbirine benzeyecek. Kod tekrarlamak yerine ortak olan kısmı bir parça görsel içine alalım. posts
klasörü içinde _branch.html.erb
dosyası tanımlayıp içine şunları yazalım:
app/views/posts/_branch.html.erb
<div id="branch-main-content" class="container"> <div class="row"> <h1 class="page-title"><%= page_title %></h1> <%= render "posts/branch/create_new_post", branch: branch %> </div><!-- row --> <div class="row"> <%= render "posts/branch/categories", branch: branch %> </div> <div class="row"> <div class="col-sm-12" id="feed"> <%= render @posts %> <%= render no_posts_partial_path %> </div> </div><!-- row --> <div class="infinite-scroll"> <%= will_paginate @posts %> </div> </div><!-- container -->
Başta
page_title
adında bir değişken var. Bunu diğer görsellerden _branch.html.erb
parça görselini yayınlarken belirleyeceğiz. Sonrasında kullanıcının yeni bir gönderi yazmasını sağlamak amacıyla _create_new_post
parça görselini kullanarak bir link vereceğiz. Şimdi bu parça görseli branch
adında yeni bir alt klasör içinde tanımlayalım ve içine şu kodu yazalım:
app/views/posts/branch/_create_new_post.html.erb
<div class="col-sm-12"> <div class="col-sm-8 col-sm-offset-2"> <%= render create_new_post_partial_path, branch: branch %> </div><!-- col-sm-8 --> </div><!-- col-sm-12 -->
Buradaki
create_new_post_partial_path
metodu hangi parça dosyanın gösterileceğine karar verecek. posts_helper.rb
yardımcılar doyası içinde metodu tanımlayalım:
app/helpers/posts_helper.rb
module PostsHelper def create_new_post_partial_path if user_signed_in? "posts/branch/create_new_post/signed_in" else "posts/branch/create_new_post/not_signed_in" end end ...
Bu iki görsel dosyasını
create_new_post
adında yeni bir alt klasör içine kodlayalım:
app/views/posts/branch/create_new_post/_signed_in.html.erb
<div class="new-post-button-parent"> <span>Kimseyi bulamadın mı? O zaman: </span> <%= link_to "Yeni gönderi oluştur", new_post_path(branch: branch), :class => "new-post-button" %> </div>
app/views/posts/branch/create_new_post/_not_signed_in.html.erb
<div class="text-center login-branch"> Yeni gönderi oluşturmak için <%= link_to "Giriş yapın", login_path, :class => "login-button login-button-branch" %> </div>
Dönelim
_branch.html.erb
dosyasına geri. Sırada _categories.html.erb
parça görselin yayınlanması var. Bu görselde kategorilerin bir listesi olacak.
app/views/posts/branch/_categories.html.erb
<% branch_path_name = "#{params[:action]}_posts_path" %> <div class="col-sm-12"> <ul class="categories-list"> <%= render all_categories_button_partial_path, branch_path_name: branch_path_name %> <% @categories.each do |category| %> <li class="category-item"> <%= link_to category.name, send(branch_path_name, category: category.name), :class => ("selected-item" if params[:category] == category.name) %> </li> <% end %> </ul> </div><!-- col-sm-12 -->
Yeni bir tanımadık metod çıktı
all_categories_button_partial_path
. Bunu da post_helper.rb
içinde yardımcı metod olarak tanımlayalım.
app/helpers/posts_helper.rb
... def all_categories_button_partial_path if params[:category].blank? "posts/branch/categories/all_selected" else "posts/branch/categories/all_not_selected" end end ...
Default olarak tüm kategoriler seçilidir. Eğer
params[:category]
parametresi yoksa kullanıcı hiç bir kategory seçmemiştir yani default olan all
seçilidir. Buna karşı gelen parça dosya şöyle:
app/views/posts/branch/categories/_all_selected.html.erb
<li class="category-item"> <%= link_to "Tümü", send(branch_path_name), :class => "selected-item" %> </li>
app/views/posts/branch/categories/_all_not_selected.html.erb
<li class="category-item"> <%= link_to "Tümü", send(branch_path_name) %> </li>
Burada kullanılan send metodu bir metodu ismini string vererek çalıştırmak için kullanılıyor. Bu metodları dinamik olarak çağırmak için çok kullanışlı bir yöntemdir. Bizim buradaki durumumuzda bulunulan kontrolörün aksiyonuna bağlı olarak farklı yollara yönlenmek için kullanılıyor.
Tekrar
_branch.html.erb
dosyasına kaldığımız terden devam edersek, no_posts_partial_path
metodu çağırılıyor. Eğer gönderi bulunamazsa metod bir mesaj verecektir.
posts_helper.rb
dosyasının içine bu metodu da ekleyelim.
app/helpers/posts_helper.rb
... def no_posts_partial_path @posts.empty? ? "posts/branch/no_posts" : "shared/empty_partial" end ...
Burada çok sevdiğim Ternary Operator kullanarak kod daha sade yapılmış.
render
metoduna boş string gönderemeyeceğimiz için boş bir parça görsel sayfasına yönlendiriyoruz.
app/views/shared/_empty_partial.html.erb
Bu boş dosyayı tanımladıktan sonra branch
klasörü altında _no_posts.html.erb
dosyasını tanımlayalım.
app/views/posts/branch/_no_posts.html.erb
<div class="text-center">Henüz yayınlanmış gönderi yok</div>
Son olarak da
will_paginate
metodu ile eğer çok fazla gönderi varsa sayfalara bölüyoruz.
hobby
, study
ve team
aksiyonları için görselleri tanımlayalım ve içlerinde _branch.html.erb
parça görselini değişik parametrelerle çağıralım. Dosyalar şöyle kodlara sahip olacak:
app/views/posts/hobby.html.erb
<%= render "posts/modal" %> <%= render partial: "posts/branch", locals: { branch: "hobby", page_title: "Aynı hobiye sahip insanlar bulun", search_placeholder: "örn. gitar çalmak, programlama, yemek pişirmek" } %>
app/views/posts/study.html.erb
<%= render "posts/modal" %> <%= render partial: "posts/branch", locals: { branch: "study", page_title: "Sizinle aynı konuda çalışan insanlar bulun", search_placeholder: "örn. beslenme, matematik, astrofizik" } %>
app/views/posts/team.html.erb
<%= render "posts/modal" %> <%= render partial: "posts/branch", locals: { branch: "team", page_title: "Takımınıza size benzer ilgileri olan insanlar bulun", search_placeholder: "örn. gruba müzisten, proje için yazılımcı" } %>
Ana sayfadan herhangi bir kolleksiyon sayfasına tıklarsak şuna benzer bir sayfa çıkar:
Sayfada aşağı scroll edersek en altta gönderilerin sayfalara bölündüğünü görürüz.
Şimdi bir sürü şeyi bir arada yaptık. Ben yaparken bir sürü hata yapmışım , buraya gelene kadar 1 saat onları düzeltmeye uğraştım. Bakalım siz bir kerede buraya gelebilecek misiniz. Ama bazen hata yapmak daha iyi anlamaya yardımcı oluyor.
Tabii ki daha yapılacak çok şey var ama kısa bir ara için iyi zaman. Bir sonraki bölümde görüşmek üzere..
Sırada şunlar var:
- ORTA SEVİYE BİR RAİLS TUTORIAL - 5 (Kolleksiyon sayfaları)
- ORTA SEVİYE BİR RAİLS TUTORIAL - 6 (Ana sayfa güncellemesi)
- ORTA SEVİYE BİR RAİLS TUTORIAL - 7 (Anlık mesajlaşma ilavesi)
Hiç yorum yok:
Yorum Gönder