forked from treehouse/mastodon
Adding public following and followers pages, fix #3
parent
c349200761
commit
71ae4dd3d2
|
@ -2,7 +2,7 @@
|
||||||
background: #282c37;
|
background: #282c37;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
padding: 60px 0;
|
padding: 60px 0;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 0;
|
||||||
border-radius: 4px 4px 0 0;
|
border-radius: 4px 4px 0 0;
|
||||||
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -64,8 +64,45 @@
|
||||||
width: 80px;
|
width: 80px;
|
||||||
color: #9baec8;
|
color: #9baec8;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
border-right: 1px solid #9baec8;
|
border-right: 1px solid #9baec8;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: -10px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 4px solid #9baec8;
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: all 0.8s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
&:after {
|
||||||
|
border-bottom: 4px solid #2b90d9;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
&:after {
|
||||||
|
opacity: 1;
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
.counter-label {
|
.counter-label {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -145,3 +182,87 @@
|
||||||
color: lighten(#282c37, 10%);
|
color: lighten(#282c37, 10%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.accounts-grid {
|
||||||
|
clear: both;
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
padding: 20px 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.account-grid-card {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 335px;
|
||||||
|
float: left;
|
||||||
|
border: 1px solid #d9e1e8;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #282c37;
|
||||||
|
height: 160px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-grid-card__header {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 10px;
|
||||||
|
border-bottom: 1px solid #d9e1e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
float: left;
|
||||||
|
margin-right: 15px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
padding-top: 10px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #282c37;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.display_name {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.display_name {
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
color: #2b90d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note {
|
||||||
|
padding: 10px;
|
||||||
|
padding-top: 15px;
|
||||||
|
color: #9baec8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nothing-here {
|
||||||
|
color: #9baec8;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,14 @@ class AccountsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def followers
|
||||||
|
@followers = @account.followers.paginate(page: params[:page], per_page: 6)
|
||||||
|
end
|
||||||
|
|
||||||
|
def following
|
||||||
|
@following = @account.following.paginate(page: params[:page], per_page: 6)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
module AccountsHelper
|
module AccountsHelper
|
||||||
|
def pagination_options
|
||||||
|
{ previous_label: "#{fa_icon('chevron-left')} Prev".html_safe, next_label: "Next #{fa_icon('chevron-right')}".html_safe, inner_window: 2 }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
.account-grid-card
|
||||||
|
.account-grid-card__header
|
||||||
|
.avatar= image_tag account.avatar.url(:medium)
|
||||||
|
.name
|
||||||
|
= link_to url_for_target(account) do
|
||||||
|
%span.display_name= display_name(account)
|
||||||
|
%span.username= "@#{account.acct}"
|
||||||
|
%p.note= account.note
|
|
@ -0,0 +1,20 @@
|
||||||
|
.card{ style: "background-image: url(#{@account.header.url(:medium)})" }
|
||||||
|
.avatar= image_tag @account.avatar.url(:large)
|
||||||
|
%h1.name
|
||||||
|
= display_name(@account)
|
||||||
|
%small= "@#{@account.username}"
|
||||||
|
.details
|
||||||
|
.counter{ class: active_nav_class(account_url(@account)) }
|
||||||
|
= link_to account_url(@account) do
|
||||||
|
%span.counter-label Posts
|
||||||
|
%span.counter-number= @account.statuses.count
|
||||||
|
.counter{ class: active_nav_class(following_account_url(@account)) }
|
||||||
|
= link_to following_account_url(@account) do
|
||||||
|
%span.counter-label Following
|
||||||
|
%span.counter-number= @account.following.count
|
||||||
|
.counter{ class: active_nav_class(followers_account_url(@account)) }
|
||||||
|
= link_to followers_account_url(@account) do
|
||||||
|
%span.counter-label Followers
|
||||||
|
%span.counter-number= @account.followers.count
|
||||||
|
.bio
|
||||||
|
%p= @account.note
|
|
@ -0,0 +1 @@
|
||||||
|
%p.nothing-here There is nothing here!
|
|
@ -0,0 +1,14 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
People who follow
|
||||||
|
= display_name(@account)
|
||||||
|
|
||||||
|
= render partial: 'header'
|
||||||
|
|
||||||
|
.accounts-grid
|
||||||
|
- @followers.each do |f|
|
||||||
|
= render partial: 'grid_card', locals: { account: f }
|
||||||
|
|
||||||
|
- if @followers.empty?
|
||||||
|
= render partial: 'nothing_here'
|
||||||
|
|
||||||
|
= will_paginate @followers, pagination_options
|
|
@ -0,0 +1,15 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
People whom
|
||||||
|
= display_name(@account)
|
||||||
|
follows
|
||||||
|
|
||||||
|
= render partial: 'header'
|
||||||
|
|
||||||
|
.accounts-grid
|
||||||
|
- @following.each do |f|
|
||||||
|
= render partial: 'grid_card', locals: { account: f }
|
||||||
|
|
||||||
|
- if @following.empty?
|
||||||
|
= render partial: 'nothing_here'
|
||||||
|
|
||||||
|
= will_paginate @following, pagination_options
|
|
@ -5,26 +5,10 @@
|
||||||
%link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
|
%link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
|
||||||
%link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
|
%link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
|
||||||
|
|
||||||
.card{ style: "background-image: url(#{@account.header.url(:medium)})" }
|
= render partial: 'header'
|
||||||
.avatar= image_tag @account.avatar.url(:large)
|
|
||||||
%h1.name
|
|
||||||
= display_name(@account)
|
|
||||||
%small= "@#{@account.username}"
|
|
||||||
.details
|
|
||||||
.counter
|
|
||||||
%span.counter-label Posts
|
|
||||||
%span.counter-number= @account.statuses.count
|
|
||||||
.counter
|
|
||||||
%span.counter-label Following
|
|
||||||
%span.counter-number= @account.following.count
|
|
||||||
.counter
|
|
||||||
%span.counter-label Followers
|
|
||||||
%span.counter-number= @account.followers.count
|
|
||||||
.bio
|
|
||||||
%p= @account.note
|
|
||||||
|
|
||||||
.activity-stream
|
.activity-stream
|
||||||
- @statuses.each do |status|
|
- @statuses.each do |status|
|
||||||
= render partial: 'stream_entries/status', locals: { status: status, include_threads: false, is_successor: false, is_predecessor: false }
|
= render partial: 'stream_entries/status', locals: { status: status, include_threads: false, is_successor: false, is_predecessor: false }
|
||||||
|
|
||||||
= will_paginate @statuses, previous_label: "#{fa_icon('chevron-left')} Prev".html_safe, next_label: "Next #{fa_icon('chevron-right')}".html_safe, inner_window: 2
|
= will_paginate @statuses, pagination_options
|
||||||
|
|
|
@ -14,6 +14,11 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
resources :accounts, path: 'users', only: [:show], param: :username do
|
resources :accounts, path: 'users', only: [:show], param: :username do
|
||||||
resources :stream_entries, path: 'updates', only: [:show]
|
resources :stream_entries, path: 'updates', only: [:show]
|
||||||
|
|
||||||
|
member do
|
||||||
|
get :followers
|
||||||
|
get :following
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resource :settings, only: [:show, :update]
|
resource :settings, only: [:show, :update]
|
||||||
|
|
|
@ -4,14 +4,28 @@ RSpec.describe AccountsController, type: :controller do
|
||||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||||
|
|
||||||
describe 'GET #show' do
|
describe 'GET #show' do
|
||||||
it 'returns 200' do
|
it 'returns http success' do
|
||||||
get :show, username: alice.username
|
get :show, username: alice.username
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 200 with Atom' do
|
it 'returns http success with Atom' do
|
||||||
get :show, username: alice.username, format: 'atom'
|
get :show, username: alice.username, format: 'atom'
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'GET #followers' do
|
||||||
|
it 'returns http success' do
|
||||||
|
get :followers, username: alice.username
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET #following' do
|
||||||
|
it 'returns http success' do
|
||||||
|
get :following, username: alice.username
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@ require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe HomeController, type: :controller do
|
RSpec.describe HomeController, type: :controller do
|
||||||
describe 'GET #index' do
|
describe 'GET #index' do
|
||||||
it 'returns 200' do
|
it 'redirects to login page' do
|
||||||
get :index
|
get :index
|
||||||
expect(response).to redirect_to(new_user_session_path)
|
expect(response).to redirect_to(new_user_session_path)
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,12 +5,12 @@ RSpec.describe StreamEntriesController, type: :controller do
|
||||||
let(:status) { Fabricate(:status, account: alice) }
|
let(:status) { Fabricate(:status, account: alice) }
|
||||||
|
|
||||||
describe 'GET #show' do
|
describe 'GET #show' do
|
||||||
it 'returns 200 with HTML' do
|
it 'returns http success with HTML' do
|
||||||
get :show, account_username: alice.username, id: status.stream_entry.id
|
get :show, account_username: alice.username, id: status.stream_entry.id
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 200 with Atom' do
|
it 'returns http success with Atom' do
|
||||||
get :show, account_username: alice.username, id: status.stream_entry.id, format: 'atom'
|
get :show, account_username: alice.username, id: status.stream_entry.id, format: 'atom'
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@ require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe XrdController, type: :controller do
|
RSpec.describe XrdController, type: :controller do
|
||||||
describe 'GET #host_meta' do
|
describe 'GET #host_meta' do
|
||||||
it 'returns 200' do
|
it 'returns http success' do
|
||||||
get :host_meta
|
get :host_meta
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
|
@ -11,12 +11,12 @@ RSpec.describe XrdController, type: :controller do
|
||||||
describe 'GET #webfinger' do
|
describe 'GET #webfinger' do
|
||||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||||
|
|
||||||
it 'returns 200 when account can be found' do
|
it 'returns http success when account can be found' do
|
||||||
get :webfinger, resource: "acct:#{alice.username}@anything.com"
|
get :webfinger, resource: "acct:#{alice.username}@anything.com"
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 404 when account cannot be found' do
|
it 'returns http not found when account cannot be found' do
|
||||||
get :webfinger, resource: 'acct:not@existing.com'
|
get :webfinger, resource: 'acct:not@existing.com'
|
||||||
expect(response).to have_http_status(:not_found)
|
expect(response).to have_http_status(:not_found)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue