panda 0.0.0.4.2 → 0.0.0.5
raw patch · 23 files changed
+144/−106 lines, 23 filesdep +MissingHdep +pandocdep +parsec
Dependencies added: MissingH, pandoc, parsec
Files
- Panda/Config/Global.hs +5/−3
- Panda/Controller/Application.hs +5/−3
- Panda/Helper/Env.hs +8/−4
- Panda/Helper/Escape.hs +5/−12
- Panda/Helper/Helper.hs +6/−3
- Panda/Model/Post.hs +13/−10
- Panda/Model/Static.hs +25/−0
- Panda/Model/Tag.hs +1/−3
- Panda/Type/Reader.hs +32/−0
- Panda/View/RSS.hs +1/−1
- Panda/View/Theme/BluePrint/Helper.hs +0/−7
- Panda/View/Theme/BluePrint/Post.hs +1/−5
- Panda/View/Theme/BluePrint/Search.hs +0/−2
- Panda/View/Theme/BluePrint/Static.hs +2/−6
- Panda/View/Theme/BluePrint/Tag.hs +0/−5
- Panda/View/Theme/BluePrint/Template/Body.hs +1/−2
- Panda/View/Theme/BluePrint/Template/Footer.hs +0/−2
- Panda/View/Theme/BluePrint/Template/Header.hs +2/−6
- Panda/View/Theme/BluePrint/Template/Sidebar.hs +0/−2
- Panda/View/Theme/BluePrint/Template/Template.hs +1/−6
- changelog.markdown +11/−0
- panda.cabal +11/−13
- readme.markdown +14/−11
Panda/Config/Global.hs view
@@ -1,8 +1,8 @@ module Panda.Config.Global where import Panda.Helper.Env-import Prelude hiding ((.), (/), id)-import System.IO.UTF8 as UIO+import Prelude hiding ((.), (/), id, readFile)+import Panda.Type.Reader db_id = "db" flat_id = "."@@ -23,7 +23,7 @@ -- unsafe, must restart server after changing config file, sorry about that ... -- but these configs are read only, and keep the view pure, so no monad headaches involved. -user_config = UIO.readFile config_uri .purify .filter_comment .lines .map strip .map (split "\\s*=\\s*") .map tuple2+user_config = readFile config_uri .purify .filter_comment .lines .map strip .map (split "\\s*=\\s*") .map tuple2 config_for' s d = user_config.lookup s .fromMaybe d config_for s = config_for' s s@@ -37,3 +37,5 @@ navigation = config_for' "navigation" "About" .split "," .map strip .reject null .("Home" :) panda_url = "http://github.com/nfjinjing/panda"++default_reader = Markdown
Panda/Controller/Application.hs view
@@ -5,7 +5,7 @@ import qualified Data.Map as Map -- env-import Panda.Helper.Env+import Panda.Helper.Env hiding (tag) import Prelude hiding ((.), (/), id) import Panda.Type.State hiding (pager) import qualified Panda.Config.Global as Config@@ -13,6 +13,7 @@ -- model import qualified Panda.Model.Post as Post+import qualified Panda.Model.Static as Static import qualified Panda.Model.Tag as Tag -- view@@ -64,11 +65,12 @@ static = do id <- uri+ static_page <- Static.get id .liftIO tags <- Tag.list.liftIO - let nav = if r.belongs_to Config.navigation then r else no_navigation where r = id.id_to_resource+ let nav = if title.belongs_to Config.navigation then title else no_navigation where title = static_page.Static.title let state = State id Pager.empty tags nav- (Config.flat_uri / id) .readFile .liftIO <.> StaticV.view state >>= output_html+ StaticV.view state static_page .output_html tag = do
Panda/Helper/Env.hs view
@@ -9,17 +9,21 @@ , module System.Time.Parse , module Panda.Helper.Helper , module Data.Maybe+ , module System.FilePath.Posix+ , module System.IO.UTF8+ , module Text.XHtml.Strict ) where -import MPS+import MPS hiding (base, col, sub) import Control.Monad hiding (join) import Control.Arrow ((>>>)) import Data.List import Network.URI-import Network.CGI+import Network.CGI hiding (Html) import System.Locale import System.Time.Parse import Panda.Helper.Helper import Data.Maybe--+import System.FilePath.Posix hiding ((<.>))+import System.IO.UTF8 (readFile)+import Text.XHtml.Strict hiding (select)
Panda/Helper/Escape.hs view
@@ -1,12 +1,11 @@ module Panda.Helper.Escape where import Text.ParserCombinators.Parsec-import MPS hiding (parse) import Char-import Prelude hiding ((.), (/), id)+import Data.Either.Utils -unicode :: Parser Char-unicode = do+unicode_char :: Parser Char+unicode_char = do char '&' char '#' word <- many1 digit@@ -14,12 +13,6 @@ return $ chr (read word) unescape_parser :: Parser String-unescape_parser = do- s <- many (unicode <|> anyChar)- return $ s--parse' p s = case (parse p "" s) of- Left err -> err.show.error- Right x -> x+unescape_parser = many (unicode_char <|> anyChar) -unescape s = parse' unescape_parser s+unescape s = forceEither $ parse unescape_parser "" s
Panda/Helper/Helper.hs view
@@ -16,10 +16,13 @@ import Panda.Helper.Escape import Char import Data.List+import Panda.Type.Reader+import System.FilePath.Posix hiding ((<.>)) (/) = (</>) -+-- model+take_extension = takeExtension >>> split "\\." >>> last -- controller uri = requestURI <.> (uriPath >>> urlDecode >>> tail)@@ -45,8 +48,8 @@ for_current_page p xs = xs.drop ((p.Pager.current - 1) * p.Pager.length) .take (p.Pager.length) -- id: /type/resoruce-id_to_type id = id.split "/" .first-id_to_resource id = id.split "/" .tail.join "/"+id_to_type id = id.from_utf8.split "/" .first+id_to_resource id = id.from_utf8.split "/" .tail.join "/" no_navigation = "" home_nav = "Home"
Panda/Model/Post.hs view
@@ -1,31 +1,34 @@-{-# OPTIONS -fno-monomorphism-restriction #-}- module Panda.Model.Post where -- env-import Panda.Helper.Env hiding (match)+import Panda.Helper.Env hiding (match, readFile, title, body) import Prelude hiding ((.), (/), id) import qualified Panda.Config.Global as Config+import Panda.Type.Reader data Post = Post { uid :: String -- blog/08-09-04 blog title , title :: String , body :: String , tags :: [String]+ , reader :: Reader } deriving (Show, Eq) list = ls Config.blog_uri <.> rsort <.> map (Config.blog_id /) >>= mapM get -get id = liftM2 (Post id (get_title id) ) (get_body id) (return [])-get_title id = id.from_utf8.words.tail.join " "-get_body id = (Config.flat_uri / id) .readFile+get id = liftM3 (Post id (get_title id) ) (get_body id) (return []) (return $ get_reader id)+get_title id = id.from_utf8.words.tail.unwords.dropExtension+get_body id = (Config.flat_uri / id) .readFile+get_reader id = id.take_extension.guess_reader.fromMaybe Config.default_reader + parse_date = parseCalendarTime defaultTimeLocale "%Y-%m-%d"-date x = case x.uid.words.first.split "/".last.("20"++).parse_date of- Nothing -> parse_date "2000-1-1".fromJust- Just x -> x+date x = x.uid.words.first.split "/".last.("20"++).parse_date.fromMaybe (parse_date "2000-1-1".fromJust) -match s x = [title, body >>> from_utf8] .map (send_to x >>> lower >>> isInfixOf (s.lower)) .or++match s x = [title, body] .map (send_to x >>> lower >>> isInfixOf (s.lower)) .or search "" = return [] search s = list <.> filter (match s)++markup x = render_to_html (x.reader) (x.body)
+ Panda/Model/Static.hs view
@@ -0,0 +1,25 @@+module Panda.Model.Static where++-- env+import Panda.Helper.Env hiding (match, body)+import Prelude hiding ((.), (/), id, readFile)+import qualified Panda.Config.Global as Config+import Panda.Type.Reader++data Static = Static + { uid :: String+ , title :: String+ , body :: String+ , tags :: [String]+ , reader :: Reader+ }+ deriving (Show, Eq)+ + +get id = liftM3 (Static id (get_title id) ) (get_body id) (return []) (return $ get_reader id)+get_title = id_to_resource >>> dropExtension+get_body id = (Config.flat_uri / id) .readFile+get_reader id = id.take_extension.guess_reader.fromMaybe Config.default_reader+++markup x = render_to_html (x.reader) (x.body)
Panda/Model/Tag.hs view
@@ -1,11 +1,9 @@-{-# OPTIONS -fno-monomorphism-restriction #-}- module Panda.Model.Tag where import qualified Panda.Model.Post as Post -- env-import Panda.Helper.Env+import Panda.Helper.Env hiding (readFile, name) import Prelude hiding ((.), (/), id) import qualified Data.Set as Set import qualified Data.Map as Map
+ Panda/Type/Reader.hs view
@@ -0,0 +1,32 @@+module Panda.Type.Reader where++import MPS +import Prelude hiding ((.), (/), id)+import qualified Data.Map as Map+import Text.Pandoc+import Control.Arrow ((>>>))+import Text.XHtml.Strict++data Reader = Markdown | RST | HTML | Latex deriving (Show, Eq)++readers = + [ (Markdown, ["markdown", "md"])+ , (RST, ["rst"] )+ , (HTML, ["html", "htm"])+ , (Latex, ["tex", "latex"])+ ]++gen_lookup (r, xs) = xs.labeling (const r)+reader_map = readers.map gen_lookup.join'.to_h+guess_reader ext = reader_map.Map.lookup ext+++to_html r = r defaultParserState >>> writeHtml defaultWriterOptions++rr Markdown = to_html readMarkdown+rr RST = to_html readRST+rr HTML = primHtml+rr Latex = to_html readLaTeX++render_to_html = rr+
Panda/View/RSS.hs view
@@ -18,7 +18,7 @@ item_rss_template x = [ Title $ x.Post.title- , Description $ x.Post.body.Config.markup.show+ , Description $ x.Post.markup.show , Author $ Config.author_email , Link $ x.item_uri , PubDate $ x.Post.date
Panda/View/Theme/BluePrint/Helper.hs view
@@ -1,15 +1,8 @@ module Panda.View.Theme.BluePrint.Helper where -- import Panda.Helper.Env import Prelude hiding ((.), (/), id, span)-import qualified Panda.Config.Global as Config-import qualified Panda.Type.State as State-import Text.XHtml.Strict -import Panda.View.Theme.BluePrint.Template.Template-import Panda.Model.Post as Post import Panda.Type.Pager as Pager
Panda/View/Theme/BluePrint/Post.hs view
@@ -3,11 +3,7 @@ -- env import Panda.Helper.Env import Prelude hiding ((.), (/), id, span)-import qualified Panda.Config.Global as Config-import qualified Panda.Type.State as State-import Text.XHtml.Strict -import Panda.Type.Pager as Pager import System.Time import System.Locale import qualified Panda.Type.State as State@@ -23,7 +19,7 @@ -- render single entry entry x = div_class "post" << [entry_title, entry_mark, entry_body] where entry_title = x.title_link- entry_body = div_class "entry" << x.Post.body.Config.markup+ entry_body = div_class "entry" << x.Post.markup entry_mark = p ! [theclass "small"] << [ x.blog_date, x.blog_tags ]
Panda/View/Theme/BluePrint/Search.hs view
@@ -2,9 +2,7 @@ import Panda.Helper.Env import Prelude hiding ((.), (/), id, span)-import qualified Panda.Config.Global as Config import qualified Panda.Type.State as State-import Text.XHtml.Strict -- view import Panda.View.Theme.BluePrint.Post hiding (view)
Panda/View/Theme/BluePrint/Static.hs view
@@ -1,11 +1,7 @@ module Panda.View.Theme.BluePrint.Static where import Panda.Helper.Env-import Prelude hiding ((.), (/), id, span)-import qualified Panda.Config.Global as Config-import qualified Panda.Type.State as State-import Text.XHtml.Strict-+import Panda.Model.Static as Static import Panda.View.Theme.BluePrint.Template.Template -view tags x = x.Config.markup.page tags+view state = Static.markup >>> page state
Panda/View/Theme/BluePrint/Tag.hs view
@@ -2,12 +2,7 @@ import Panda.Helper.Env import Prelude hiding ((.), (/), id, span)-import qualified Panda.Config.Global as Config import qualified Panda.Type.State as State-import Text.XHtml.Strict---- model-import Panda.Model.Tag as Tag -- view import Panda.View.Theme.BluePrint.Post hiding (view)
Panda/View/Theme/BluePrint/Template/Body.hs view
@@ -5,7 +5,6 @@ import Prelude hiding ((.), (/), id, span) import qualified Panda.Config.Global as Config import qualified Panda.Type.State as State-import Text.XHtml.Strict -- view import Panda.View.Theme.BluePrint.Template.Sidebar@@ -48,7 +47,7 @@ link x = if x == home_nav then home_link else static_link x home_link = hotlink "/" << home_nav-static_link s = hotlink ("/" / "static" / s) << s+static_link s = hotlink ("/" / "static" / s) << s.dropExtension body_content x = div_class_id "column span-9 first" "maincontent" <<
@@ -3,8 +3,6 @@ import Panda.Helper.Env import Prelude hiding ((.), (/), id, span) import qualified Panda.Config.Global as Config-import qualified Panda.Type.State as State-import Text.XHtml.Strict import qualified Panda.Config.Global as Config
Panda/View/Theme/BluePrint/Template/Header.hs view
@@ -3,16 +3,12 @@ import Panda.Helper.Env import Prelude hiding ((.), (/), id, span) import qualified Panda.Config.Global as Config-import qualified Panda.Type.State as State-import Text.XHtml.Strict -html_head = header << [meta_tag, title_tag, screen_css, wp_css, custom_css, rss_tag] -- , ie_css, custom_css]+html_head = header << [meta_tag, title_tag, screen_css, wp_css, custom_css, rss_tag] title_tag = thetitle << Config.blog_title screen_css = css_link "/theme/blueprint/wp/css/screen.css" wp_css = css_link "/theme/blueprint/wp/css/blueprint-wp.css"--- ie_css = ie $ css_link "theme/blueprint/core/ie.css" custom_css = css_link "/theme/blueprint/wp/css/custom.css"--rss_tag = rss_link "rss.xml"+rss_tag = rss_link "rss.xml"
Panda/View/Theme/BluePrint/Template/Sidebar.hs view
@@ -2,9 +2,7 @@ import Panda.Helper.Env hiding (rss_link) import Prelude hiding ((.), (/), id, span)-import qualified Panda.Config.Global as Config import qualified Panda.Type.State as State-import Text.XHtml.Strict import qualified Data.Set as Set
Panda/View/Theme/BluePrint/Template/Template.hs view
@@ -3,9 +3,4 @@ import Panda.View.Theme.BluePrint.Template.Header import Panda.View.Theme.BluePrint.Template.Body -import Panda.Helper.Env--page state x = - [ html_head- , html_body state x- ]+page state x = [html_head, html_body state x]
changelog.markdown view
@@ -1,3 +1,14 @@+0.0.0.5+--------++### Features++* Support HTML, reStructuredText and LaTeX in addition to Markdown, just add a the appropriate file extension, no extension defaults to Markdown++### Fix++* cabal dependency on parsec+ 0.0.0.4.2 ----------
panda.cabal view
@@ -1,5 +1,5 @@ Name: panda-Version: 0.0.0.4.2+Version: 0.0.0.5 Build-type: Simple Synopsis: Simple Static Blog Engine Description: Simple Static Blog Engine@@ -14,31 +14,29 @@ data-files: readme.markdown, changelog.markdown library- build-depends: base, cgi, network, haskell98, old-locale, old-time, directory, filepath, containers >= 0.1.0.0, mps >= 0.0.0.1, parsedate >= 3000.0.0, rss >= 3000.0.1, xhtml >= 3000.2.0.0, kibro >= 0.0, utf8-string >= 0.3.1+ build-depends: base, cgi, network, haskell98, old-locale, old-time, directory, filepath, containers >= 0.1.0.0, mps >= 0.0.0.1, parsedate >= 3000.0.0, rss >= 3000.0.1, xhtml >= 3000.2.0.0, kibro >= 0.0, utf8-string >= 0.3.1, pandoc >= 0.46, MissingH, parsec exposed-modules: Panda- Panda.Controller.Application Panda.Config.Global- - Panda.Helper.Helper- Panda.Helper.Escape+ Panda.Controller.Application Panda.Helper.Env-+ Panda.Helper.Escape+ Panda.Helper.Helper Panda.Model.Post+ Panda.Model.Static Panda.Model.Tag- Panda.Type.Pager+ Panda.Type.Reader Panda.Type.State- Panda.View.RSS+ Panda.View.Theme.BluePrint.Helper Panda.View.Theme.BluePrint.Post+ Panda.View.Theme.BluePrint.Search Panda.View.Theme.BluePrint.Static- Panda.View.Theme.BluePrint.Helper Panda.View.Theme.BluePrint.Tag- Panda.View.Theme.BluePrint.Search- Panda.View.Theme.BluePrint.Template.Template- Panda.View.Theme.BluePrint.Template.Header Panda.View.Theme.BluePrint.Template.Body Panda.View.Theme.BluePrint.Template.Footer+ Panda.View.Theme.BluePrint.Template.Header Panda.View.Theme.BluePrint.Template.Sidebar+ Panda.View.Theme.BluePrint.Template.Template
readme.markdown view
@@ -1,4 +1,4 @@-Panda static blogging engine+Panda - simple blogging engine ============================== Sample file db structure@@ -7,23 +7,27 @@ db |---- blog | |---- 08-09-01 first post- | |---- 09-09-02 learn javascript+ | |---- 09-09-02 learn javascript.html | |---- tag- |---- programming- |---- funny+ | |---- programming+ | |---- funny+ |+ |---- static+ |---- About+ Why ---- -* Blog entries are stored locally in markdown format ( can be changed easily with more hacking )+* Blog entries are stored locally+* Write posts in Markdown, HTML, reStructuredText or even LaTeX format ( no Math equations yet ) * Remote server is a mirror of local repository * No server side API for publishing / editing, just use Darcs, Git or any SCM * No need to find external hosting of your videos, images or sound. Put them in public folder ( still managed by SCM if you wish )-* Embed any HTML snippets-* Statically typed HTML combinator = valid html-* Based on Kibro-* Freshman level MVC design+* Easy to use, just create a file and the engine takes care of the rest+* Extensible through embedding any HTML snippets+* Use `custom.css` for theming Quick Demo -----------@@ -36,8 +40,7 @@ ------- Panda is in its early stage. I got tired of importing / exporting blogs when switching blogging platforms, -I needed a way to not be bounded to any service API, and that's the main design goal for Panda. There's no theming yet-(except that you wish to hack the source).+I needed a way to not be bounded to any service API. The main benefit is that if I ever wanted to stop using Panda, all my blogs and resources are in manageable states.