prepare for next implementation in go
This commit is contained in:
parent
5570b0b568
commit
83cb61da71
9
Gemfile
9
Gemfile
|
@ -1,9 +0,0 @@
|
||||||
source 'https://rubygems.org'
|
|
||||||
|
|
||||||
gem 'sequel'
|
|
||||||
gem 'pg'
|
|
||||||
gem 'zero', :git => 'https://github.com/libzero/zero.git'
|
|
||||||
gem 'slim'
|
|
||||||
gem 'sass'
|
|
||||||
gem 'kramdown'
|
|
||||||
gem 'puma'
|
|
34
Gemfile.lock
34
Gemfile.lock
|
@ -1,34 +0,0 @@
|
||||||
GIT
|
|
||||||
remote: https://github.com/libzero/zero.git
|
|
||||||
revision: dde9fc410fb50bc44b128fb1032b15f09c53e0f7
|
|
||||||
specs:
|
|
||||||
zero (0.2.0)
|
|
||||||
tilt
|
|
||||||
|
|
||||||
GEM
|
|
||||||
remote: https://rubygems.org/
|
|
||||||
specs:
|
|
||||||
kramdown (1.3.2)
|
|
||||||
pg (0.17.1)
|
|
||||||
puma (2.7.1)
|
|
||||||
rack (>= 1.1, < 2.0)
|
|
||||||
rack (1.5.2)
|
|
||||||
sass (3.2.14)
|
|
||||||
sequel (4.7.0)
|
|
||||||
slim (2.0.2)
|
|
||||||
temple (~> 0.6.6)
|
|
||||||
tilt (>= 1.3.3, < 2.1)
|
|
||||||
temple (0.6.7)
|
|
||||||
tilt (2.0.0)
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
ruby
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
kramdown
|
|
||||||
pg
|
|
||||||
puma
|
|
||||||
sass
|
|
||||||
sequel
|
|
||||||
slim
|
|
||||||
zero!
|
|
|
@ -1,8 +0,0 @@
|
||||||
#!/usr/bin/env rackup
|
|
||||||
require File.expand_path('../lib/boot.rb', __FILE__)
|
|
||||||
|
|
||||||
Renderer.find_templates('templates')
|
|
||||||
run Application.new(Router, {
|
|
||||||
:renderer => Renderer,
|
|
||||||
:query => {}
|
|
||||||
})
|
|
|
@ -1 +0,0 @@
|
||||||
:db: "postgres://localhost/blogdb"
|
|
|
@ -1,7 +0,0 @@
|
||||||
module Routes
|
|
||||||
class Atom
|
|
||||||
def self.call(session)
|
|
||||||
Post
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
module Routes
|
|
||||||
class Images
|
|
||||||
def self.call(session)
|
|
||||||
file = "images/#{session.request.path.gsub(/images/, '')}"
|
|
||||||
return RouteNotFound unless File.exist?(file)
|
|
||||||
session.response.body = File.read(file)
|
|
||||||
session.response.content_type = 'image/png'
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,10 +0,0 @@
|
||||||
module Routes
|
|
||||||
class MethodNotAllowed
|
|
||||||
def self.call(session)
|
|
||||||
session.response.status = 405
|
|
||||||
session.response.content_type = 'text/html'
|
|
||||||
session.response.body = 'Method not supported by this resource!'
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,63 +0,0 @@
|
||||||
module Routes
|
|
||||||
class Post < Controller
|
|
||||||
PREV_AND_NEXT_QUERY = <<SQL
|
|
||||||
select (
|
|
||||||
select id from posts where written < ? and released order by written desc limit 1
|
|
||||||
) older,
|
|
||||||
(
|
|
||||||
select id from posts where written > ? and released order by written limit 1
|
|
||||||
) younger
|
|
||||||
SQL
|
|
||||||
|
|
||||||
def self.get(session)
|
|
||||||
posts = define_posts_query(session)
|
|
||||||
if session.options[:id]
|
|
||||||
posts = posts.filter(:posts__id => session.options[:id].to_i)
|
|
||||||
return RouteNotFound if posts.empty?
|
|
||||||
set_previous_and_next_post(session, posts)
|
|
||||||
else
|
|
||||||
if session.request.params['search']
|
|
||||||
posts = load_fulltextsearch(session, posts)
|
|
||||||
end
|
|
||||||
page = session.request.params['page'].to_i
|
|
||||||
per_page = session.request.params['per_page'].to_i
|
|
||||||
per_page = 10 if per_page && per_page < 1
|
|
||||||
set_page_information(session, posts, page, per_page)
|
|
||||||
posts = posts.limit(per_page).offset(page * per_page)
|
|
||||||
end
|
|
||||||
session.options[:posts] = posts
|
|
||||||
session.options[:render] = 'posts/index'
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.define_posts_query(session)
|
|
||||||
posts = DB[:posts].
|
|
||||||
filter(:released => true).
|
|
||||||
select(:posts__id___post_id, :written, :title, :content, :username).
|
|
||||||
join(:accounts, :id___account_id => :account_id).
|
|
||||||
reverse_order(:written, :posts__id)
|
|
||||||
end
|
|
||||||
|
|
||||||
# load posts depending on the pagination
|
|
||||||
def self.set_page_information(session, posts, page, per_page)
|
|
||||||
# compute pages
|
|
||||||
session.options[:page] = page if page
|
|
||||||
session.options[:query][:per_page] = per_page if per_page
|
|
||||||
session.options[:pages] = posts.count / per_page
|
|
||||||
end
|
|
||||||
|
|
||||||
# load a single posts and the ids of the next and previous posts
|
|
||||||
def self.set_previous_and_next_post(session, posts)
|
|
||||||
written = posts.first[:written]
|
|
||||||
session.options[:post_ids_pn] = DB[PREV_AND_NEXT_QUERY, written, written].first
|
|
||||||
end
|
|
||||||
|
|
||||||
# adjust query to use fulltext search
|
|
||||||
def self.load_fulltextsearch(session, posts)
|
|
||||||
session.options[:query][:search] = session.request.params['search']
|
|
||||||
posts.filter(
|
|
||||||
'posts.search_field @@ to_tsquery(\'english\', ?)',
|
|
||||||
session.request.params['search'].tr(' ', '&')
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,8 +0,0 @@
|
||||||
module Routes
|
|
||||||
class RouteNotFound < Controller
|
|
||||||
def self.get(session)
|
|
||||||
session.options[:render] = 'error/route_not_found'
|
|
||||||
session.response.status = 404
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,8 +0,0 @@
|
||||||
module Routes
|
|
||||||
class Stylesheet
|
|
||||||
def self.call(session)
|
|
||||||
session.options[:render] = 'stylesheet/index'
|
|
||||||
session.options[:renderer]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +0,0 @@
|
||||||
module Routes
|
|
||||||
class Welcome
|
|
||||||
def self.call(session)
|
|
||||||
Post
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
Binary file not shown.
Before Width: | Height: | Size: 56 KiB |
|
@ -1,19 +0,0 @@
|
||||||
class Application
|
|
||||||
def initialize(start, defaults = {})
|
|
||||||
@start = start
|
|
||||||
@defaults = defaults
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
session = Session.new(
|
|
||||||
::Zero::Request.new(env),
|
|
||||||
::Zero::Response.new,
|
|
||||||
Render.new(@defaults.clone)
|
|
||||||
)
|
|
||||||
worker = @start
|
|
||||||
while not worker.nil?
|
|
||||||
worker = worker.call(session)
|
|
||||||
end
|
|
||||||
session.response.to_a
|
|
||||||
end
|
|
||||||
end
|
|
16
lib/boot.rb
16
lib/boot.rb
|
@ -1,16 +0,0 @@
|
||||||
$LOAD_PATH << File.expand_path('..', __FILE__)
|
|
||||||
|
|
||||||
require 'libraries'
|
|
||||||
require 'session'
|
|
||||||
require 'application'
|
|
||||||
require 'controller'
|
|
||||||
require 'renderer'
|
|
||||||
require 'render'
|
|
||||||
require 'router'
|
|
||||||
|
|
||||||
config = YAML.load_file(File.expand_path('../../config.yml', __FILE__))
|
|
||||||
DB = Sequel.connect(config[:db])
|
|
||||||
|
|
||||||
Dir[File.expand_path('../../controller', __FILE__) + '/**'].each do |controller|
|
|
||||||
require controller
|
|
||||||
end
|
|
|
@ -1,12 +0,0 @@
|
||||||
class Controller
|
|
||||||
def self.call(session)
|
|
||||||
return call_method(session) if respond_to? session.request.method
|
|
||||||
Routes::MethodNotAllowed.call(session)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.call_method(session)
|
|
||||||
result = send(session.request.method, session)
|
|
||||||
return result if result.kind_of?(Class)
|
|
||||||
session.options[:renderer]
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +0,0 @@
|
||||||
require 'bundler/setup'
|
|
||||||
require 'yaml'
|
|
||||||
require 'sass'
|
|
||||||
require 'tilt'
|
|
||||||
require 'tilt/sass'
|
|
||||||
require 'sequel'
|
|
||||||
require 'zero'
|
|
||||||
require 'slim'
|
|
||||||
require 'kramdown'
|
|
|
@ -1,46 +0,0 @@
|
||||||
# defines a render container with some helper functions to keep the templates
|
|
||||||
# small
|
|
||||||
class Render
|
|
||||||
SLASH = '/'
|
|
||||||
|
|
||||||
def initialize(options)
|
|
||||||
@options = options
|
|
||||||
end
|
|
||||||
|
|
||||||
def [](key)
|
|
||||||
fetch(key)
|
|
||||||
end
|
|
||||||
|
|
||||||
def []=(key, value)
|
|
||||||
@options[key] = value
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch(key)
|
|
||||||
@options[key]
|
|
||||||
end
|
|
||||||
|
|
||||||
def has_key?(key)
|
|
||||||
@options.has_key?(key)
|
|
||||||
end
|
|
||||||
|
|
||||||
def options
|
|
||||||
@options
|
|
||||||
end
|
|
||||||
|
|
||||||
def link_to(*params)
|
|
||||||
query = []
|
|
||||||
while params.last.kind_of? Hash
|
|
||||||
query.push params.pop
|
|
||||||
end
|
|
||||||
return path(params) if query.empty?
|
|
||||||
path(params) + '?' + query_string(query)
|
|
||||||
end
|
|
||||||
|
|
||||||
def path(params)
|
|
||||||
SLASH + params.join(SLASH)
|
|
||||||
end
|
|
||||||
|
|
||||||
def query_string(query)
|
|
||||||
URI.encode_www_form(query.inject(:merge))
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,84 +0,0 @@
|
||||||
class Renderer
|
|
||||||
COMPONENT_MATCHER = %r{/?(?<template>[^\.]+)\.(?<type>[^\.]+)\.(?<engine>.+)}
|
|
||||||
DEFAULT_TYPE = :default_type
|
|
||||||
|
|
||||||
def self.call(session)
|
|
||||||
template = do_checks(session)
|
|
||||||
return nil unless template
|
|
||||||
type = get_type(session, template)
|
|
||||||
session.response.body = render(template, type, session.options)
|
|
||||||
session.response.content_type = type_map[type]
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.render(template, type, object)
|
|
||||||
layout = templates['layout']
|
|
||||||
if layout && layout.has_key?(type)
|
|
||||||
return layout[type].render(object) do
|
|
||||||
template[type].render(object)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
template[type].render(object)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.do_checks(session)
|
|
||||||
unless session.options.has_key? :render
|
|
||||||
session.response.body = ':render not set!'
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
to_render = session.options[:render]
|
|
||||||
unless templates.has_key? to_render
|
|
||||||
session.response.body = 'Template does not exist!'
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
return templates[to_render]
|
|
||||||
end
|
|
||||||
|
|
||||||
# initialize the template cache
|
|
||||||
def self.find_templates(path)
|
|
||||||
templates = {}
|
|
||||||
Dir[path + '/**/*'].each do |file|
|
|
||||||
parts = file.gsub(path, '').match(COMPONENT_MATCHER)
|
|
||||||
next unless File.file?(file) && parts
|
|
||||||
templates[parts[:template]] ||= {}
|
|
||||||
templates[parts[:template]].merge!({parts[:type].to_sym => Tilt.new(file)})
|
|
||||||
end
|
|
||||||
templates
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.templates
|
|
||||||
@@templates ||= find_templates 'templates'
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.set_types(types)
|
|
||||||
@@type_map = types.invert
|
|
||||||
@@types = types
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.types
|
|
||||||
@@types ||= {
|
|
||||||
'*/*' => DEFAULT_TYPE,
|
|
||||||
'text/css' => :css,
|
|
||||||
'text/html' => :html,
|
|
||||||
'application/atom+xml' => :atom
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.type_map
|
|
||||||
@@type_map ||= types.invert
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.get_type(session, template)
|
|
||||||
type = get_preferred_type(session.request, template)
|
|
||||||
return template.first[0] if type == DEFAULT_TYPE
|
|
||||||
type
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.get_preferred_type(request, template)
|
|
||||||
request.accept.types.each do |type|
|
|
||||||
next unless types.has_key? type
|
|
||||||
return types[type] if template.has_key? types[type]
|
|
||||||
return DEFAULT_TYPE if types[type] == DEFAULT_TYPE
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,38 +0,0 @@
|
||||||
class Router
|
|
||||||
ROUTE_REGEX = %r{\A(/(?<controller>[a-zA-Z]+)\.?(?<extension>[a-zA-Z]+)?(/(?<id>[^/]+)?)?)?\Z}
|
|
||||||
# get the controller handling the request
|
|
||||||
def self.call(session)
|
|
||||||
variables = session.request.path.match(ROUTE_REGEX)
|
|
||||||
return default_route unless variables && variables[:controller]
|
|
||||||
session.options[:id] = variables[:id]
|
|
||||||
find(variables[:controller])
|
|
||||||
end
|
|
||||||
|
|
||||||
# the namespace of all routes
|
|
||||||
def self.namespace
|
|
||||||
@@namespace ||= ::Routes
|
|
||||||
end
|
|
||||||
|
|
||||||
# set the namespace to a module or class which holds all controllers
|
|
||||||
def self.set_namespace(namespace)
|
|
||||||
@@namespace = namespace
|
|
||||||
end
|
|
||||||
|
|
||||||
# the default route to take when no path is given
|
|
||||||
def self.default_route
|
|
||||||
@@default ||= namespace.const_get(:Welcome)
|
|
||||||
end
|
|
||||||
|
|
||||||
# set the default route to take when no path is given
|
|
||||||
def self.set_default_route(default)
|
|
||||||
@@default = default
|
|
||||||
end
|
|
||||||
|
|
||||||
# check for the controller name and return 404 when not found
|
|
||||||
def self.find(ctrl)
|
|
||||||
ctrl = ctrl.capitalize
|
|
||||||
# make constant lookup without ancestors
|
|
||||||
return namespace.const_get(ctrl, false) if namespace.const_defined?(ctrl, false)
|
|
||||||
namespace::RouteNotFound
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1 +0,0 @@
|
||||||
Session = Struct.new(:request, :response, :options)
|
|
|
@ -1,47 +0,0 @@
|
||||||
Sequel.migration do
|
|
||||||
change do
|
|
||||||
create_table(:accounts) do
|
|
||||||
primary_key :id
|
|
||||||
String :username, :size=>50
|
|
||||||
String :email, :size=>50
|
|
||||||
String :crypted_password, :size=>70
|
|
||||||
String :role, :size=>50
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table(:tags) do
|
|
||||||
primary_key :id
|
|
||||||
String :name, :text=>true
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table(:posts, :ignore_index_errors=>true) do
|
|
||||||
primary_key :id
|
|
||||||
String :title, :text=>true, :null=>false
|
|
||||||
DateTime :written
|
|
||||||
TrueClass :released, :default=>false
|
|
||||||
String :markup, :default=>"markdown", :text=>true
|
|
||||||
String :content, :text=>true
|
|
||||||
foreign_key :account_id, :accounts, :null=>false, :key=>[:id]
|
|
||||||
|
|
||||||
index [:account_id], :name=>:index_posts_account
|
|
||||||
index [:written, :id], :name=>:posts_written_id_idx
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table(:comments, :ignore_index_errors=>true) do
|
|
||||||
primary_key :id
|
|
||||||
String :author, :size=>50
|
|
||||||
String :email, :size=>50
|
|
||||||
TrueClass :acknowledged, :default=>false
|
|
||||||
String :body, :text=>true
|
|
||||||
foreign_key :post_id, :posts, :null=>false, :key=>[:id]
|
|
||||||
|
|
||||||
index [:post_id], :name=>:index_comments_post
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table(:post_tags) do
|
|
||||||
foreign_key :post_id, :posts, :null=>false, :key=>[:id]
|
|
||||||
foreign_key :tag_id, :tags, :null=>false, :key=>[:id]
|
|
||||||
|
|
||||||
primary_key [:post_id, :tag_id]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,52 +0,0 @@
|
||||||
# this is the schema from the old platform
|
|
||||||
Sequel.migration do
|
|
||||||
up do
|
|
||||||
drop_table :post_tags
|
|
||||||
drop_table :comments
|
|
||||||
drop_table :tags
|
|
||||||
|
|
||||||
alter_table :posts do
|
|
||||||
add_column :language, String, :size => 10
|
|
||||||
end
|
|
||||||
|
|
||||||
from(:posts).update(:language => 'english')
|
|
||||||
|
|
||||||
alter_table :posts do
|
|
||||||
set_column_not_null :language
|
|
||||||
end
|
|
||||||
|
|
||||||
run 'create function search_field(posts) returns tsvector as $$' +
|
|
||||||
"select to_tsvector($1.language::regconfig, $1.title || ' ' || $1.content);" +
|
|
||||||
'$$ language sql immutable;'
|
|
||||||
end
|
|
||||||
|
|
||||||
down do
|
|
||||||
alter_table :posts do
|
|
||||||
drop_column :language
|
|
||||||
end
|
|
||||||
run 'drop function search_field(posts);'
|
|
||||||
|
|
||||||
create_table(:tags) do
|
|
||||||
primary_key :id
|
|
||||||
String :name, :text=>true
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table(:comments, :ignore_index_errors=>true) do
|
|
||||||
primary_key :id
|
|
||||||
String :author, :size=>50
|
|
||||||
String :email, :size=>50
|
|
||||||
TrueClass :acknowledged, :default=>false
|
|
||||||
String :body, :text=>true
|
|
||||||
foreign_key :post_id, :posts, :null=>false, :key=>[:id]
|
|
||||||
|
|
||||||
index [:post_id], :name=>:index_comments_post
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table(:post_tags) do
|
|
||||||
foreign_key :post_id, :posts, :null=>false, :key=>[:id]
|
|
||||||
foreign_key :tag_id, :tags, :null=>false, :key=>[:id]
|
|
||||||
|
|
||||||
primary_key [:post_id, :tag_id]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
Binary file not shown.
Before Width: | Height: | Size: 8.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 104 KiB |
|
@ -1,4 +0,0 @@
|
||||||
p.error
|
|
||||||
'Sorry, this article does not exist. Maybe you want to go the
|
|
||||||
a(href=link_to('')) homepage
|
|
||||||
' and see, if you can find your post there?
|
|
|
@ -1,24 +0,0 @@
|
||||||
doctype 5
|
|
||||||
html
|
|
||||||
head
|
|
||||||
title zero-knowledge
|
|
||||||
meta(
|
|
||||||
http-equiv='Content-Type'
|
|
||||||
content='text/html; charset=utf-8')
|
|
||||||
link(
|
|
||||||
href='/atom.xml'
|
|
||||||
rel='alternate'
|
|
||||||
title='Atom 1.0'
|
|
||||||
type='application/atom+xml')
|
|
||||||
link(
|
|
||||||
href='/stylesheet.css'
|
|
||||||
rel='stylesheet'
|
|
||||||
type='text/css')
|
|
||||||
body
|
|
||||||
header#header
|
|
||||||
a href='/'
|
|
||||||
h1 zero-knowledge
|
|
||||||
h2 no clue at all
|
|
||||||
img src='/images/zero-knowledge.png' alt='zero-knowledge'
|
|
||||||
#content
|
|
||||||
==yield
|
|
|
@ -1,18 +0,0 @@
|
||||||
doctype xml
|
|
||||||
feed xmlns='http://www.w3.org/2005/Atom'
|
|
||||||
title zero-knowledge
|
|
||||||
link href='http://zero-knowledge.org'
|
|
||||||
link type='application/atom+xml' rel='self' href='http://zero-knowledge.org'
|
|
||||||
updated=fetch(:posts).first[:written].xmlschema
|
|
||||||
id http://zero-knowledge.org/
|
|
||||||
-for post in fetch(:posts)
|
|
||||||
entry
|
|
||||||
id="http://zero-knowledge.org/post/#{post[:post_id]}"
|
|
||||||
link(type='text/html' rel='alternate'
|
|
||||||
href="http://zero-knowledge.org/post/#{post[:post_id]}")
|
|
||||||
title=post[:title]
|
|
||||||
updated=post[:written].xmlschema
|
|
||||||
author
|
|
||||||
name=post[:username]
|
|
||||||
summary type='html'=post[:content]
|
|
||||||
content type='html'=Kramdown::Document.new(post[:content]).to_html
|
|
|
@ -1,29 +0,0 @@
|
||||||
- if has_key?(:page) && 0 < fetch(:page)
|
|
||||||
a.page.up(
|
|
||||||
href=link_to(:post, fetch(:query), :page => fetch(:page) - 1)
|
|
||||||
) show newer
|
|
||||||
- if has_key?(:post_ids_pn) && fetch(:post_ids_pn)[:younger]
|
|
||||||
a.page.up(
|
|
||||||
href=link_to(:post, fetch(:post_ids_pn)[:younger])
|
|
||||||
) show newer
|
|
||||||
|
|
||||||
- for post in fetch(:posts)
|
|
||||||
article
|
|
||||||
header
|
|
||||||
h1
|
|
||||||
//a(href=link_to(:post, post[:post_id], fetch(:query))) post[:title]
|
|
||||||
a(href=link_to(:post, post[:post_id]))=post[:title]
|
|
||||||
footer
|
|
||||||
.author=post[:username]
|
|
||||||
.date= post[:written].strftime('%Y-%m-%d')
|
|
||||||
.time= post[:written].strftime('%H-%M')
|
|
||||||
section==Kramdown::Document.new(post[:content]).to_html
|
|
||||||
|
|
||||||
- if has_key?(:page) && fetch(:page) < fetch(:pages)
|
|
||||||
a.page.down(
|
|
||||||
href=link_to(:post, fetch(:query), :page => fetch(:page) + 1)
|
|
||||||
) show older
|
|
||||||
- if has_key?(:post_ids_pn) && fetch(:post_ids_pn)[:older]
|
|
||||||
a.page.down(
|
|
||||||
href=link_to(:post, fetch(:post_ids_pn)[:older])
|
|
||||||
) show older
|
|
|
@ -1,130 +0,0 @@
|
||||||
// normal text color
|
|
||||||
$normal_color: hsl(0,0, 90%);
|
|
||||||
// the nice orange
|
|
||||||
$action_color: hsl(32, 100%, 50%);
|
|
||||||
// the blue
|
|
||||||
$alternate_color: hsl(204, 35%, 35%);
|
|
||||||
// box color for quotes and code
|
|
||||||
$box_color: hsla(0, 0%, 0%, 0);
|
|
||||||
|
|
||||||
// standard size to size everything from that
|
|
||||||
$standard-width: 1em;
|
|
||||||
|
|
||||||
// other variables
|
|
||||||
$box_border: $standard-width solid $box_color;
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-size: 99%;
|
|
||||||
font-family: sans-serif;
|
|
||||||
/* original picture from http://subtlepatterns.com/iron-grip/ */
|
|
||||||
background-image: url('/images/irongrip-zero.png');
|
|
||||||
min-width: 300px;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 1100px;
|
|
||||||
margin: auto;
|
|
||||||
color: $normal_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: "PT mono", monospace;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
border: $box_border;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
border: $box_border;
|
|
||||||
margin: 0;
|
|
||||||
font-style: italic;
|
|
||||||
|
|
||||||
p:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
p:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#header {
|
|
||||||
h1, h2 {
|
|
||||||
display: none;
|
|
||||||
margin: $standard-width / 2;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
padding-left: $standard-width;
|
|
||||||
padding-right: $standard-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: $action-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
padding: $standard-width;
|
|
||||||
font-size: $standard-width * 0.9;
|
|
||||||
font-weight: bold;
|
|
||||||
&.up {
|
|
||||||
border-top: $standard-width / 4 solid $alternate-color;
|
|
||||||
&:hover, &:focus, &:active {
|
|
||||||
border-top: $standard-width / 4 solid $action-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.down {
|
|
||||||
border-bottom: $standard-width / 4 solid $alternate-color;
|
|
||||||
&:hover, &:focus, &:active {
|
|
||||||
border-bottom: $standard-width / 4 solid $action-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
padding: $standard-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content, pre, blockquote {
|
|
||||||
background-color: fade-out($alternate-color, 0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
article {
|
|
||||||
padding-top: $standard-width;
|
|
||||||
padding-bottom: $standard-width;
|
|
||||||
header {
|
|
||||||
padding: $standard-width / 4;
|
|
||||||
display: inline-block;
|
|
||||||
h1 { margin: 0;}
|
|
||||||
h1, h2 { display: inline-block; }
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
padding: $standard-width / 4;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: $standard-width * 0.9;
|
|
||||||
div {
|
|
||||||
display: inline-block;
|
|
||||||
margin: $standard-width / 5;
|
|
||||||
font-weight: bold;
|
|
||||||
color: hsl(0, 0%, 60%);
|
|
||||||
}
|
|
||||||
.author:before { content: 'by '; }
|
|
||||||
.date:before { content: ' on '; }
|
|
||||||
.time { display: none; }
|
|
||||||
}
|
|
||||||
section {
|
|
||||||
border-top: $standard-width/5 solid $alternate-color;
|
|
||||||
word-wrap: break-word;
|
|
||||||
h1 { font-size: $standard-width * 1.3 }
|
|
||||||
h2 { font-size: $standard-width * 1.2 }
|
|
||||||
h3 { font-size: $standard-width * 1.1; font-weight: normal; }
|
|
||||||
h1, h2, h3 {
|
|
||||||
border-bottom: $standard-width / 10 solid $normal-color;
|
|
||||||
margin-right: 25%;
|
|
||||||
}
|
|
||||||
code, pre { word-wrap: initial; }
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue