Write blog post list component

This commit is contained in:
2025-10-02 12:12:59 +02:00
parent 7432a46ae2
commit 278f51ce2e
12 changed files with 205 additions and 100 deletions

View File

@@ -1,18 +1,20 @@
Class {
#name : #TBApplicationRootComponent,
#superclass : #WAComponent,
#name : 'TBApplicationRootComponent',
#superclass : 'WAComponent',
#instVars : [
'main'
],
#category : #'TinyBlog-Components'
#category : 'TinyBlog-Components-Components',
#package : 'TinyBlog-Components',
#tag : 'Components'
}
{ #category : #testing }
{ #category : 'testing' }
TBApplicationRootComponent class >> canBeRoot [
^ true
]
{ #category : #initialization }
{ #category : 'initialization' }
TBApplicationRootComponent class >> initialize [
"self initialize"
| app |
@@ -23,23 +25,29 @@ TBApplicationRootComponent class >> initialize [
addLibrary: SBSDeploymentLibrary
]
{ #category : #rendering }
{ #category : 'rendering' }
TBApplicationRootComponent >> children [
^ { main }
]
{ #category : #initialization }
{ #category : 'initialization' }
TBApplicationRootComponent >> initialize [
super initialize.
main := TBScreenComponent new
main := TBPostsListComponent new
]
{ #category : #rendering }
{ #category : 'initialization' }
TBApplicationRootComponent >> main: aComponent [
main := aComponent
]
{ #category : 'rendering' }
TBApplicationRootComponent >> renderContentOn: html [
html render: main
]
{ #category : #rendering }
{ #category : 'rendering' }
TBApplicationRootComponent >> updateRoot: anHtmlRoot [
super updateRoot: anHtmlRoot.
anHtmlRoot beHtml5.

View File

@@ -0,0 +1,27 @@
Class {
#name : 'TBHeaderComponent',
#superclass : 'SBSComponent',
#category : 'TinyBlog-Components-Components',
#package : 'TinyBlog-Components',
#tag : 'Components'
}
{ #category : 'rendering' }
TBHeaderComponent >> renderBrandOn: html [
html navigationBarBrand
url: self application url;
with: 'TinyBlog'
]
{ #category : 'rendering' }
TBHeaderComponent >> renderContentOn: html [
| bar |
bar := html navigationBar.
bar background beLight.
bar with: [
html container: [
self renderBrandOn: html
]
]
]

View File

@@ -0,0 +1,43 @@
Class {
#name : 'TBPostComponent',
#superclass : 'SBSComponent',
#instVars : [
'post'
],
#category : 'TinyBlog-Components-Components',
#package : 'TinyBlog-Components',
#tag : 'Components'
}
{ #category : 'initialization' }
TBPostComponent >> date [
^ post date
]
{ #category : 'initialization' }
TBPostComponent >> initialize [
super initialize.
post := TBPost new
]
{ #category : 'initialization' }
TBPostComponent >> post: aPost [
post := aPost
]
{ #category : 'initialization' }
TBPostComponent >> renderContentOn: html [
html heading level: 2; with: self title.
html heading level: 6; with: self date.
html text: self text
]
{ #category : 'initialization' }
TBPostComponent >> text [
^ post text
]
{ #category : 'initialization' }
TBPostComponent >> title [
^ post title
]

View File

@@ -0,0 +1,41 @@
Class {
#name : 'TBPostsListComponent',
#superclass : 'TBScreenComponent',
#instVars : [
'postComponents'
],
#category : 'TinyBlog-Components-Components',
#package : 'TinyBlog-Components',
#tag : 'Components'
}
{ #category : 'initialization' }
TBPostsListComponent >> children [
^ self postComponents, super children
]
{ #category : 'initialization' }
TBPostsListComponent >> initialize [
super initialize.
postComponents := OrderedCollection new
]
{ #category : 'initialization' }
TBPostsListComponent >> postComponents [
postComponents := self readSelectedPosts
collect: [ :each | TBPostComponent new post: each ].
^ postComponents
]
{ #category : 'initialization' }
TBPostsListComponent >> readSelectedPosts [
^ self blog allVisibleBlogPosts
]
{ #category : 'rendering' }
TBPostsListComponent >> renderContentOn: html [
super renderContentOn: html.
html container: [
self postComponents do: [ :p |
html render: p ] ]
]

View File

@@ -1,36 +1,38 @@
Class {
#name : #TBScreenComponent,
#superclass : #WAComponent,
#name : 'TBScreenComponent',
#superclass : 'SBSRootComponent',
#instVars : [
'header'
],
#category : #'TinyBlog-Components'
#category : 'TinyBlog-Components-Components',
#package : 'TinyBlog-Components',
#tag : 'Components'
}
{ #category : #acccessing }
{ #category : 'acccessing' }
TBScreenComponent >> blog [
"Return the current blog. In the future we will ask the
session to return the blog of the currently logged in user."
^ TBBlog current
]
{ #category : #acccessing }
{ #category : 'acccessing' }
TBScreenComponent >> children [
^ { header }
]
{ #category : #initialization }
{ #category : 'initialization' }
TBScreenComponent >> createHeaderComponent [
^ TBHeaderComponent new
]
{ #category : #initialization }
{ #category : 'initialization' }
TBScreenComponent >> initialize [
super initialize.
header := self createHeaderComponent
]
{ #category : #acccessing }
{ #category : 'acccessing' }
TBScreenComponent >> renderContentOn: html [
html render: header
]

View File

@@ -0,0 +1 @@
Package { #name : 'TinyBlog-Components' }

View File

@@ -1,13 +1,14 @@
Class {
#name : #TBBlog,
#superclass : #Object,
#name : 'TBBlog',
#superclass : 'Object',
#instVars : [
'posts'
],
#category : #TinyBlog
#category : 'TinyBlog',
#package : 'TinyBlog'
}
{ #category : #demos }
{ #category : 'demos' }
TBBlog class >> createDemoPosts [
"TBBlog createDemoPosts"
self current
@@ -29,7 +30,7 @@ TBBlog class >> createDemoPosts [
category: 'Pharo') visible: true)
]
{ #category : #initialization }
{ #category : 'initialization' }
TBBlog class >> current [
"answer the instance of the TBRepository"
^ self selectAll
@@ -37,70 +38,70 @@ TBBlog class >> current [
ifEmpty: [ self new save ]
]
{ #category : #initialization }
{ #category : 'initialization' }
TBBlog class >> initialize [
self reset
]
{ #category : #reading }
{ #category : 'reading' }
TBBlog class >> initializeVoyageOnMemoryDB [
VOMemoryRepository new enableSingleton
]
{ #category : #reading }
{ #category : 'reading' }
TBBlog class >> isVoyageRoot [
"Indicates that instances of this class are top level documents in noSQL databases"
^ true
]
{ #category : #initialization }
{ #category : 'initialization' }
TBBlog class >> reset [
self initializeVoyageOnMemoryDB.
]
{ #category : #reading }
{ #category : 'reading' }
TBBlog >> allBlogPosts [
^ posts
]
{ #category : #reading }
{ #category : 'reading' }
TBBlog >> allBlogPostsFromCategory: aCategory [
^ posts select: [ :p | p category = aCategory ]
]
{ #category : #reading }
{ #category : 'reading' }
TBBlog >> allCategories [
^ (self allBlogPosts collect: [ :p | p category ]) asSet
]
{ #category : #reading }
{ #category : 'reading' }
TBBlog >> allVisibleBlogPosts [
^ posts select: [ :p | p isVisible ]
]
{ #category : #reading }
{ #category : 'reading' }
TBBlog >> allVisibleBlogPostsFromCategory: aCategory [
^ posts select: [ :p | p category = aCategory and: [ p isVisible ] ]
]
{ #category : #initialization }
{ #category : 'initialization' }
TBBlog >> initialize [
super initialize.
posts := OrderedCollection new
]
{ #category : #deleting }
{ #category : 'deleting' }
TBBlog >> removeAllPosts [
posts := OrderedCollection new.
self save
]
{ #category : #initialization }
{ #category : 'initialization' }
TBBlog >> size [
^ posts size
]
{ #category : #writing }
{ #category : 'writing' }
TBBlog >> writeBlogPost: aPost [
"Add the blog post in database."
self allBlogPosts add: aPost.

View File

@@ -1,16 +1,18 @@
Class {
#name : #TBBlogTest,
#superclass : #TestCase,
#name : 'TBBlogTest',
#superclass : 'TestCase',
#instVars : [
'blog',
'post',
'first',
'previousRepository'
],
#category : #'TinyBlog-Tests'
#category : 'TinyBlog-Tests',
#package : 'TinyBlog',
#tag : 'Tests'
}
{ #category : #running }
{ #category : 'running' }
TBBlogTest >> setUp [
previousRepository := VORepository current.
VORepository setRepository: VOMemoryRepository new.
@@ -21,60 +23,60 @@ TBBlogTest >> setUp [
post := (TBPost title: 'Another title' text: 'Another text' category: 'Second Category') beVisible
]
{ #category : #running }
{ #category : 'running' }
TBBlogTest >> tearDown [
VORepository setRepository: previousRepository
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testAddBlogPost [
blog writeBlogPost: post.
self assert: blog size equals: 2
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testAllBlogPosts [
blog writeBlogPost: post.
self assert: blog allBlogPosts size equals: 2
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testAllBlogPostsFromCategory [
self assert: (blog allBlogPostsFromCategory: 'First Category')
size equals: 1
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testAllCategories [
blog writeBlogPost: post.
self assert: blog allCategories size equals: 2
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testAllVisibleBlogPosts [
blog writeBlogPost: post.
self assert: blog allVisibleBlogPosts size equals: 1
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testAllVisibleBlogPostsFromCategory [
blog writeBlogPost: post.
self assert: (blog allVisibleBlogPostsFromCategory: 'First Category') size equals: 0.
self assert: (blog allVisibleBlogPostsFromCategory: 'Second Category') size equals: 1.
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testRemoveAllBlogPosts [
blog removeAllPosts.
self assert: blog size equals: 0
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testSize [
self assert: blog size equals: 1
]
{ #category : #tests }
{ #category : 'tests' }
TBBlogTest >> testUnclassifiedBlogPosts [
self assert: (blog allBlogPosts select: [ :p | p isUnclassified ]) size equals: 0
]

View File

@@ -1,23 +0,0 @@
Class {
#name : #TBHeaderComponent,
#superclass : #WAComponent,
#category : #'TinyBlog-Components'
}
{ #category : #rendering }
TBHeaderComponent >> renderBrandOn: html [
html tbsNavbarHeader: [
html tbsNavbarBrand
url: self application url;
with: 'TinyBlog'
]
]
{ #category : #rendering }
TBHeaderComponent >> renderContentOn: html [
html tbsNavbar beDefault; with: [
html tbsContainer: [
self renderBrandOn: html
]
]
]

View File

@@ -1,6 +1,6 @@
Class {
#name : #TBPost,
#superclass : #Object,
#name : 'TBPost',
#superclass : 'Object',
#instVars : [
'title',
'text',
@@ -8,10 +8,11 @@ Class {
'category',
'visible'
],
#category : #TinyBlog
#category : 'TinyBlog',
#package : 'TinyBlog'
}
{ #category : #'instance creation' }
{ #category : 'instance creation' }
TBPost class >> title: aTitle text: aText [
^ self new
title: aTitle;
@@ -19,48 +20,48 @@ TBPost class >> title: aTitle text: aText [
yourself
]
{ #category : #'instance creation' }
{ #category : 'instance creation' }
TBPost class >> title: aTitle text: aText category: aCategory [
^ (self title: aTitle text: aText)
category: aCategory;
yourself
]
{ #category : #'as yet unclassified' }
{ #category : 'as yet unclassified' }
TBPost class >> unclassifiedTag [
^ 'Unclassified'
]
{ #category : #action }
{ #category : 'action' }
TBPost >> beVisible [
self visible: true
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> category [
^ category
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> category: anObject [
category := anObject
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> date [
^ date
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> date: anObject [
date := anObject
]
{ #category : #initialization }
{ #category : 'initialization' }
TBPost >> initialize [
super initialize.
self category: self class unclassifiedTag.
@@ -68,52 +69,52 @@ TBPost >> initialize [
self notVisible.
]
{ #category : #testing }
{ #category : 'testing' }
TBPost >> isUnclassified [
^ self category = self class unclassifiedTag
]
{ #category : #testing }
{ #category : 'testing' }
TBPost >> isVisible [
^ self visible
]
{ #category : #action }
{ #category : 'action' }
TBPost >> notVisible [
self visible: false
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> text [
^ text
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> text: anObject [
text := anObject
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> title [
^ title
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> title: anObject [
title := anObject
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> visible [
^ visible
]
{ #category : #accessing }
{ #category : 'accessing' }
TBPost >> visible: anObject [
visible := anObject

View File

@@ -1,10 +1,12 @@
Class {
#name : #TBPostTest,
#superclass : #TestCase,
#category : #'TinyBlog-Tests'
#name : 'TBPostTest',
#superclass : 'TestCase',
#category : 'TinyBlog-Tests',
#package : 'TinyBlog',
#tag : 'Tests'
}
{ #category : #tests }
{ #category : 'tests' }
TBPostTest >> testPostIsCreatedCorrectly [
| post |
@@ -16,7 +18,7 @@ TBPostTest >> testPostIsCreatedCorrectly [
self assert: post text equals: 'TinyBlog is a small blog engine made with Pharo.'.
]
{ #category : #tests }
{ #category : 'tests' }
TBPostTest >> testWithoutCategoryIsUnclassified [
| post |

View File

@@ -1 +1 @@
Package { #name : #TinyBlog }
Package { #name : 'TinyBlog' }