Compare commits

...

43 Commits

Author SHA1 Message Date
2875964efc Replacing temporal downloded folders for new themes. 2024-10-20 19:59:36 -05:00
7b86b2cfeb Replacing in memory process from GtSubProcess instead of TaskIt futures. 2024-08-02 14:19:00 -05:00
af81f92399 Using GtSubProcess to work on memory and avoid external files creation. 2024-08-02 13:29:56 -05:00
b500a65c00 Renaming. 2024-04-03 10:15:32 -05:00
83ea8d4310 Renaming. 2024-04-01 13:16:55 -05:00
2d811e9f38 Default server shared with the one serving MiniDocs. 2024-03-30 18:06:16 -05:00
a8d12ec46f Implementing components. #defaultView needs to be debugged. 2024-03-30 13:40:50 -05:00
c609595272 Starting implementation of default app view body. 2024-03-30 10:41:25 -05:00
81298aefba Starting implementation of default app view body. 2024-03-30 10:24:17 -05:00
72e0c775e5 Default view as a code block. 2024-03-29 22:25:37 -05:00
f3a1927615 Starting default views. 2024-03-29 21:46:34 -05:00
a96dd95359 Default shared server with MiniDocs to create App views/(sub)routes. 2024-03-29 20:27:48 -05:00
8833341eee Starting BreaApps. 2024-03-29 20:11:27 -05:00
bbda57b908 Replacing GrafoscopioUtils for MiniDocs as a dependency. 2024-03-29 19:13:57 -05:00
f0dfea31b5 Testing future collections. 2023-12-10 13:44:11 -05:00
ef3218a343 Renabling themes downloading. 2023-12-09 18:20:38 -05:00
f29ea2d014 Reenabling themes download. 2023-12-09 18:19:18 -05:00
b0498bfcc5 Disabling Noha's Fork to make Brea installable. 2021-05-08 17:41:33 -05:00
5b04df81b7 Merge 6055fd04f4 2020-12-19 11:24:36 -05:00
9f28bccc1e Support for BreaOperators 2020-12-19 11:24:21 -05:00
6055fd04f4 Merge pull request 'Improving Windows support.' (#2) from Windows into master 2020-12-18 13:54:40 -05:00
51ad9a8e12 Merge 9f0f06d285 2020-12-18 10:50:24 -08:00
1044fb4997 Improving Windows support. 2020-12-18 10:06:54 -08:00
9f0f06d285 Support for Airtable data sources, publishing tests and now BreaQueries are part of the BreaThemes. 2020-12-05 21:16:14 -05:00
3cb08d4d2c Fixing typo with wrong number of parenthesis. 2020-11-21 17:08:59 -05:00
72098ee5b9 Updated test. Need to improve on Internet line endings. 2020-11-21 14:15:38 -05:00
ffeeff423b Adding tests package. 2020-11-21 13:34:20 -05:00
ba03def62c Code cleaning. Improving html export. 2020-11-19 19:05:28 -05:00
e839ee18c8 Initial support for JSON files as page template metadata finished. 2020-11-07 12:07:04 -05:00
45f1ac84b1 Making bodyTag optinal in HTML templates, in preparation for JSON support. 2020-11-07 11:47:41 -05:00
cd938cf480 Starting support for json data files. 2020-11-07 10:24:01 -05:00
c11c00b7d1 GrafoscopioUtils as dependency and starting theme configuration. 2020-10-23 21:50:53 -05:00
471353880e Renaming and PetitParser for YAML. 2020-10-21 18:40:05 -05:00
321daf7165 Scripts installation. 2020-10-08 17:37:22 -05:00
bdd1813efb External page metadata and subpages support. 2020-08-28 20:25:35 -05:00
60c94d23e5 Starting modelling available theme packs and providers. 2020-08-15 12:23:24 -05:00
4bd52732ab Starting themes customization. 2020-08-13 19:14:20 -05:00
c7fb5d8900 Starting Brea Themes and their installation. 2020-08-07 14:04:45 -05:00
c2fafbbad4 Merge 9a71c35602 2020-08-01 18:49:42 -05:00
8900a33b1b Splitting Mustache templates supporting a common pattern. 2020-08-01 18:49:28 -05:00
9a71c35602 Documentación en un sólo repo para que sea consistente. 2020-07-27 21:17:47 -05:00
e759f93afb Merge 1a6c46840a 2020-07-27 21:12:00 -05:00
e5303fa3e7 Wiki pages preliminar exportation working. 2020-07-26 21:09:53 -05:00
23 changed files with 1074 additions and 1185 deletions

View File

@ -9,44 +9,8 @@ A simple dynamic distributed web site generator for public & open data, combinin
- [Markdeep][markdeep]: for agile and structured light documentation.
- **Middleware**: [Teapot][teapot]: for defining behavior, data models and connecting front-end and backend.
This is the [documentation and issues repository][brea-fossil].
The [source code repository](http://smalltalkhub.com/#!/~Offray/Brea) is hosted in SmalltalkHub.
This is the source code repository. For more information visit the [documentation and issues repository][brea-fossil].
To start run this code from [Pharo](http://pharo.org/) 6.1:
```
Metacello new
smalltalkhubUser: 'Offray' project: 'Brea';
configuration: 'Brea';
load.
```
For further instructions and documentation the recommended way to proceed is by downloading, reading and executing
the [Brea Grafoscopio interactive notebook](./doc/tip/brea.ston)
(you will need to have [Grafoscopio][grafoscopio:en] installed and to know how to use it).
![The Grafoscopio interactive notebook documenting Brea.](https://i.imgur.com/Cq8ygi9.png)
The name came out as part of a friends joke, talking about how [brea][w:brea] ([pitch][w:pitch])
allows the easy creation and preservation of fossils. This is the current incarnation of an
old project prototyped with the excellent [web2py][web2py], but this time with the advantages
of Pharo ecosystem, particularly [live coding][w:live-coding].
## Why two source code repositories?
We split the repositories in two because the Fossil powered one is well suited for files and tickets,
while the SmalltalkHub one is best suited for Smalltalk source code.
For historical reasons, different Smalltalk communities developed and hosted their source code there,
which gives them the autonomy of a simple and self-contained DVCS, that was wrote in the language they knew.
That was before the popularity of DVCS advanced by Git and GitHub, and now most projects are being migrated to
GitHub to get more visibility and improve collaboration (SmalltalkHub uses an simple optimistic versioning
system that is showing its age), while sacrificing autonomy, simplicity and self-containment.
We think that Fossil as a back end could provide the advantages of a modern DVCS, while keeping
the properties we like to have regarding autonomy, simplicity and self-containment.
At some point we hope that the work is being done in the Git/GitHub front to migrate
source code from Smalltalk would be useful to host a single Fossil repository containing
software and documentation (and issues for both).
Meanwhile, we will split them in the ones mentioned before.
[brea-fossil]: http://mutabit.com/repos.fossil/brea/home
[fossil]: http://fossil-scm.org/

View File

@ -16,12 +16,27 @@ BaselineOfBrea >> baseline: spec [
for: #common
do: [
"Dependencies"
self miniDocs: spec.
spec
baseline: 'NeoJSON' with: [ spec repository: 'github://svenvc/NeoJSON/repository' ];
baseline: 'Mustache' with: [ spec repository: 'github://noha/mustache/repository' ];
baseline: 'TaskIt' with: [ spec repository: 'github://noha/taskit:add-all-future' ].
baseline: 'TaskIt' with: [ spec repository: 'github://pharo-contributions/taskit:v1.0' ]
"[ spec repository: 'github://noha/taskit:add-all-future' ]"
"Disabling Noha's Fork to make Brea installable.".
"Packages"
spec package: 'Brea' with: [ spec requires: #('NeoJSON' 'Mustache' 'TaskIt') ].
spec package: 'Brea' with: [ spec requires: #('MiniDocs' 'TaskIt') ].
]
]
{ #category : #baselines }
BaselineOfBrea >> miniDocs: spec [
| repo |
repo := ExoRepo new
repository: 'https://code.tupale.co/Offray/MiniDocs'.
repo
onConflict: [ :ex | ex useLoaded ];
onUpgrade: [ :ex | ex useLoaded ];
onDowngrade: [ :ex | ex useLoaded ];
onWarningLog;
load.
spec baseline: 'MiniDocs' with: [ spec repository: 'gitlocal://', repo local fullName ]
]

View File

@ -0,0 +1,21 @@
"
A BreaQueryTest is a test class for testing the behavior of BreaQuery
"
Class {
#name : #BreaOperatorTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}
{ #category : #tests }
BreaOperatorTest >> testSTONSerialization [
| original store deserialized |
original := BreaOperator new
name: 'plus';
inputs: {'a' -> 3. 'b' -> 4} asDictionary;
codeBlock: [ :x :y | x + y ].
store := STON toString: original.
deserialized := (STONReader on: store readStream) next.
self assert: original execute equals: deserialized execute
]

View File

@ -0,0 +1,204 @@
"
A BreaPageTest is a test class for testing the behavior of BreaPage
"
Class {
#name : #BreaPageTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}
{ #category : #initialization }
BreaPageTest >> createHTMLTemplateFile [
| testFile contents |
testFile := FileLocator temp / 'template.mus.html'.
testFile ensureCreateFile.
contents :=
'<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
<p>
{{#show}} You should see me. {{/show}}
</p>
<p>
{{#unhide}} You should not see me. {{/unhide}}
</p>
{{{ contents }}}
</body>
</html>'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #initialization }
BreaPageTest >> createJSONFile [
| testFile contents |
testFile := self jsonTestFile.
testFile ensureCreateFile.
contents := '{ "title": "This is a test", "show": true, "unhide": false }'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #initialization }
BreaPageTest >> createMarkdownFile [
| testFile contents |
testFile := self markdownTestFile.
testFile ensureCreateFile.
contents :=
'---
title: This is a test
show: true
unhide: false
---
# Level one header
And paragraph contents with _emphasis_ and **strong emphasis**.'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> htmlBodyContents [
^ '<h1 id="level-one-header">Level one header</h1>
<p>And paragraph contents with <em>emphasis</em> and <strong>strong emphasis</strong>.</p>
'
]
{ #category : #'as yet unclassified' }
BreaPageTest >> htmlOutput [
^ '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>This is a test</title>
</head>
<body>
<h1>This is a test</h1>
<p>
You should see me.
</p>
<p>
</p>
', self htmlBodyContents,
'
</body>
</html>'
]
{ #category : #'as yet unclassified' }
BreaPageTest >> jsonTestFile [
^ FileLocator temp / 'test1.json'.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> markdownTestFile [
^ FileLocator temp / 'test.md'.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> setUp [
"I create disposable simple files for testing purposes."
super setUp.
self createMarkdownFile.
self createHTMLTemplateFile.
self createJSONFile
]
{ #category : #tests }
BreaPageTest >> testJSONMetadataExtraction [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test1';
folder: FileLocator temp.
self assert: page metadata equals: testMetadata
]
{ #category : #tests }
BreaPageTest >> testJSONPopulateMetadata [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test1';
folder: FileLocator temp.
page templateData at: 'extra' put: 'value'.
self assert: page populateMetadata equals: (testMetadata at: 'extra' put: 'value'; yourself)
]
{ #category : #tests }
BreaPageTest >> testMarkdownContentExtraction [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
self assert: page contents equals: self markdownTestFile contents.
]
{ #category : #tests }
BreaPageTest >> testMarkdownHTMLExport [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp;
template: 'template.mus.html';
bodyTag: 'contents'.
self assert: (page exportAsHTML contents) equals: self htmlOutput.
]
{ #category : #tests }
BreaPageTest >> testMarkdownMetadataExtraction [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
self assert: page metadata equals: testMetadata
]
{ #category : #tests }
BreaPageTest >> testMarkdownPopulateBody [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp;
bodyTag: 'contents'.
page populateTaggedBody.
self assert: (page templateData at: 'contents') equals: self htmlBodyContents.
]
{ #category : #tests }
BreaPageTest >> testMarkdownPopulateMetadata [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
page templateData at: 'extra' put: 'value'.
self assert: page populateMetadata equals: (testMetadata at: 'extra' put: 'value'; yourself)
]

View File

@ -0,0 +1 @@
Package { #name : #'Brea-Tests' }

View File

@ -0,0 +1,20 @@
Extension { #name : #BlockClosure }
{ #category : #'*Brea' }
BlockClosure class >> fromSton: stonReader [
^ self compilerClass new
source: stonReader parseListSingleton;
evaluate
]
{ #category : #'*Brea' }
BlockClosure >> stonContainSubObjects [
^ false
]
{ #category : #'*Brea' }
BlockClosure >> stonOn: stonWriter [
self isClean
ifTrue: [ stonWriter writeObject: self listSingleton: self printString ]
ifFalse: [ stonWriter error: 'Only clean block can be serialized' ]
]

View File

@ -0,0 +1,104 @@
Class {
#name : #BreaApp,
#superclass : #Object,
#instVars : [
'name',
'folder',
'host',
'componets'
],
#category : #Brea
}
{ #category : #accessing }
BreaApp >> add: anObject [
anObject class = String ifFalse: [ ].
self body
nextPutAll: (Pandoc htmlStringToMarkdown: anObject); cr.
]
{ #category : #accessing }
BreaApp >> appName [
^ self name asCamelCase
]
{ #category : #accessing }
BreaApp >> at: key put: anObject [
self components at: key put: anObject.
]
{ #category : #accessing }
BreaApp >> components [
^ componets ifNil: [ componets := OrderedDictionary new]
]
{ #category : #accessing }
BreaApp >> componentsWebView [
| response |
response := '' writeStream.
self components ifEmpty: [ ^ response contents ].
self components valuesDo: [ :component |
response
nextPutAll: component webView; cr
].
^ response contents
]
{ #category : #accessing }
BreaApp >> defaultView [
^ '<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark" />
<link rel="stylesheet" href="css/pico.min.css">
<title>', self name, '</title>
</head>
<body>
<main class="container">
', self componentsWebView,'
</main>
</body>
</html>'
]
{ #category : #accessing }
BreaApp >> folder [
^ folder
]
{ #category : #accessing }
BreaApp >> folder: aFileDirectory [
folder := aFileDirectory
]
{ #category : #accessing }
BreaApp >> name [
^ name
]
{ #category : #accessing }
BreaApp >> name: aString [
name := aString
]
{ #category : #accessing }
BreaApp >> parentFolder: anObject [
self folder: anObject / self name asCamelCase
]
{ #category : #accessing }
BreaApp >> preview [
| defaultRoute |
defaultRoute := 'http://localhost:',self webHost server port asString, '/', self appName.
self webHost
GET: self appName -> [ self defaultView ].
GoogleChrome openWindowOn: defaultRoute
]
{ #category : #accessing }
BreaApp >> webHost [
^ host ifNil: [ host := Teapot allInstances detect: [ :each | each server isRunning ] ifNone: [ host := Teapot on. host server start ]]
]

View File

@ -1,31 +0,0 @@
Class {
#name : #BreaDataSource,
#superclass : #Object,
#instVars : [
'source',
'queries'
],
#category : #Brea
}
{ #category : #accessing }
BreaDataSource >> queries [
^ queries
]
{ #category : #accessing }
BreaDataSource >> queries: anObject [
queries := anObject
]
{ #category : #accessing }
BreaDataSource >> source [
^ source
]
{ #category : #accessing }
BreaDataSource >> source: aDictionary [
"Key, value pair in aDictionary contain a short name and a url pointing to a local or a remote
resource. If is local a FileLocator should be provided."
source := aDictionary
]

View File

@ -0,0 +1,78 @@
"
I model the file where contents (data and/or metadata) for the Brea CSM pages are stored.
"
Class {
#name : #BreaFile,
#superclass : #Object,
#instVars : [
'folder',
'name'
],
#category : #Brea
}
{ #category : #'instance creation' }
BreaFile class >> fromShortName: nameString andFolder: aFileLocation [
"I create a new BreaFile assigning priorities to the filename discovery according to
their extension currently present in a particular folder."
| extensions |
extensions := #('md' 'json' 'yaml').
extensions do: [ :ext | | markupFile filename |
filename := nameString, '.', ext.
markupFile := aFileLocation / filename.
markupFile exists ifTrue: [ ^ self new name: filename; folder: aFileLocation ].
].
^ nil.
]
{ #category : #accessing }
BreaFile >> contentString [
self name ifNil: [ ^ nil ].
(self name endsWith: '.md') ifTrue: [ ^ self contents contents ].
(self name endsWith: '.json') ifTrue: [ ^ self contents asString ].
]
{ #category : #accessing }
BreaFile >> contents [
| file |
self name ifNil: [ ^ nil ].
file := self folder / self name.
(self name endsWith: '.md') ifTrue: [ ^ Markdown fromFile: file ].
(self name endsWith: '.json') ifTrue: [ ^ NeoJSONObject fromString: file contents ]
]
{ #category : #accessing }
BreaFile >> file [
self folder ifNil: [ ^ self ].
self name ifNil: [ ^ self ].
^ self folder / self name.
]
{ #category : #accessing }
BreaFile >> folder [
^ folder
]
{ #category : #accessing }
BreaFile >> folder: anObject [
folder := anObject
]
{ #category : #accessing }
BreaFile >> metadata [
self name ifNil: [ ^ nil ].
(self name endsWith: '.md') ifTrue: [ ^ self contents metadata ].
(self name endsWith: '.json') ifTrue: [ ^ self contents asDictionary ].
]
{ #category : #accessing }
BreaFile >> name [
^ name
]
{ #category : #accessing }
BreaFile >> name: anObject [
name := anObject
]

View File

@ -1,489 +0,0 @@
"
I model a member of a Brea site, usually a human.
"
Class {
#name : #BreaMember,
#superclass : #Object,
#instVars : [
'givenName',
'familyName',
'picture',
'country',
'tags',
'email',
'password',
'webPresence',
'organizations'
],
#category : #Brea
}
{ #category : #converting }
BreaMember >> asStonModified [
"asSton is generated a core dumped now. This renaming is trying to solve that. Maybe
in the offical release it will be solved"
^ STON toStringPretty: self
]
{ #category : #accessing }
BreaMember >> country [
^ country
]
{ #category : #accessing }
BreaMember >> country: anObject [
country := anObject
]
{ #category : #public }
BreaMember >> countryTemplate [
^ '{{#country}}
<tr>
<td class="mdl-data-table__cell--non-numeric"><b>Country</b></td>
<td class="mdl-data-table__cell--non-numeric">{{.}}</td>
</tr>
{{/country}}' asMustacheTemplate value: self
]
{ #category : #helpers }
BreaMember >> createTestUser [
^ self class new
givenName: 'Test';
familyName: 'User';
country: 'Neverland';
memberOf: 'HackBo' withWebsite: 'http://hackbo.co/';
memberOf: 'mutabiT' withWebsite: 'http://mutabit.com/';
website: 'http://test.user';
twitter: '@offrayLC';
email: 'iam@test.user';
tags: 'just, a lot, of words, separated, by commas'.
]
{ #category : #accessing }
BreaMember >> email [
^ email
]
{ #category : #accessing }
BreaMember >> email: anEmailAddress [
email := (SHA1 new hashMessage: anEmailAddress) hex
]
{ #category : #accessing }
BreaMember >> facebook [
^ self webPresence facebook.
]
{ #category : #accessing }
BreaMember >> facebook: aProfileName [
aProfileName = ''
ifTrue: [ self webPresence facebook: nil ]
ifFalse: [ self webPresence facebook: aProfileName ]
]
{ #category : #public }
BreaMember >> facebookTemplate [
^ '{{#facebook}}
<tr>
<td class="mdl-data-table__cell--non-numeric">
<b>Facebook</b></td>
<td class="mdl-data-table__cell--non-numeric">
<a href="https://facebook.com/{{.}}">
{{.}}</a></td>
</tr>
{{/facebook}}' asMustacheTemplate value: self
]
{ #category : #accessing }
BreaMember >> familyName [
^ familyName
]
{ #category : #accessing }
BreaMember >> familyName: anObject [
familyName := anObject
]
{ #category : #helpers }
BreaMember >> fullName [
^ self givenName asLowercase, '-', self familyName asLowercase
]
{ #category : #accessing }
BreaMember >> getGenericProfilePicture [
"Other considered avatars where:
'https://upload.wikimedia.org/wikipedia/commons/1/1e/Default-avatar.jpg'"
self picture: 'https://www.jamf.com/jamf-nation/img/default-avatars/generic-user.png'.
^ picture
]
{ #category : #accessing }
BreaMember >> givenName [
^ givenName
]
{ #category : #accessing }
BreaMember >> givenName: anObject [
givenName := anObject
]
{ #category : #public }
BreaMember >> head [
^ '<head>', self headMeta, self headTitle, self headStyles,'</head>'
]
{ #category : #utility }
BreaMember >> headMeta [
^ '<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="A portfolio template that uses Material Design Lite.">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">'
]
{ #category : #utility }
BreaMember >> headStyles [
^ '
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.grey-pink.min.css" />
<link rel="stylesheet" href="http://mutabit.com/repos.fossil/gig/doc/tip/styles.css" />
<link rel="stylesheet" href="styles.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
'
]
{ #category : #utility }
BreaMember >> headTitle [
^ self headTitled: 'GIG: Network'
]
{ #category : #utility }
BreaMember >> headTitled: aString [
^ '<title>', aString ,'</title>'
]
{ #category : #public }
BreaMember >> html [
"I show the member profile as HTML"
^ self head, self htmlOutput
]
{ #category : #public }
BreaMember >> htmlInput [
"I capture data in a HTML Form and use it to create a new BreaMember"
^ '
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="A portfolio template that uses Material Design Lite.">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<title>Add Member | GIG Network</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.grey-pink.min.css" />
<link rel="stylesheet" href="styles.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
</head>
<body>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<div class="mdl-layout__drawer mdl-layout--small-screen-only">
<nav class="mdl-navigation mdl-typography--body-1-force-preferred-font">
<a class="mdl-navigation__link is-active" href="index.html">Portfolio</a>
<a class="mdl-navigation__link" href="blog.html">Blog</a>
<a class="mdl-navigation__link" href="about.html">About</a>
<a class="mdl-navigation__link" href="contact.html">Contact</a>
</nav>
</div>
<main class="mdl-layout__content">
<div class="mdl-grid portfolio-max-width portfolio-contact">
<div class="mdl-cell mdl-cell--12-col mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">Add new member</h2>
</div>
<div class="mdl-card__supporting-text">
<p>
Fill out the form.
The fields preceded by [*] are obligatory.
</p>
<form enctype="application/x-www-form-urlencoded" action="summit" method="POST" class="">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" pattern="[A-Z,a-z, ]*" type="text" name="givenName">
<label class="mdl-textfield__label" for="givenName">[*]Given Name...</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" pattern="[A-Z,a-z, ]*" type="text" name="familyName">
<label class="mdl-textfield__label" for="familyName">[*]Family Name...</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="email">
<label class="mdl-textfield__label" for="email">[*]Email...</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" pattern="[A-Z,a-z, ]*" type="text" name="country">
<label class="mdl-textfield__label" for="country">[*]Country...</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" pattern="[A-Z,a-z, ]*" type="text" name="organizations">
<label class="mdl-textfield__label" for="organizations">
[*]Organization(s) (separated with commas)</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="picture">
<label class="mdl-textfield__label" for="website">Profile picture url...</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="website">
<label class="mdl-textfield__label" for="website">Personal website...</label>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="twitter">
<label class="mdl-textfield__label" for="twitter">Twitter...</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="facebook">
<label class="mdl-textfield__label" for="facebook">Facebook...</label>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<textarea class="mdl-textfield__input" type="text" rows="5" name="tags"></textarea>
<label class="mdl-textfield__label" for="tags">Tags (separated with commas)...</label>
</div>
<p>
<button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect
mdl-button--accent" type="submit" value="Submit">
Submit
</button>
</p>
</form>
</div>
</div>
</div>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer__left-section">
<div class="mdl-logo">Simple portfolio website</div>
</div>
<div class="mdl-mini-footer__right-section">
<ul class="mdl-mini-footer__link-list">
<li><a href="#">Help</a></li>
<li><a href="#">Privacy & Terms</a></li>
</ul>
</div>
</footer>
</main>
</div>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
</body>
</html>
'
]
{ #category : #public }
BreaMember >> htmlOutput [
^ self htmlOutputTemplate asMustacheTemplate value: self
]
{ #category : #public }
BreaMember >> htmlOutputTemplate [
"I show the member profile as HTML"
^ '<div class="mdl-grid portfolio-max-width">
<div class="mdl-cell mdl-card mdl-shadow--4dp portfolio-card">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">{{givenName}} {{familyName}}</h2>
</div>
<div class="mdl-card__media">
<img class="article-image"
src="{{picture}}"
border="0" alt="">
</div>
<div class="mdl-card__supporting-text">
<table class="mdl-data-table mdl-js-data-table">
<tbody>
<tr>
<td class="mdl-data-table__cell--non-numeric"><b>Name</b></td>
<td class="mdl-data-table__cell--non-numeric">{{givenName}} {{familyName}}</td>
</tr>',
self countryTemplate,
self organizationsTemplate,
self websiteTemplate,
self twitterTemplate,
self facebookTemplate,
self tagsTemplate,
'
</tbody>
</table>
</div>
<div class="mdl-card__actions mdl-card--border">
<a class="mdl-button mdl-button--colored mdl-js-button
mdl-js-ripple-effect mdl-button--accent"
href="portfolio-example01.html">Read more</a>
</div>
</div>
</div>
'
]
{ #category : #accessing }
BreaMember >> instagram [
^ self webPresence instagram.
]
{ #category : #accessing }
BreaMember >> instagram: aProfileName [
self webPresence instagram: aProfileName
]
{ #category : #accessing }
BreaMember >> memberOf: anOrgName [
self organizations add:
(BreaOrganization new name: anOrgName)
]
{ #category : #accessing }
BreaMember >> memberOf: anOrgName withWebsite: aUrl [
self organizations add:
(BreaOrganization new
name: anOrgName;
website: aUrl)
]
{ #category : #accessing }
BreaMember >> organizations [
^ organizations ifNil: [ organizations := OrderedCollection new ]
]
{ #category : #accessing }
BreaMember >> organizations: anOrgListOrName [
anOrgListOrName splitOn: ',' do: [ :each | self memberOf: each ]
]
{ #category : #public }
BreaMember >> organizationsTemplate [
^ '
<tr>
<td class="mdl-data-table__cell--non-numeric"><b>Organization(s)</b></td>
<td class="mdl-data-table__cell--non-numeric">
{{#organizations}}
<a href="{{website}}">{{name}}</a>
{{/organizations}}
</td>
</tr>' asMustacheTemplate value: self
]
{ #category : #accessing }
BreaMember >> password [
^ password
]
{ #category : #accessing }
BreaMember >> password: anObject [
password := anObject
]
{ #category : #accessing }
BreaMember >> picture [
^ picture ifNil: [ ^ self getGenericProfilePicture ]
]
{ #category : #accessing }
BreaMember >> picture: anImageFilePath [
picture := anImageFilePath
]
{ #category : #helpers }
BreaMember >> renderTestUserAsHtml [
^ self class new createTestUser html
]
{ #category : #'server handling' }
BreaMember >> storeInto: aFileDirectory [
| folder file |
folder := (aFileDirectory asFileReference / self fullName) ensureCreateDirectory.
file := (folder / 'info.ston') ensureCreateFile.
file writeStreamDo: [:stream |
(STON writer on: stream)
newLine: String crlf;
prettyPrint: true;
nextPut: self]
]
{ #category : #accessing }
BreaMember >> tags [
^ tags
]
{ #category : #accessing }
BreaMember >> tags: anObject [
tags := anObject
]
{ #category : #public }
BreaMember >> tagsTemplate [
^ '{{#tags}}
<tr>
<td colspan="2"; style="text-align:left">
<b>Tags</b><br>
{{.}}
</td>
</tr>
{{/tags}}' asMustacheTemplate value: self
]
{ #category : #accessing }
BreaMember >> twitter [
^ self webPresence twitter.
]
{ #category : #accessing }
BreaMember >> twitter: aProfileName [
aProfileName = ''
ifTrue: [ self webPresence twitter: nil ]
ifFalse: [ self webPresence twitter: aProfileName ]
]
{ #category : #public }
BreaMember >> twitterTemplate [
^ '{{#twitter}}
<tr>
<td class="mdl-data-table__cell--non-numeric">
<b>Twitter</b></td>
<td class="mdl-data-table__cell--non-numeric">
<a href="https://twitter.com/{{.}}">
{{.}}</a></td>
</tr>
{{/twitter}}' asMustacheTemplate value: self
]
{ #category : #accessing }
BreaMember >> webPresence [
^ webPresence ifNil: [ webPresence := BreaWebPresence new ]
]
{ #category : #accessing }
BreaMember >> webPresence: anObject [
webPresence := anObject
]
{ #category : #accessing }
BreaMember >> website [
^ self webPresence website.
]
{ #category : #accessing }
BreaMember >> website: anUrl [
self webPresence website: anUrl
]
{ #category : #public }
BreaMember >> websiteTemplate [
^ '{{#website}}
<tr>
<td class="mdl-data-table__cell--non-numeric"><b>Website</b></td>
<td class="mdl-data-table__cell--non-numeric">
<a href="{{.}}">{{.}}</a>
</td>
{{/website}}' asMustacheTemplate value: self
]

View File

@ -1,8 +0,0 @@
"
A BreaMemberTest is a test class for testing the behavior of BreaMember
"
Class {
#name : #BreaMemberTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}

View File

@ -0,0 +1,95 @@
"
I represent a operation that can be done on data inputs to produce and output by executing
a code block.
I can be used by BreaThemes to produce outpus reflected in a particular set of theme pages.
- (for bonus points) how to create instances.
One simple example is simply gorgeous.
Internal Representation and Key Implementation Points.
Instance Variables
codeBlock: <Object>
inputs: <Object>
name: <Object>
Implementation Points
"
Class {
#name : #BreaOperator,
#superclass : #Object,
#instVars : [
'name',
'inputs',
'codeBlock',
'cleanedInputs'
],
#category : #Brea
}
{ #category : #converting }
BreaOperator >> asSton [
^ STON toStringPretty: self
]
{ #category : #converting }
BreaOperator >> cleanInputs [
self cleanedInputs ifNil: [ ^ self ].
self cleanedInputs ifTrue: [
self inputs keysAndValuesDo: [ :k :v | | currentValue |
currentValue := self inputs at: k.
self inputs at: k put: currentValue class new
]
].
]
{ #category : #accessing }
BreaOperator >> cleanedInputs [
^ cleanedInputs
]
{ #category : #accessing }
BreaOperator >> cleanedInputs: aBoolean [
"I tell if the inputs should be cleaned when the query is serialized as STON, for
example when they contain sensible information, like API keys or passwords"
cleanedInputs := aBoolean
]
{ #category : #accessing }
BreaOperator >> codeBlock [
^ codeBlock
]
{ #category : #accessing }
BreaOperator >> codeBlock: anObject [
codeBlock := anObject
]
{ #category : #execution }
BreaOperator >> execute [
^ self codeBlock valueWithArguments: self inputs values.
]
{ #category : #accessing }
BreaOperator >> inputs [
^ inputs
]
{ #category : #accessing }
BreaOperator >> inputs: anOrderedDictionary [
inputs := anOrderedDictionary
]
{ #category : #accessing }
BreaOperator >> name [
^ name
]
{ #category : #accessing }
BreaOperator >> name: anObject [
name := anObject
]

View File

@ -1,32 +0,0 @@
"
I store the places a BreaMember is affiliated to.
"
Class {
#name : #BreaOrganization,
#superclass : #Object,
#instVars : [
'name',
'website'
],
#category : #Brea
}
{ #category : #accessing }
BreaOrganization >> name [
^ name
]
{ #category : #accessing }
BreaOrganization >> name: anObject [
name := anObject
]
{ #category : #accessing }
BreaOrganization >> website [
^ website
]
{ #category : #accessing }
BreaOrganization >> website: anObject [
website := anObject
]

View File

@ -0,0 +1,255 @@
"
I model a wiki page of a Brea site.
I am modelled after common wiki pages, where a document in a light markup laguage
is converted in HTML and is expected to access document history (I am helped by
FossilRepo for that).
I can be used for other types of publications, like blog post though.
"
Class {
#name : #BreaPage,
#superclass : #Object,
#instVars : [
'shortName',
'template',
'templateData',
'bodyTag',
'splitters',
'subpages',
'metadata',
'folder',
'file'
],
#category : #Brea
}
{ #category : #operation }
BreaPage >> bodyContentsAsHTML [
| sourcePage commandParameters |
self contentsFile ifNil: [ ^ self ].
sourcePage := self file file.
Smalltalk os isWindows ifTrue: [
^ Pandoc markdownToHtml: sourcePage
].
commandParameters := ' -f markdown+startnum+task_lists -t html '.
^ GtSubprocessWithInMemoryOutput new
shellCommand: 'pandoc', commandParameters, sourcePage fullName;
runAndWait;
stdout.
]
{ #category : #accessing }
BreaPage >> bodyTag [
^ bodyTag
]
{ #category : #accessing }
BreaPage >> bodyTag: aString [
"I represent the Mustache Template tag used to denote the body part of a page.
While the metadata is self describing via YAML metadata blocks in Markddown, so
they map where ever they are needed in a template, the Markdown file that will be converted
in HTML via a template doesn't know which part should occupy once the conversion is done.
I provide such knowledge. So if a page template puts the body content under the mustache tag
{{content}}, I should use bodyTag: 'content'.
bodyTag: is template dependant."
bodyTag := aString
]
{ #category : #accessing }
BreaPage >> contents [
| result |
self contentsFile ifNil: [ ^ nil ].
result := '' writeStream.
result nextPutAll: self contentsFile contentString.
self subpages ifNotNil: [
self subpages do: [ :sp | | markdownTempFile |
markdownTempFile := self folder / (sp, '.md').
result nextPutAll: (Markdown fromFile: markdownTempFile) contents.
]
].
^ result contents withInternetLineEndings.
]
{ #category : #operation }
BreaPage >> contentsFile [
self folder ifNil: [ ^ self ].
self shortName ifNil: [ ^ self ].
^ BreaFile fromShortName: self shortName andFolder: self folder.
]
{ #category : #'as yet unclassified' }
BreaPage >> exportAsHTML [
| htmlContents allActions actionsArray semaphore result |
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
actionsArray := { [ self populateMetadata ] future. }.
self splitters ifNotEmpty: [ actionsArray := actionsArray copyWith: [ self split ] future ].
self bodyTag ifNotNil: [
actionsArray := actionsArray copyWith: [ self populateBodyAs: self bodyTag ] future ].
allActions := TKTFuture fromCollectionOfFutures: actionsArray.
semaphore := Semaphore new.
allActions onSuccessDo: [ :values |
result := values last.
semaphore signal.
].
semaphore wait.
htmlContents := (MustacheTemplate on: result templateFile contents) value: result templateData.
^ MarkupFile exportAsFileOn: self folder / (self shortName, '.html' ) containing: htmlContents
]
{ #category : #accessing }
BreaPage >> file [
(self shortName isNil or: [ self folder isNil ]) ifTrue: [ ^ nil ].
^ file ifNil: [ ^ BreaFile fromShortName: self shortName andFolder: self folder ]
]
{ #category : #accessing }
BreaPage >> file: anObject [
file := anObject
]
{ #category : #accessing }
BreaPage >> folder [
^ folder
]
{ #category : #accessing }
BreaPage >> folder: folderFileReference [
folder := folderFileReference
]
{ #category : #'as yet unclassified' }
BreaPage >> htmlContents [
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ (MustacheTemplate on: self templateFile contents) value: self templateData.
]
{ #category : #accessing }
BreaPage >> metadata [
^ metadata ifNil: [ self contentsFile metadata ]
]
{ #category : #accessing }
BreaPage >> metadata: aDictionary [
"External place where page metadata is located (on Internet or the local file system) in JSON format.
If nil, is suposed that is placed in the Markdown file with the page contents."
metadata := aDictionary
]
{ #category : #'as yet unclassified' }
BreaPage >> populateBodyAs: key [
self templateData at: key put: self bodyContentsAsHTML.
^ self.
]
{ #category : #'as yet unclassified' }
BreaPage >> populateExternalMetadata [
self metadata ifNil: [ ^ self ].
self
]
{ #category : #operation }
BreaPage >> populateMetadata [
| metadataTemp |
self metadata
ifNotNil: [ metadataTemp := self metadata ]
ifNil: [ metadataTemp := self contentsFile metadata].
metadataTemp keysAndValuesDo: [ :key :value |
self templateData at: key put: value ].
^ self templateData
]
{ #category : #operation }
BreaPage >> populateTaggedBody [
self bodyTag ifNil: [ ^ self ].
^ self populateBodyAs: self bodyTag.
]
{ #category : #accessing }
BreaPage >> shortName [
^ shortName
]
{ #category : #accessing }
BreaPage >> shortName: aString [
"The name of the file tha contains the light markup to produce the web page, without file extension.
By default I work with Markdown files."
shortName := aString
]
{ #category : #'as yet unclassified' }
BreaPage >> split [
self splitters ifEmpty: [ ^ self ].
self splitters keysAndValuesDo: [ :key :value | self split: key with: value ].
]
{ #category : #'as yet unclassified' }
BreaPage >> split: key with: subkey [
"I split a comma separated collection of subkeys stored in the 'key' field and name each one as 'subkey'
to put it indiviudally in a Mustache template."
| allSubkeys cleaned data |
allSubkeys := (self populateMetadata at: key) splitOn: ','.
cleaned := allSubkeys collect: [ :item | item withBlanksCondensed ].
data := OrderedCollection new.
cleaned do: [ :item |
data add: { subkey -> item } asDictionary ].
self populateMetadata at: key put: data; yourself.
]
{ #category : #'as yet unclassified' }
BreaPage >> splitterAt: key with: subkey [
self splitters at: key put: subkey
]
{ #category : #accessing }
BreaPage >> splitters [
^ splitters ifNil: [ splitters := Dictionary new ]
]
{ #category : #accessing }
BreaPage >> splitters: aDictionary [
"I model the pattern where a Mustache template contains something like
{{# key}} {{value}} {{/ key}} and has data that needs to be split before injecting it in the template."
splitters := aDictionary
]
{ #category : #accessing }
BreaPage >> subpages [
^ subpages
]
{ #category : #accessing }
BreaPage >> subpages: shortNamesList [
"I am used when a page is composed of other subpages (for example with link aliases) that are shared
accross several pages."
subpages := shortNamesList
]
{ #category : #accessing }
BreaPage >> template [
^ template
]
{ #category : #accessing }
BreaPage >> template: mustacheFileName [
"Usually templates and their pages are located in the same folder."
template := mustacheFileName
]
{ #category : #accessing }
BreaPage >> templateData [
^ templateData ifNil: [ templateData := Dictionary new ]
]
{ #category : #accessing }
BreaPage >> templateData: aDictionary [
templateData := aDictionary
]
{ #category : #'as yet unclassified' }
BreaPage >> templateFile [
self folder ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ self folder / self template
]

View File

@ -1,89 +0,0 @@
"
I define a [Mustache][1] template and how it is used to create
derivate output files combining it with particular data sources.
[1]: https://mustache.github.io/
"
Class {
#name : #BreaTemplate,
#superclass : #Object,
#instVars : [
'template',
'data',
'location',
'queries',
'outputs'
],
#category : #Brea
}
{ #category : #adding }
BreaTemplate >> addDataSourceNamed: name with: source [
self
data at: name put: source.
self data.
]
{ #category : #accessing }
BreaTemplate >> data [
^ data ifNil: [ data := Dictionary new ]
]
{ #category : #accessing }
BreaTemplate >> data: aDictionary [
"Each item in the dictionary is a unique alias (as key) and a data location (as value),
usually on the web.
Alias and locations are used later to define data queries to feed into templates."
data := aDictionary
]
{ #category : #accessing }
BreaTemplate >> location [
^ location
]
{ #category : #accessing }
BreaTemplate >> location: aFolderPath [
"This is the place where a template and its derivate files are located.
A shared location is an easy approach to start with and creates more explicit
relation between derived files and templates.
Eventually some re-mapping or re-routing could be used so templates and their outputs
could be further apart."
location := aFolderPath
]
{ #category : #accessing }
BreaTemplate >> outputs [
^ outputs
]
{ #category : #accessing }
BreaTemplate >> outputs: fileNamesList [
"fileNamesList contain the files which are derived from the template."
outputs := fileNamesList
]
{ #category : #accessing }
BreaTemplate >> queries [
^ queries ifNil: [ queries := Dictionary new ]
]
{ #category : #accessing }
BreaTemplate >> queries: aDictionary [
"aDictionary contains the alias for the query as key and a block that will be executed
on a particular data source, as value."
queries := aDictionary
]
{ #category : #accessing }
BreaTemplate >> template [
^ template
]
{ #category : #accessing }
BreaTemplate >> template: aFileName [
"I provide the name of the mustache base template.
The file can have any name, but by convention they end in '.mus.html' 'mus.md' and
so on."
template := aFileName
]

View File

@ -0,0 +1,229 @@
"
I model a web theme.
For the Collaborators Part: State my main collaborators and one line about how I interact with them.
Public API and Key Messages
- message one
- message two
- (for bonus points) how to create instances.
One simple example is simply gorgeous.
Internal Representation and Key Implementation Points.
Instance Variables
name: <Object>
preview: <Object>
provider: <Object>
url: <Object>
Implementation Points
"
Class {
#name : #BreaTheme,
#superclass : #Object,
#instVars : [
'name',
'folder',
'provider',
'url',
'preview',
'license',
'operators'
],
#category : #Brea
}
{ #category : #accessing }
BreaTheme class >> availablePacks [
^ self downloadLinks keys
]
{ #category : #utilities }
BreaTheme class >> downloadLinks [
"Keys are the theme names and values are the url where it can be downloaded
as a zip file.
For the moment we work only with HTML5Up themes, but more could be added
and the code should be refactored accordingly."
| result providerUrl |
result := Dictionary new.
providerUrl := 'https://html5up.net'.
result
at: 'Paradigm Shift' put: providerUrl, '/paradigm-shift/download';
at: 'Massively' put: providerUrl, '/massively/download';
at: 'Ethereal' put: providerUrl, '/ethereal/download';
at: 'Story' put: providerUrl, '/story/download';
at: 'Dimension' put: providerUrl, '/dimension/download';
at: 'Editorial' put: providerUrl, '/editorial/download';
at: 'Forty' put: providerUrl, '/forty/download';
at: 'Stellar' put: providerUrl, '/stellar/download';
at: 'Multiverse' put: providerUrl, '/multiverse/download';
at: 'Phantom' put: providerUrl, '/phantom/download';
at: 'Hyperspace' put: providerUrl, '/hyperspace/download';
at: 'Future Imperfect' put: providerUrl, '/future-imperfect/download';
at: 'Solid State' put: providerUrl, '/solid-state/download';
at: 'Identity' put: providerUrl, '/identity/download';
at: 'Lens' put: providerUrl, '/lens/download';
at: 'Fractal' put: providerUrl, '/fractal/download';
at: 'Eventually' put: providerUrl, '/eventually/download';
at: 'Spectral' put: providerUrl, '/spectral/download';
at: 'Phonon' put: providerUrl, '/photon/download';
at: 'Highlights' put: providerUrl, '/highlights/download';
at: 'Landed' put: providerUrl, '/landed/download';
at: 'Strata' put: providerUrl, '/strata/download';
at: 'Read Only' put: providerUrl, '/read-only/download';
at: 'Alpha' put: providerUrl, '/alpha/download';
at: 'Directive' put: providerUrl, '/directive/download';
at: 'Aerial' put: providerUrl, '/aerial/download';
at: 'Twenty' put: providerUrl, '/twenty/download';
at: 'Big Picture' put: providerUrl, '/big-picture/download';
at: 'Tessellate' put: providerUrl, '/tessellate/download';
at: 'Overflow' put: providerUrl, 'overflow/download';
at: 'Prologue' put: providerUrl, '/prologue/download';
at: 'Helios' put: providerUrl, '/helios/download';
at: 'Telephasic' put: providerUrl, '/telephasic/download';
at: 'Strongly Typed' put: providerUrl, '/strongly-typed/download';
at: 'Parallelism' put: providerUrl, '/parallelism/download';
at: 'Escape Velocity' put: providerUrl, '/escape-velocity/download';
at: 'Astral' put: providerUrl, '/astral/download';
at: 'Striped' put: providerUrl, '/striped/download';
at: 'Dopetrope' put: providerUrl, '/dopetrope/download';
at: 'Miniport' put: providerUrl, '/miniport/download';
at: 'TXT' put: providerUrl, '/txt/download';
at: 'Verti' put: providerUrl, '/verti/download';
at: 'Zerofour' put: providerUrl, '/zerofour/download';
at: 'Arcana' put: providerUrl, '/arcana/download';
at: 'Halcyonic' put: providerUrl, '/halcyonic/download';
at: 'Minimaxing' put: providerUrl, '/minimaxing/download'.
^ result
]
{ #category : #operation }
BreaTheme >> addOperator: aBreaQuery [
self operators add: aBreaQuery cleanInputs
]
{ #category : #operation }
BreaTheme >> asSton [
^ STON toStringPretty: self
]
{ #category : #utilities }
BreaTheme >> dashedName [
^ self name asDashedLowercase
]
{ #category : #operation }
BreaTheme >> downloadInto: aFolder [
| tempName zippedFile |
self url ifNil: [ ^ self ].
tempName := self name.
zippedFile := aFolder / self dashedName , 'zip'.
aFolder ensureCreateDirectory.
GrafoscopioUtils
downloadingFrom: self url withMessage: 'Downloading ', tempName, '...' into: zippedFile.
self folder: aFolder.
^ zippedFile
]
{ #category : #accessing }
BreaTheme >> folder [
^ folder
]
{ #category : #accessing }
BreaTheme >> folder: anObject [
folder := anObject
]
{ #category : #installation }
BreaTheme >> installInto: aFolder [
| zippedFile |
self url ifNil: [ ^ self ].
zippedFile := FileLocator temp / 'download'.
zippedFile ensureDelete.
ZnClient new
url: self url;
downloadTo: FileLocator temp.
(ZipArchive new readFrom: zippedFile) extractAllTo: aFolder.
self folder: aFolder.
^ aFolder
]
{ #category : #accessing }
BreaTheme >> license [
^ license
]
{ #category : #accessing }
BreaTheme >> license: anObject [
license := anObject
]
{ #category : #operation }
BreaTheme >> loadConfiguration [
| config |
config := self folder / 'brea.yaml'.
config exists
ifTrue: [ ^ PPYAMLGrammar new parse: config contents ]
ifFalse: [ self inform:
'No configuration file found. A "brea.yaml" file should be located in the theme root folder.
please run "#updateCustomizations" after defining a theme name from the
"BreaTheme availablePacks".
If no configuration is defined for such theme name you can create and empty configuration
file by running "#createBaseConfiguration" and filing out the "brea.yaml" fields.
For more information or help ask at https://t.me/grafoscopio .' ]
]
{ #category : #accessing }
BreaTheme >> name [
^ name ifNil: [ name = 'unamed' ]
]
{ #category : #accessing }
BreaTheme >> name: anObject [
name := anObject
]
{ #category : #accessing }
BreaTheme >> operators [
^ operators ifNil: [ operators := OrderedCollection new ]
]
{ #category : #accessing }
BreaTheme >> operators: cleanedBreaQueriesCollection [
operators := cleanedBreaQueriesCollection
]
{ #category : #accessing }
BreaTheme >> preview [
^ preview
]
{ #category : #accessing }
BreaTheme >> preview: anObject [
preview := anObject
]
{ #category : #accessing }
BreaTheme >> provider [
^ provider
]
{ #category : #accessing }
BreaTheme >> provider: anObject [
provider := anObject
]
{ #category : #accessing }
BreaTheme >> url [
^ url ifNil: [ url := self class downloadLinks at: self name. ]
]
{ #category : #accessing }
BreaTheme >> url: anObject [
url := anObject
]

View File

@ -0,0 +1,22 @@
"
I provide common utilities for the use with the Brea CMS.
"
Class {
#name : #BreaUtils,
#superclass : #Object,
#category : #Brea
}
{ #category : #'as yet unclassified' }
BreaUtils class >> installSkeleton [
"I populate the folder and files structures for Brea documentation and customizations."
| skeleton destination |
GrafoscopioUtils
downloadingFrom: 'https://mutabit.com/repos.fossil/brea/zip'
withMessage: 'Dowloading files skeleton'
into: FileLocator temp.
skeleton := ZipArchive new readFrom: FileLocator temp / 'zip'.
destination := FileLocator home / '.local/share/Brea'.
destination ensureCreateDirectory.
skeleton extractAllTo: destination.
]

View File

@ -1,54 +0,0 @@
"
I store the common forms of web presence a BreaMember can have online.
"
Class {
#name : #BreaWebPresence,
#superclass : #Object,
#instVars : [
'website',
'twitter',
'facebook',
'instagram'
],
#category : #Brea
}
{ #category : #accessing }
BreaWebPresence >> facebook [
^ facebook
]
{ #category : #accessing }
BreaWebPresence >> facebook: anObject [
facebook := anObject
]
{ #category : #accessing }
BreaWebPresence >> instagram [
^ instagram
]
{ #category : #accessing }
BreaWebPresence >> instagram: anObject [
instagram := anObject
]
{ #category : #accessing }
BreaWebPresence >> twitter [
^ twitter
]
{ #category : #accessing }
BreaWebPresence >> twitter: anObject [
twitter := anObject
]
{ #category : #accessing }
BreaWebPresence >> website [
^ website
]
{ #category : #accessing }
BreaWebPresence >> website: anObject [
website := anObject
]

View File

@ -1,292 +0,0 @@
"
I model the fossil repository where public data is stored for the
building of this web site.
"
Class {
#name : #BreaWebsite,
#superclass : #Object,
#instVars : [
'fossilRepo',
'server',
'template',
'title'
],
#category : #Brea
}
{ #category : #utility }
BreaWebsite class >> availableTemplates [
self templates keys.
]
{ #category : #utility }
BreaWebsite class >> demoFolder [
^ FileLocator temp asFileReference / 'BreaDemo'.
]
{ #category : #example }
BreaWebsite class >> example [
"I run an example mockup of a website using Brea.
After runing me, go to:
- http://localhost:8080/demo
- http://localhost:8080/members/test
- http://localhost:8080/members/add "
self new
local: FileLocator temp asFileReference / 'BreaDemo';
template: 'portafolio';
downloadTemplate;
modifyTemplate;
start
]
{ #category : #example }
BreaWebsite class >> exampleDashboard [
"I run an example mockup of a website using Brea.
After runing me, go to: http://localhost:8080/demo "
self new
local: FileLocator temp asFileReference / 'BreaDemo';
template: 'dashboard';
downloadTemplate;
modifyTemplate;
start
]
{ #category : #'server handling' }
BreaWebsite class >> stopAll [
"I stop the server"
Teapot stopAll
]
{ #category : #utility }
BreaWebsite class >> templates [
"I provide the supported MDL templates taken from: https://getmdl.io/templates/"
^ Dictionary new
at: 'portafolio' put: 'https://code.getmdl.io/1.3.0/mdl-template-portfolio.zip';
at: 'dashboard' put: 'https://code.getmdl.io/1.3.0/mdl-template-dashboard.zip';
yourself.
]
{ #category : #utility }
BreaWebsite >> defaultTemplate [
self template
ifNil: [
self template: 'portafolio' ].
^ self template.
]
{ #category : #utility }
BreaWebsite >> downloadDefaultTemplate [
self downloadTemplateNamed: self defaultTemplate Into: self local.
]
{ #category : #utility }
BreaWebsite >> downloadDefaultTemplateInto: aDirectory [
| remoteUrl templatesFile |
aDirectory ensureDeleteAll.
aDirectory ensureCreateDirectory.
remoteUrl := self class templates at: self template.
GrafoscopioUtils
downloadingFrom: remoteUrl
withMessage: 'Downloading templates'
into: FileLocator temp asFileReference.
templatesFile := FileLocator temp asFileReference / (remoteUrl splitOn: '/') last.
ZipArchive new
readFrom: templatesFile;
extractAllTo: aDirectory
]
{ #category : #utility }
BreaWebsite >> downloadTemplate [
self downloadTemplateNamed: self template Into: self local.
]
{ #category : #utility }
BreaWebsite >> downloadTemplateNamed: aName Into: aDirectory [
"aName: String aDirectory: aFileLocation"
| remoteUrl templatesFile localDirectory |
localDirectory := aDirectory asFileReference.
localDirectory ensureDeleteAll.
localDirectory ensureCreateDirectory.
remoteUrl := self class templates at: aName.
GrafoscopioUtils
downloadingFrom: remoteUrl
withMessage: 'Downloading templates'
into: FileLocator temp asFileReference.
templatesFile := FileLocator temp asFileReference / (remoteUrl splitOn: '/') last.
ZipArchive new
readFrom: templatesFile;
extractAllTo: localDirectory
]
{ #category : #accessing }
BreaWebsite >> fossilRepo [
^ fossilRepo ifNil: [ fossilRepo := FossilRepo new ]
]
{ #category : #accessing }
BreaWebsite >> fossilRepo: aFossilRepo [
fossilRepo := aFossilRepo
]
{ #category : #utility }
BreaWebsite >> local [
^ self fossilRepo local
]
{ #category : #'server handling' }
BreaWebsite >> local: aFilePath [
"I define the local storage of the Fossil repository.
For the moment aFilePath must be an absolute "
| localSite |
aFilePath asFileReference exists
ifFalse: [
localSite := (FileLocator temp / 'breaSite') ensureCreateDirectory.
self fossilRepo local: localSite fullName ]
ifTrue: [ self fossilRepo local: aFilePath ].
]
{ #category : #'server handling' }
BreaWebsite >> local: aFilePath remote: anUrl [
"I define the local and remote storages of the Fossil repository"
self remote: anUrl.
self local: aFilePath
]
{ #category : #utility }
BreaWebsite >> modifyDashboardTemplate [
"I replace default templates with versioned files, that contains Mustache tags used
for examples."
"This part should be factorized and integrated into a single method tha modifies any
template, instead of repeated the code of modifyPortafolioTemplate."
| remoteRepoUrl files |
remoteRepoUrl := 'http://mutabit.com/repos.fossil/brea/templates/portaforlio'.
files := #('index.html' 'styles.css').
"files do: [ :file |
GrafoscopioUtils
downloadingFrom: remoteRepoUrl, 'doc/tip/', file
withMessage: 'Replacing ', file
into: self local ]"
]
{ #category : #utility }
BreaWebsite >> modifyPortafolioTemplate [
"I replace default templates with versioned files, that contains Mustache tags used
for examples."
| remoteRepoUrl files |
remoteRepoUrl := 'http://mutabit.com/repos.fossil/gig/'.
files := #('index.html' 'styles.css').
files do: [ :file |
GrafoscopioUtils
downloadingFrom: remoteRepoUrl, 'doc/tip/', file
withMessage: 'Replacing ', file
into: self local ]
]
{ #category : #utility }
BreaWebsite >> modifyTemplate [
"I replace default templates with versioned files, that contains Mustache tags used
for examples."
self template = 'portafolio' ifTrue: [ self modifyPortafolioTemplate ].
self template = 'dashboard' ifTrue: [ self modifyDashboardTemplate ]
]
{ #category : #'input processing' }
BreaWebsite >> processNewMember: request [
| member badRequest |
badRequest := [ ^ ZnResponse badRequest: request ].
(request hasEntity
and: [ request contentType matches: ZnMimeType applicationFormUrlEncoded ])
ifFalse: [ badRequest ].
member := BreaMember new
givenName: (request at: #givenName);
familyName: (request at: #familyName);
email: (request at: #email);
country: (request at: #country);
organizations: (request at: #organizations);
picture: (request at: #picture);
website: (request at: #website);
twitter: (request at: #twitter);
facebook: (request at: #facebook);
tags: (request at: #tags).
self store: member.
^ 'New member stored!'
]
{ #category : #'server handling' }
BreaWebsite >> remote: anUrl [
"I define the remote storage of the Fossil repository"
self remote: anUrl.
]
{ #category : #'server handling' }
BreaWebsite >> routes [
"I define how the website behaves accordingly to particular routes."
self server
serveStatic: 'demo' from: (self local);
GET: 'members/test' -> [ :req | BreaMember new renderTestUserAsHtml ];
GET: 'members/add' -> [ :req | BreaMember new htmlInput ];
POST: 'members/summit' -> [ :req | self processNewMember: req ]
]
{ #category : #accessing }
BreaWebsite >> server [
^ server ifNil: [ self setup ]
]
{ #category : #accessing }
BreaWebsite >> server: anObject [
server := anObject
]
{ #category : #accessing }
BreaWebsite >> setup [
^ server := Teapot
configure:
{(#port -> 8080).
(#debugMode -> true)}
]
{ #category : #'server handling' }
BreaWebsite >> start [
"I define the config and start the server"
self routes.
self server start
]
{ #category : #'server handling' }
BreaWebsite >> storageFor: anObject [
"I define the places where local storage is done for several types of objects"
anObject class = BreaMember
ifTrue: [ ^ self local asFileReference / 'members' ].
^ self
]
{ #category : #'server handling' }
BreaWebsite >> store: anObject [
"I store different kind of objects in the website repository.
For the moment I will only store BreaMembers, but as long as new
objects will emerge, I will specialize other ways of storage."
anObject storeInto: (self storageFor: anObject)
]
{ #category : #accessing }
BreaWebsite >> template [
^ template
]
{ #category : #accessing }
BreaWebsite >> template: aTemplateName [
"I define the default template to be used for the Brea website.
Available options are at self class templates."
template := aTemplateName
]
{ #category : #accessing }
BreaWebsite >> title [
^ title
]
{ #category : #accessing }
BreaWebsite >> title: anObject [
title := anObject
]

View File

@ -1,149 +0,0 @@
"
I model a wiki page of a Brea site.
"
Class {
#name : #BreaWikiPage,
#superclass : #Object,
#instVars : [
'shortName',
'template',
'templateData',
'namespace',
'bodyTag'
],
#category : #Brea
}
{ #category : #operation }
BreaWikiPage >> bodyContentsAsHTML [
| sourcePage |
self markdownFile ifNil: [ ^ self ].
sourcePage := FileLocator temp / 'wikiPage.md'.
MarkupFile exportAsFileOn: sourcePage containing: self markdownFile contents.
^ Pandoc markdownToHtml: sourcePage
]
{ #category : #accessing }
BreaWikiPage >> bodyTag [
^ bodyTag
]
{ #category : #accessing }
BreaWikiPage >> bodyTag: aString [
"I represent the Mustache Template tag used to denote the body part of a page.
While the metadata is self describing via YAML metadata blocks in Markddown, so
they map where ever they are needed in a template, the Markdown file that will be converted
in HTML via a template doesn't know which part should occupy once the conversion is done.
I provide such knowledge. So if a page template puts the body content under the mustache tag
{{content}}, I should use bodyTag: 'content'.
bodyTag: is template dependant."
bodyTag := aString
]
{ #category : #'as yet unclassified' }
BreaWikiPage >> exportAsHTML [
| htmlContents allActions semaphore result |
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
self bodyTag ifNil: [ ^ self ].
allActions := TKTFuture all: {
[ self populateMetadata ] future.
[ self populateBodyAs: self bodyTag ] future.
}.
semaphore := Semaphore new.
allActions onSuccessDo: [ :values |
result := values last.
semaphore signal.
].
semaphore wait.
htmlContents := (MustacheTemplate on: result templateFile contents) value: result templateData.
^ MarkupFile exportAsFileOn: self namespace / (self shortName, '.html' ) containing: htmlContents
]
{ #category : #'as yet unclassified' }
BreaWikiPage >> htmlContents [
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ (MustacheTemplate on: self templateFile contents) value: self templateData.
]
{ #category : #operation }
BreaWikiPage >> markdownFile [
| localFile |
self namespace ifNil: [ ^ self ].
self shortName ifNil: [ ^ self ].
localFile := self namespace / (self shortName, '.md').
localFile exists ifFalse: [ ^ self ].
^ Markdown fromFile: localFile
]
{ #category : #accessing }
BreaWikiPage >> namespace [
^ namespace
]
{ #category : #accessing }
BreaWikiPage >> namespace: folderFileReference [
namespace := folderFileReference
]
{ #category : #'as yet unclassified' }
BreaWikiPage >> populateBodyAs: key [
| allActions result semaphore |
allActions := TKTFuture all: {
[ self bodyContentsAsHTML ] future.
}.
semaphore := Semaphore new.
allActions onSuccessDo: [ :values |
result := values last.
semaphore signal ].
semaphore wait.
self templateData at: key put: result contents.
^ self.
]
{ #category : #operation }
BreaWikiPage >> populateMetadata [
self markdownFile metadata keysAndValuesDo: [ :key :value |
self templateData at: key put: value
].
^ templateData
]
{ #category : #accessing }
BreaWikiPage >> shortName [
^ shortName
]
{ #category : #accessing }
BreaWikiPage >> shortName: aString [
shortName := aString
]
{ #category : #accessing }
BreaWikiPage >> template [
^ template
]
{ #category : #accessing }
BreaWikiPage >> template: mustacheFileName [
"Usually templates and their pages are located in the same folder."
template := mustacheFileName
]
{ #category : #accessing }
BreaWikiPage >> templateData [
^ templateData ifNil: [ templateData := Dictionary new ]
]
{ #category : #accessing }
BreaWikiPage >> templateData: aDictionary [
templateData := aDictionary
]
{ #category : #'as yet unclassified' }
BreaWikiPage >> templateFile [
self namespace ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ self namespace / self template
]

View File

@ -0,0 +1,13 @@
"
I store metadata for this package. These meta data are used by other tools such as the SmalllintManifestChecker and the critics Browser
"
Class {
#name : #ManifestBrea,
#superclass : #PackageManifest,
#category : #'Brea-Manifest'
}
{ #category : #'code-critics' }
ManifestBrea class >> ruleRBStringConcatenationRuleV1FalsePositive [
^ #(#(#(#RGMethodDefinition #(#BreaPage #contents #false)) #'2020-08-28T20:08:20.291489-05:00') #(#(#RGMethodDefinition #(#BreaFile #fromShortName:andFolder: #false)) #'2020-11-06T20:59:12.94748-05:00') #(#(#RGMethodDefinition #(#'BreaFile class' #fromShortName:andFolder: #true)) #'2020-11-06T21:02:25.564981-05:00') )
]

View File

@ -0,0 +1,6 @@
Extension { #name : #String }
{ #category : #'*Brea' }
String >> webView [
^ (Pandoc htmlStringToMarkdown: self) accentedCharactersCorrection
]

View File

@ -0,0 +1,6 @@
Extension { #name : #Teapot }
{ #category : #'*Brea' }
Teapot >> dynamicRoutes [
^ dynamicRouter routes
]