mirror of
https://github.com/aelve/guide.git
synced 2024-11-23 12:15:06 +03:00
Category groups
This commit is contained in:
parent
f560f461d2
commit
db57156b1b
14
src/Cache.hs
14
src/Cache.hs
@ -42,9 +42,9 @@ cache = unsafePerformIO STMMap.newIO
|
|||||||
data CacheKey
|
data CacheKey
|
||||||
= CacheCategoryList
|
= CacheCategoryList
|
||||||
-- categories
|
-- categories
|
||||||
| CacheCategory (Uid Category)
|
| CacheCategory (Uid Category)
|
||||||
| CacheCategoryTitle (Uid Category)
|
| CacheCategoryHeader (Uid Category)
|
||||||
| CacheCategoryNotes (Uid Category)
|
| CacheCategoryNotes (Uid Category)
|
||||||
-- items
|
-- items
|
||||||
| CacheItem (Uid Item)
|
| CacheItem (Uid Item)
|
||||||
| CacheItemInfo (Uid Item)
|
| CacheItemInfo (Uid Item)
|
||||||
@ -58,10 +58,10 @@ instance Hashable CacheKey
|
|||||||
|
|
||||||
cacheDepends :: GlobalState -> CacheKey -> [CacheKey]
|
cacheDepends :: GlobalState -> CacheKey -> [CacheKey]
|
||||||
cacheDepends gs key = case key of
|
cacheDepends gs key = case key of
|
||||||
CacheCategoryList -> [key]
|
CacheCategoryList -> [key]
|
||||||
CacheCategory _ -> [key, CacheCategoryList]
|
CacheCategory _ -> [key, CacheCategoryList]
|
||||||
CacheCategoryTitle x -> [key, CacheCategory x, CacheCategoryList]
|
CacheCategoryHeader x -> [key, CacheCategory x, CacheCategoryList]
|
||||||
CacheCategoryNotes x -> [key, CacheCategory x, CacheCategoryList]
|
CacheCategoryNotes x -> [key, CacheCategory x, CacheCategoryList]
|
||||||
-- If the item's group has been changed, it can influence how other items
|
-- If the item's group has been changed, it can influence how other items
|
||||||
-- in the same category are rendered (specifically, their lists of groups
|
-- in the same category are rendered (specifically, their lists of groups
|
||||||
-- in iteminfo will change)
|
-- in iteminfo will change)
|
||||||
|
11
src/JS.hs
11
src/JS.hs
@ -56,7 +56,8 @@ allJSFunctions = JS . T.unlines . map fromJS $ [
|
|||||||
addCategoryAndRedirect, addItem,
|
addCategoryAndRedirect, addItem,
|
||||||
addPro, addCon,
|
addPro, addCon,
|
||||||
-- Set methods
|
-- Set methods
|
||||||
submitCategoryTitle, submitItemDescription, submitCategoryNotes,
|
submitCategoryTitle, submitCategoryGroup, submitCategoryNotes,
|
||||||
|
submitItemDescription,
|
||||||
submitItemInfo, submitItemNotes, submitItemEcosystem,
|
submitItemInfo, submitItemNotes, submitItemEcosystem,
|
||||||
submitTrait,
|
submitTrait,
|
||||||
-- Other things
|
-- Other things
|
||||||
@ -452,6 +453,14 @@ submitCategoryTitle =
|
|||||||
.done(replaceWithData(node));
|
.done(replaceWithData(node));
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
submitCategoryGroup :: JSFunction a => a
|
||||||
|
submitCategoryGroup =
|
||||||
|
makeJSFunction "submitCategoryGroup" ["node", "catId", "s"]
|
||||||
|
[text|
|
||||||
|
$.post("/haskell/set/category/"+catId+"/group", {content: s})
|
||||||
|
.done(replaceWithData(node));
|
||||||
|
|]
|
||||||
|
|
||||||
submitCategoryNotes :: JSFunction a => a
|
submitCategoryNotes :: JSFunction a => a
|
||||||
submitCategoryNotes =
|
submitCategoryNotes =
|
||||||
makeJSFunction "submitCategoryNotes" ["node", "catId", "s"]
|
makeJSFunction "submitCategoryNotes" ["node", "catId", "s"]
|
||||||
|
23
src/Main.hs
23
src/Main.hs
@ -171,6 +171,7 @@ invalidateCacheForEdit ed = do
|
|||||||
Edit'AddPro itemId _ _ -> [CacheItem itemId]
|
Edit'AddPro itemId _ _ -> [CacheItem itemId]
|
||||||
Edit'AddCon itemId _ _ -> [CacheItem itemId]
|
Edit'AddCon itemId _ _ -> [CacheItem itemId]
|
||||||
Edit'SetCategoryTitle catId _ _ -> [CacheCategory catId]
|
Edit'SetCategoryTitle catId _ _ -> [CacheCategory catId]
|
||||||
|
Edit'SetCategoryGroup catId _ _ -> [CacheCategory catId]
|
||||||
Edit'SetCategoryNotes catId _ _ -> [CacheCategory catId]
|
Edit'SetCategoryNotes catId _ _ -> [CacheCategory catId]
|
||||||
Edit'SetItemName itemId _ _ -> [CacheItem itemId]
|
Edit'SetItemName itemId _ _ -> [CacheItem itemId]
|
||||||
Edit'SetItemLink itemId _ _ -> [CacheItem itemId]
|
Edit'SetItemLink itemId _ _ -> [CacheItem itemId]
|
||||||
@ -212,6 +213,11 @@ undoEdit (Edit'SetCategoryTitle catId old new) = do
|
|||||||
if now /= new
|
if now /= new
|
||||||
then return (Left "title has been changed further")
|
then return (Left "title has been changed further")
|
||||||
else Right () <$ dbUpdate (SetCategoryTitle catId old)
|
else Right () <$ dbUpdate (SetCategoryTitle catId old)
|
||||||
|
undoEdit (Edit'SetCategoryGroup catId old new) = do
|
||||||
|
now <- view group_ <$> dbQuery (GetCategory catId)
|
||||||
|
if now /= new
|
||||||
|
then return (Left "group has been changed further")
|
||||||
|
else Right () <$ dbUpdate (SetCategoryGroup catId old)
|
||||||
undoEdit (Edit'SetCategoryNotes catId old new) = do
|
undoEdit (Edit'SetCategoryNotes catId old new) = do
|
||||||
now <- view (notes.mdText) <$> dbQuery (GetCategory catId)
|
now <- view (notes.mdText) <$> dbQuery (GetCategory catId)
|
||||||
if now /= new
|
if now /= new
|
||||||
@ -270,10 +276,10 @@ undoEdit (Edit'MoveTrait itemId traitId direction) = do
|
|||||||
|
|
||||||
renderMethods :: SpockM () () ServerState ()
|
renderMethods :: SpockM () () ServerState ()
|
||||||
renderMethods = Spock.subcomponent "render" $ do
|
renderMethods = Spock.subcomponent "render" $ do
|
||||||
-- Title of a category
|
-- Header of a category
|
||||||
Spock.get (categoryVar <//> "title") $ \catId -> do
|
Spock.get (categoryVar <//> "header") $ \catId -> do
|
||||||
category <- dbQuery (GetCategory catId)
|
category <- dbQuery (GetCategory catId)
|
||||||
lucidIO $ renderCategoryTitle category
|
lucidIO $ renderCategoryHeader category
|
||||||
-- Notes for a category
|
-- Notes for a category
|
||||||
Spock.get (categoryVar <//> "notes") $ \catId -> do
|
Spock.get (categoryVar <//> "notes") $ \catId -> do
|
||||||
category <- dbQuery (GetCategory catId)
|
category <- dbQuery (GetCategory catId)
|
||||||
@ -309,10 +315,17 @@ setMethods = Spock.subcomponent "set" $ do
|
|||||||
-- Title of a category
|
-- Title of a category
|
||||||
Spock.post (categoryVar <//> "title") $ \catId -> do
|
Spock.post (categoryVar <//> "title") $ \catId -> do
|
||||||
content' <- param' "content"
|
content' <- param' "content"
|
||||||
invalidateCache' (CacheCategoryTitle catId)
|
invalidateCache' (CacheCategoryHeader catId)
|
||||||
(edit, category) <- dbUpdate (SetCategoryTitle catId content')
|
(edit, category) <- dbUpdate (SetCategoryTitle catId content')
|
||||||
addEdit edit
|
addEdit edit
|
||||||
lucidIO $ renderCategoryTitle category
|
lucidIO $ renderCategoryHeader category
|
||||||
|
-- Group of a category
|
||||||
|
Spock.post (categoryVar <//> "group") $ \catId -> do
|
||||||
|
content' <- param' "content"
|
||||||
|
invalidateCache' (CacheCategoryHeader catId)
|
||||||
|
(edit, category) <- dbUpdate (SetCategoryGroup catId content')
|
||||||
|
addEdit edit
|
||||||
|
lucidIO $ renderCategoryHeader category
|
||||||
-- Notes for a category
|
-- Notes for a category
|
||||||
Spock.post (categoryVar <//> "notes") $ \catId -> do
|
Spock.post (categoryVar <//> "notes") $ \catId -> do
|
||||||
content' <- param' "content"
|
content' <- param' "content"
|
||||||
|
125
src/Types.hs
125
src/Types.hs
@ -22,7 +22,6 @@ module Types
|
|||||||
ItemKind(..),
|
ItemKind(..),
|
||||||
hackageName,
|
hackageName,
|
||||||
Item(..),
|
Item(..),
|
||||||
group_,
|
|
||||||
pros,
|
pros,
|
||||||
prosDeleted,
|
prosDeleted,
|
||||||
cons,
|
cons,
|
||||||
@ -54,6 +53,7 @@ module Types
|
|||||||
description,
|
description,
|
||||||
notes,
|
notes,
|
||||||
created,
|
created,
|
||||||
|
group_,
|
||||||
|
|
||||||
-- * Edits
|
-- * Edits
|
||||||
Edit(..),
|
Edit(..),
|
||||||
@ -79,6 +79,7 @@ module Types
|
|||||||
SetGlobalState(..),
|
SetGlobalState(..),
|
||||||
-- *** 'Category'
|
-- *** 'Category'
|
||||||
SetCategoryTitle(..),
|
SetCategoryTitle(..),
|
||||||
|
SetCategoryGroup(..),
|
||||||
SetCategoryNotes(..),
|
SetCategoryNotes(..),
|
||||||
-- *** 'Item'
|
-- *** 'Item'
|
||||||
SetItemName(..),
|
SetItemName(..),
|
||||||
@ -137,6 +138,61 @@ import Utils
|
|||||||
import Markdown
|
import Markdown
|
||||||
|
|
||||||
|
|
||||||
|
{- Note [extending types]
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Here's what you should do if you add a new field to 'Trait', 'Item', or 'Category'.
|
||||||
|
|
||||||
|
|
||||||
|
Types.hs
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
1. Fix all warnings about uninitialised fields that might appear (by e.g. providing a default value).
|
||||||
|
|
||||||
|
2. Update the migration code; see Note [acid-state]. (Usually updating the migration code means simply copying and pasting the old version of the type and adding “_n” to all fields, where ‘n’ is ‘previous n’ + 1.)
|
||||||
|
|
||||||
|
3. If the field is user-editable: add a new constructor to 'Edit' and update the migration code for 'Edit'. Update 'isVacuousEdit', too.
|
||||||
|
|
||||||
|
4. Create a method for updating the field (setSomethingField), add it to the “makeAcidic ''GlobalState” declaration, and export the SetSomethingField type.
|
||||||
|
|
||||||
|
5. Export a lens for the field (if it shares the name with some other field, move it to the “* Overloaded things” heading).
|
||||||
|
|
||||||
|
|
||||||
|
Cache.hs
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
1. If the field is non-trivial (e.g. “notes”) and it makes sense to cache it, add it to 'CacheKey'.
|
||||||
|
|
||||||
|
2. Update 'cacheDepends'.
|
||||||
|
|
||||||
|
|
||||||
|
JS.hs
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
1. If the field is user-editable, add a method for setting it and don't forget to add it to the 'allJSFunctions' list.
|
||||||
|
|
||||||
|
|
||||||
|
View.hs
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
1. If the field is non-trivial, add a method for rendering it.
|
||||||
|
|
||||||
|
2. Don't forget to actually render it if the user is supposed to see it.
|
||||||
|
|
||||||
|
3. Add a branch for the constructor you made in Types.hs/#3 to 'renderEdit'.
|
||||||
|
|
||||||
|
|
||||||
|
Main.hs
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
1. Add a case to 'invalidateCacheForEdit'.
|
||||||
|
|
||||||
|
2. Add a case to 'undoEdit'.
|
||||||
|
|
||||||
|
3. If the field is user-editable, add a method for changing it to 'setMethods'.
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
data Trait = Trait {
|
data Trait = Trait {
|
||||||
_traitUid :: Uid Trait,
|
_traitUid :: Uid Trait,
|
||||||
_traitContent :: MarkdownInline }
|
_traitContent :: MarkdownInline }
|
||||||
@ -311,6 +367,7 @@ hueToLightColor (Hue i) = table !! ((i-1) `mod` length table)
|
|||||||
data Category = Category {
|
data Category = Category {
|
||||||
_categoryUid :: Uid Category,
|
_categoryUid :: Uid Category,
|
||||||
_categoryTitle :: Text,
|
_categoryTitle :: Text,
|
||||||
|
_categoryGroup_ :: Text,
|
||||||
_categoryCreated :: UTCTime,
|
_categoryCreated :: UTCTime,
|
||||||
_categoryNotes :: MarkdownBlock,
|
_categoryNotes :: MarkdownBlock,
|
||||||
_categoryGroups :: Map Text Hue,
|
_categoryGroups :: Map Text Hue,
|
||||||
@ -318,7 +375,7 @@ data Category = Category {
|
|||||||
_categoryItemsDeleted :: [Item] }
|
_categoryItemsDeleted :: [Item] }
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
deriveSafeCopySimple 4 'extension ''Category
|
deriveSafeCopySimple 5 'extension ''Category
|
||||||
makeFields ''Category
|
makeFields ''Category
|
||||||
|
|
||||||
categorySlug :: Category -> Text
|
categorySlug :: Category -> Text
|
||||||
@ -328,28 +385,28 @@ categorySlug category =
|
|||||||
-- Old version, needed for safe migration. It can most likely be already
|
-- Old version, needed for safe migration. It can most likely be already
|
||||||
-- deleted (if a checkpoint has been created), but it's been left here as a
|
-- deleted (if a checkpoint has been created), but it's been left here as a
|
||||||
-- template for future migrations.
|
-- template for future migrations.
|
||||||
data Category_v3 = Category_v3 {
|
data Category_v4 = Category_v4 {
|
||||||
_categoryUid_v3 :: Uid Category,
|
_categoryUid_v4 :: Uid Category,
|
||||||
_categoryTitle_v3 :: Text,
|
_categoryTitle_v4 :: Text,
|
||||||
_categoryCreated_v3 :: UTCTime,
|
_categoryCreated_v4 :: UTCTime,
|
||||||
_categoryNotes_v3 :: MarkdownBlock,
|
_categoryNotes_v4 :: MarkdownBlock,
|
||||||
_categoryGroups_v3 :: Map Text Hue,
|
_categoryGroups_v4 :: Map Text Hue,
|
||||||
_categoryItems_v3 :: [Item],
|
_categoryItems_v4 :: [Item],
|
||||||
_categoryItemsDeleted_v3 :: [Item] }
|
_categoryItemsDeleted_v4 :: [Item] }
|
||||||
|
|
||||||
-- TODO: at the next migration change this to deriveSafeCopySimple!
|
deriveSafeCopySimple 4 'base ''Category_v4
|
||||||
deriveSafeCopy 3 'base ''Category_v3
|
|
||||||
|
|
||||||
instance Migrate Category where
|
instance Migrate Category where
|
||||||
type MigrateFrom Category = Category_v3
|
type MigrateFrom Category = Category_v4
|
||||||
migrate Category_v3{..} = Category {
|
migrate Category_v4{..} = Category {
|
||||||
_categoryUid = _categoryUid_v3,
|
_categoryUid = _categoryUid_v4,
|
||||||
_categoryTitle = _categoryTitle_v3,
|
_categoryTitle = _categoryTitle_v4,
|
||||||
_categoryCreated = _categoryCreated_v3,
|
_categoryGroup_ = "Miscellaneous",
|
||||||
_categoryNotes = _categoryNotes_v3,
|
_categoryCreated = _categoryCreated_v4,
|
||||||
_categoryGroups = _categoryGroups_v3,
|
_categoryNotes = _categoryNotes_v4,
|
||||||
_categoryItems = _categoryItems_v3,
|
_categoryGroups = _categoryGroups_v4,
|
||||||
_categoryItemsDeleted = _categoryItemsDeleted_v3 }
|
_categoryItems = _categoryItems_v4,
|
||||||
|
_categoryItemsDeleted = _categoryItemsDeleted_v4 }
|
||||||
|
|
||||||
-- Edits
|
-- Edits
|
||||||
|
|
||||||
@ -377,6 +434,10 @@ data Edit
|
|||||||
editCategoryUid :: Uid Category,
|
editCategoryUid :: Uid Category,
|
||||||
editCategoryTitle :: Text,
|
editCategoryTitle :: Text,
|
||||||
editCategoryNewTitle :: Text }
|
editCategoryNewTitle :: Text }
|
||||||
|
| Edit'SetCategoryGroup {
|
||||||
|
editCategoryUid :: Uid Category,
|
||||||
|
editCategoryGroup :: Text,
|
||||||
|
editCategoryNewGroup :: Text }
|
||||||
| Edit'SetCategoryNotes {
|
| Edit'SetCategoryNotes {
|
||||||
editCategoryUid :: Uid Category,
|
editCategoryUid :: Uid Category,
|
||||||
editCategoryNotes :: Text,
|
editCategoryNotes :: Text,
|
||||||
@ -442,9 +503,9 @@ data Edit
|
|||||||
|
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
|
||||||
deriveSafeCopySimple 2 'extension ''Edit
|
deriveSafeCopySimple 3 'extension ''Edit
|
||||||
|
|
||||||
genVer ''Edit 1 [
|
genVer ''Edit 2 [
|
||||||
-- Add
|
-- Add
|
||||||
Copy 'Edit'AddCategory,
|
Copy 'Edit'AddCategory,
|
||||||
Copy 'Edit'AddItem,
|
Copy 'Edit'AddItem,
|
||||||
@ -471,12 +532,11 @@ genVer ''Edit 1 [
|
|||||||
Copy 'Edit'MoveItem,
|
Copy 'Edit'MoveItem,
|
||||||
Copy 'Edit'MoveTrait ]
|
Copy 'Edit'MoveTrait ]
|
||||||
|
|
||||||
-- TODO: at the next migration change this to deriveSafeCopySimple!
|
deriveSafeCopySimple 2 'base ''Edit_v2
|
||||||
deriveSafeCopy 1 'base ''Edit_v1
|
|
||||||
|
|
||||||
instance Migrate Edit where
|
instance Migrate Edit where
|
||||||
type MigrateFrom Edit = Edit_v1
|
type MigrateFrom Edit = Edit_v2
|
||||||
migrate = $(migrateVer ''Edit 1 [
|
migrate = $(migrateVer ''Edit 2 [
|
||||||
CopyM 'Edit'AddCategory,
|
CopyM 'Edit'AddCategory,
|
||||||
CopyM 'Edit'AddItem,
|
CopyM 'Edit'AddItem,
|
||||||
CopyM 'Edit'AddPro,
|
CopyM 'Edit'AddPro,
|
||||||
@ -508,6 +568,8 @@ instance Migrate Edit where
|
|||||||
isVacuousEdit :: Edit -> Bool
|
isVacuousEdit :: Edit -> Bool
|
||||||
isVacuousEdit Edit'SetCategoryTitle{..} =
|
isVacuousEdit Edit'SetCategoryTitle{..} =
|
||||||
editCategoryTitle == editCategoryNewTitle
|
editCategoryTitle == editCategoryNewTitle
|
||||||
|
isVacuousEdit Edit'SetCategoryGroup{..} =
|
||||||
|
editCategoryGroup == editCategoryNewGroup
|
||||||
isVacuousEdit Edit'SetCategoryNotes{..} =
|
isVacuousEdit Edit'SetCategoryNotes{..} =
|
||||||
editCategoryNotes == editCategoryNewNotes
|
editCategoryNotes == editCategoryNewNotes
|
||||||
isVacuousEdit Edit'SetItemName{..} =
|
isVacuousEdit Edit'SetItemName{..} =
|
||||||
@ -662,6 +724,7 @@ addCategory catId title' created' = do
|
|||||||
let newCategory = Category {
|
let newCategory = Category {
|
||||||
_categoryUid = catId,
|
_categoryUid = catId,
|
||||||
_categoryTitle = title',
|
_categoryTitle = title',
|
||||||
|
_categoryGroup_ = "Miscellaneous",
|
||||||
_categoryCreated = created',
|
_categoryCreated = created',
|
||||||
_categoryNotes = renderMarkdownBlock "",
|
_categoryNotes = renderMarkdownBlock "",
|
||||||
_categoryGroups = mempty,
|
_categoryGroups = mempty,
|
||||||
@ -736,6 +799,12 @@ setCategoryTitle catId title' = do
|
|||||||
let edit = Edit'SetCategoryTitle catId oldTitle title'
|
let edit = Edit'SetCategoryTitle catId oldTitle title'
|
||||||
(edit,) <$> use (categoryById catId)
|
(edit,) <$> use (categoryById catId)
|
||||||
|
|
||||||
|
setCategoryGroup :: Uid Category -> Text -> Acid.Update GlobalState (Edit, Category)
|
||||||
|
setCategoryGroup catId group' = do
|
||||||
|
oldGroup <- categoryById catId . group_ <<.= group'
|
||||||
|
let edit = Edit'SetCategoryGroup catId oldGroup group'
|
||||||
|
(edit,) <$> use (categoryById catId)
|
||||||
|
|
||||||
setCategoryNotes :: Uid Category -> Text -> Acid.Update GlobalState (Edit, Category)
|
setCategoryNotes :: Uid Category -> Text -> Acid.Update GlobalState (Edit, Category)
|
||||||
setCategoryNotes catId notes' = do
|
setCategoryNotes catId notes' = do
|
||||||
oldNotes <- categoryById catId . notes <<.= renderMarkdownBlock notes'
|
oldNotes <- categoryById catId . notes <<.= renderMarkdownBlock notes'
|
||||||
@ -1050,7 +1119,7 @@ makeAcidic ''GlobalState [
|
|||||||
'addPro, 'addCon,
|
'addPro, 'addCon,
|
||||||
-- set
|
-- set
|
||||||
'setGlobalState,
|
'setGlobalState,
|
||||||
'setCategoryTitle, 'setCategoryNotes,
|
'setCategoryTitle, 'setCategoryGroup, 'setCategoryNotes,
|
||||||
'setItemName, 'setItemLink, 'setItemGroup, 'setItemKind,
|
'setItemName, 'setItemLink, 'setItemGroup, 'setItemKind,
|
||||||
'setItemDescription, 'setItemNotes, 'setItemEcosystem,
|
'setItemDescription, 'setItemNotes, 'setItemEcosystem,
|
||||||
'setTraitContent,
|
'setTraitContent,
|
||||||
|
37
src/View.hs
37
src/View.hs
@ -19,6 +19,7 @@ module View
|
|||||||
renderDonate,
|
renderDonate,
|
||||||
renderCategoryPage,
|
renderCategoryPage,
|
||||||
renderUnwrittenRules,
|
renderUnwrittenRules,
|
||||||
|
renderSearchResults,
|
||||||
|
|
||||||
-- * Tracking
|
-- * Tracking
|
||||||
renderTracking,
|
renderTracking,
|
||||||
@ -28,7 +29,7 @@ module View
|
|||||||
-- ** Categories
|
-- ** Categories
|
||||||
renderCategoryList,
|
renderCategoryList,
|
||||||
renderCategory,
|
renderCategory,
|
||||||
renderCategoryTitle,
|
renderCategoryHeader,
|
||||||
renderCategoryNotes,
|
renderCategoryNotes,
|
||||||
-- ** Items
|
-- ** Items
|
||||||
renderItem,
|
renderItem,
|
||||||
@ -279,6 +280,10 @@ renderEdit globalState edit = do
|
|||||||
Edit'SetCategoryTitle _catId oldTitle newTitle -> p_ $ do
|
Edit'SetCategoryTitle _catId oldTitle newTitle -> p_ $ do
|
||||||
"changed title of category " >> quote (toHtml oldTitle)
|
"changed title of category " >> quote (toHtml oldTitle)
|
||||||
" to " >> quote (toHtml newTitle)
|
" to " >> quote (toHtml newTitle)
|
||||||
|
Edit'SetCategoryGroup catId oldGroup newGroup -> p_ $ do
|
||||||
|
"changed group of category " >> printCategory catId
|
||||||
|
" from " >> quote (toHtml oldGroup)
|
||||||
|
" to " >> quote (toHtml newGroup)
|
||||||
Edit'SetCategoryNotes catId oldNotes newNotes -> do
|
Edit'SetCategoryNotes catId oldNotes newNotes -> do
|
||||||
p_ $ "changed notes of category " >> printCategory catId
|
p_ $ "changed notes of category " >> printCategory catId
|
||||||
table_ $ tr_ $ do
|
table_ $ tr_ $ do
|
||||||
@ -378,7 +383,7 @@ renderHaskellRoot globalState mbSearchQuery =
|
|||||||
| otherwise = filter ((/= 0) . rank) .
|
| otherwise = filter ((/= 0) . rank) .
|
||||||
reverse . sortOn rank
|
reverse . sortOn rank
|
||||||
$ globalState^.categories
|
$ globalState^.categories
|
||||||
renderCategoryList rankedCategories
|
renderSearchResults rankedCategories
|
||||||
-- TODO: maybe add a button like “give me random category that is
|
-- TODO: maybe add a button like “give me random category that is
|
||||||
-- unfinished”
|
-- unfinished”
|
||||||
|
|
||||||
@ -537,6 +542,18 @@ helpVersion = 3
|
|||||||
-- 'Cache.invalidateCache'.
|
-- 'Cache.invalidateCache'.
|
||||||
renderCategoryList :: (MonadIO m, MonadRandom m) => [Category] -> HtmlT m ()
|
renderCategoryList :: (MonadIO m, MonadRandom m) => [Category] -> HtmlT m ()
|
||||||
renderCategoryList cats = cached CacheCategoryList $ do
|
renderCategoryList cats = cached CacheCategoryList $ do
|
||||||
|
div_ [id_ "categories"] $
|
||||||
|
for_ (groupWith (view group_) cats) $ \gr ->
|
||||||
|
div_ [class_ "category-group"] $ do
|
||||||
|
h2_ $ toHtml (gr^?!_head.group_)
|
||||||
|
for gr $ \category -> do
|
||||||
|
-- TODO: this link shouldn't be absolute [absolute-links]
|
||||||
|
a_ [href_ ("/haskell/" <> categorySlug category)] $
|
||||||
|
toHtml (category^.title)
|
||||||
|
br_ []
|
||||||
|
|
||||||
|
renderSearchResults :: Monad m => [Category] -> HtmlT m ()
|
||||||
|
renderSearchResults cats = do
|
||||||
div_ [id_ "categories"] $
|
div_ [id_ "categories"] $
|
||||||
for_ cats $ \category -> do
|
for_ cats $ \category -> do
|
||||||
-- TODO: this link shouldn't be absolute [absolute-links]
|
-- TODO: this link shouldn't be absolute [absolute-links]
|
||||||
@ -544,8 +561,8 @@ renderCategoryList cats = cached CacheCategoryList $ do
|
|||||||
toHtml (category^.title)
|
toHtml (category^.title)
|
||||||
br_ []
|
br_ []
|
||||||
|
|
||||||
renderCategoryTitle :: MonadIO m => Category -> HtmlT m ()
|
renderCategoryHeader :: MonadIO m => Category -> HtmlT m ()
|
||||||
renderCategoryTitle category = cached (CacheCategoryTitle (category^.uid)) $ do
|
renderCategoryHeader category = cached (CacheCategoryHeader (category^.uid)) $ do
|
||||||
let thisId = "category-title-" <> uidToText (category^.uid)
|
let thisId = "category-title-" <> uidToText (category^.uid)
|
||||||
this = JS.selectId thisId
|
this = JS.selectId thisId
|
||||||
h2_ [id_ thisId, class_ "category-title"] $ do
|
h2_ [id_ thisId, class_ "category-title"] $ do
|
||||||
@ -560,6 +577,9 @@ renderCategoryTitle category = cached (CacheCategoryTitle (category^.uid)) $ do
|
|||||||
a_ [href_ ("/haskell/" <> categorySlug category)] $
|
a_ [href_ ("/haskell/" <> categorySlug category)] $
|
||||||
toHtml (category^.title)
|
toHtml (category^.title)
|
||||||
emptySpan "1em"
|
emptySpan "1em"
|
||||||
|
span_ [class_ "group"] $
|
||||||
|
toHtml (category^.group_)
|
||||||
|
emptySpan "1em"
|
||||||
textButton "edit" $
|
textButton "edit" $
|
||||||
JS.switchSection (this, "editing" :: Text)
|
JS.switchSection (this, "editing" :: Text)
|
||||||
emptySpan "1em"
|
emptySpan "1em"
|
||||||
@ -572,6 +592,13 @@ renderCategoryTitle category = cached (CacheCategoryTitle (category^.uid)) $ do
|
|||||||
autocomplete_ "off",
|
autocomplete_ "off",
|
||||||
onEnter $
|
onEnter $
|
||||||
JS.submitCategoryTitle (this, category^.uid, inputValue)]
|
JS.submitCategoryTitle (this, category^.uid, inputValue)]
|
||||||
|
emptySpan "0.5em"
|
||||||
|
textInput [
|
||||||
|
class_ "group",
|
||||||
|
value_ (category^.group_),
|
||||||
|
autocomplete_ "off",
|
||||||
|
onEnter $
|
||||||
|
JS.submitCategoryGroup (this, category^.uid, inputValue)]
|
||||||
emptySpan "1em"
|
emptySpan "1em"
|
||||||
textButton "cancel" $
|
textButton "cancel" $
|
||||||
JS.switchSection (this, "normal" :: Text)
|
JS.switchSection (this, "normal" :: Text)
|
||||||
@ -604,7 +631,7 @@ renderCategoryNotes category = cached (CacheCategoryNotes (category^.uid)) $ do
|
|||||||
renderCategory :: (MonadIO m, MonadRandom m) => Category -> HtmlT m ()
|
renderCategory :: (MonadIO m, MonadRandom m) => Category -> HtmlT m ()
|
||||||
renderCategory category = cached (CacheCategory (category^.uid)) $ do
|
renderCategory category = cached (CacheCategory (category^.uid)) $ do
|
||||||
div_ [class_ "category", id_ (categoryNodeId category)] $ do
|
div_ [class_ "category", id_ (categoryNodeId category)] $ do
|
||||||
renderCategoryTitle category
|
renderCategoryHeader category
|
||||||
renderCategoryNotes category
|
renderCategoryNotes category
|
||||||
itemsNode <- div_ [class_ "items"] $ do
|
itemsNode <- div_ [class_ "items"] $ do
|
||||||
mapM_ (renderItem category) (category^.items)
|
mapM_ (renderItem category) (category^.items)
|
||||||
|
@ -47,12 +47,18 @@ body {
|
|||||||
width: 100%; }
|
width: 100%; }
|
||||||
|
|
||||||
#categories {
|
#categories {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: space-between;
|
||||||
margin-top: 1em; }
|
margin-top: 1em; }
|
||||||
|
|
||||||
#categories > a {
|
#categories a {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 130%;
|
line-height: 100%;
|
||||||
font-size: 150%; }
|
font-size: 110%; }
|
||||||
|
|
||||||
|
.category-group {
|
||||||
|
min-width: 350px; }
|
||||||
|
|
||||||
.category {
|
.category {
|
||||||
margin-top: 3em; }
|
margin-top: 3em; }
|
||||||
@ -78,6 +84,11 @@ body {
|
|||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
height: 20px; }
|
height: 20px; }
|
||||||
|
|
||||||
|
.category-title .group {
|
||||||
|
font-size: 60%;
|
||||||
|
font-weight: normal;
|
||||||
|
color: gray; }
|
||||||
|
|
||||||
.item-traits, .item-notes, .item-description, .item-ecosystem {
|
.item-traits, .item-notes, .item-description, .item-ecosystem {
|
||||||
padding: 10px 15px 20px 15px; }
|
padding: 10px 15px 20px 15px; }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user