Skip to content

Commit f159492

Browse files
committed
First commit.
0 parents  commit f159492

15 files changed

+442
-0
lines changed

.gitignore

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
nerc
2+
test/*.css
3+
test/*.json
4+
test/*.htm
5+
test/*.html
6+
test/*/*.css
7+
test/*/*.json
8+
test/*/*.htm
9+
test/*/*.html
10+
test/*/*/*.css
11+
test/*/*/*.json
12+
test/*/*/*.htm
13+
test/*/*/*.html

README.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# NERC
2+
3+
Web anti-framework in Nim.
4+
5+
6+
7+
## Rationale:
8+
9+
Too many web frameworks are written in slow, heavy, bloated interpreted languages, so this is an *anti*-framework written in a fast, lightweight, and *nim*ble compiled language.
10+
11+
12+
13+
## License:
14+
15+
This code is dedicated to the public domain, but is also made available under the terms of the 0-clause BSD license, as some jurisdictions do not recognize the public domain.
16+
17+
18+
19+
The terms of the 0-clause BSD license are thus:
20+
```
21+
22+
Copyright (C) 2025 Christopher DeBoy <chrisxdeboy@gmail.com>
23+
24+
25+
26+
Permission to use, copy, modify, and/or distribute this software for
27+
any purpose with or without fee is hereby granted.
28+
29+
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
30+
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
31+
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
32+
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
33+
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
34+
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
35+
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

config.nims

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

nerc.nimble

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Package
2+
3+
version = "0.0.1"
4+
author = "8bitprodigy"
5+
description = "A simple web anti-framework written in Nim."
6+
license = "0BSD"
7+
srcDir = "src"
8+
bin = @["nerc"]
9+
10+
11+
# Dependencies
12+
13+
requires "nim >= 2.2.2"
14+
requires "markdown"

src/nerc.nim

+200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import
2+
json,
3+
macros,
4+
markdown,
5+
os,
6+
strutils,
7+
terminal
8+
9+
10+
type
11+
ItemKind = enum
12+
itemFile, itemDir
13+
14+
FileKind = enum
15+
fileMarkdown,
16+
fileJSON
17+
fileHTML
18+
fileTemplate
19+
20+
DirTreeNode = ref object
21+
depth: uint
22+
name: string
23+
path: string
24+
parent: DirTreeNode
25+
case kind: ItemKind
26+
of itemDir:
27+
contents: seq[DirTreeNode]
28+
style: string
29+
config: JsonNode
30+
of itemFile:
31+
fileKind: FileKind
32+
33+
34+
proc convertMarkdownToNercPage(tree: DirTreeNode)
35+
proc buildDirTree(node: DirTreeNode, depth: uint)
36+
proc printTree(tree: DirTreeNode)
37+
proc genSidebar( tree: DirTreeNode, currentItem: DirTreeNode): string
38+
proc populateDirs(treeRoot: DirTreeNode)
39+
40+
41+
const
42+
PageTitleTag: string = "<!--page title-->"
43+
StyleOverrideTag: string = "<!--style override-->"
44+
LinksLeftTag: string = "<!--links left-->"
45+
LinksRightTag: string = "<!--links right-->"
46+
SiteTitleTag: string = "<!--site title-->"
47+
SubtitleTag: string = "<!--subtitle-->"
48+
SidebarTag: string = "<!--sidebar-->"
49+
ContentTag: string = "<!--content-->"
50+
FooterLeftTag: string = "<!--footer left-->"
51+
FooterRightTag: string = "<!--footer right-->"
52+
53+
htmlTemplate = staticRead("res/template.htm")
54+
defaultStyle = staticRead("res/styles.css")
55+
defaultJson = staticRead("res/config.json")
56+
57+
58+
var
59+
pageTitle: string
60+
htmlSidebar: string
61+
htmlLinksLeft: string
62+
htmlLinksRight: string
63+
htmlFooterLeft: string
64+
htmlFooterRight: string
65+
66+
fsTree: DirTreeNode = DirTreeNode(depth: 0, name: "Main", path: ".", kind: itemDir)
67+
68+
69+
70+
proc removeSuffixInsensitive(s, suffix: string): string =
71+
if s.toLowerAscii().endsWith(suffix.toLowerAscii()):
72+
return s[0 ..< s.len - suffix.len]
73+
return s
74+
75+
76+
proc convertMarkdownToNercPage(tree: DirTreeNode) =
77+
echo tree.path[2..^1] & " : " & tree.name & "\n\n\n"
78+
if tree.kind == itemDir: return
79+
80+
var outPath: string = tree.path[2..^1]
81+
outPath.removeSuffix(".md")
82+
if toLowerAscii(outPath).endsWith("readme"):
83+
outpath = outPath.removeSuffixInsensitive("readme") & "index"
84+
outPath = outPath & ".htm"
85+
86+
let mdFile = readFile(tree.path[2..^1])
87+
88+
var htmlTxt = htmlTemplate.replace(ContentTag,markdown(mdFile))
89+
htmlTxt = htmlTxt.replace(SidebarTag,genSidebar(fsTree,tree))
90+
91+
writefile(outPath, htmlTxt)
92+
93+
94+
proc buildDirTree(node: DirTreeNode, depth: uint) =
95+
let path = node.path
96+
97+
for kind, name in walkDir(path, relative = true):
98+
if name[0] == '.': continue # Skip hidden files and directories (such as .git)
99+
if kind == pcFile:
100+
var new_node: DirTreeNode = DirTreeNode(depth: depth, kind: itemFile, name: name.split('.')[0].replace('_', ' '), path: path & '/' & name)
101+
102+
if name.toLowerAscii().endsWith(".md"):
103+
new_node.fileKind = fileMarkdown
104+
#convertMarkdownToNercPage(path)
105+
elif name.toLowerAscii() == "config.json":
106+
new_node.fileKind = fileJSON
107+
elif name.toLowerAscii() == "template.htm":
108+
new_node.fileKind = fileTemplate
109+
elif name.toLowerAscii().endsWith(".htm") || name.toLowerAscii().endsWith(".html"):
110+
new_node.fileKind = fileHTML
111+
else: continue
112+
113+
#echo "\t", path & "/" & name
114+
node.contents.add(new_node)
115+
116+
elif kind == pcDir:
117+
var new_node: DirTreeNode = DirTreeNode(depth: depth, kind: itemDir, name: name, path: path & '/' & name)
118+
#echo path & "/" & name
119+
buildDirTree(new_node, depth+1)
120+
node.contents.add(new_node)
121+
122+
123+
proc printTree(tree: DirTreeNode) =
124+
if tree.kind == itemFile:
125+
126+
case tree.fileKind
127+
of fileMarkdown: echo tree.depth, repeat('\t', tree.depth), tree.name, " : Markdown"
128+
of fileJSON: echo tree.depth, repeat('\t', tree.depth), tree.name, " : JSON"
129+
of fileTemplate: echo tree.depth, repeat('\t', tree.depth), tree.name, " : HTML"
130+
131+
elif tree.kind == itemDir:
132+
echo repeat('\t', tree.depth), tree.path, " : ", tree.name, " : ", tree.contents.len()
133+
134+
for item in tree.contents:
135+
printTree(item)
136+
continue
137+
138+
139+
proc genSidebar(tree: DirTreeNode, currentItem: DirTreeNode): string =
140+
var sidebar: string
141+
142+
if tree.kind == itemFile:
143+
if tree.fileKind != fileMarkdown: return ""
144+
145+
var
146+
name = tree.name
147+
path = tree.path
148+
149+
path.removeSuffix("md")
150+
path = path & "htm"
151+
152+
if "readme" == toLowerAscii(name): return ""
153+
if "index" == name: return ""
154+
if tree == currentItem: name = ">> " & name & " <<"
155+
156+
return repeat('\t', tree.depth) & "<li class=\"page\"><a href=\"" & path & "\">" & name & "</a></li>\n"
157+
158+
elif tree.kind == itemDir:
159+
var
160+
itemList: string
161+
name = tree.name
162+
163+
if tree.depth == 0: name = "Main"
164+
165+
for item in tree.contents:
166+
itemList = itemList & genSidebar(item, currentItem)
167+
168+
itemList =
169+
"<li class=\"dir\"><a href=\"" & tree.path & "\">" & name & "</a>\n" & "<ul>\n" &
170+
itemList &
171+
"</ul>\n</li>"
172+
173+
if tree.depth == 0: itemList = "<ul>\n" & itemList & "\n</ul>"
174+
175+
return itemList
176+
177+
178+
proc populateDirs(treeRoot: DirTreeNode) =
179+
180+
for node in treeRoot.contents:
181+
if node.kind == itemFile:
182+
if node.fileKind != fileMarkdown: continue
183+
convertMarkdownToNercPage(node)
184+
elif node.kind == itemDir:
185+
populateDirs(node)
186+
187+
188+
proc main() =
189+
let args = commandLineParams()
190+
let currentDir = "."
191+
192+
if 0 < args.len:
193+
if isValidFileName(args[0]):
194+
echo args[0]
195+
196+
buildDirTree(fsTree, 1)
197+
printTree(fsTree)
198+
populateDirs(fsTree)
199+
200+
main()

src/res/config.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"page title": "Default nerc site",
3+
"site title": "Default nerc site",
4+
"subtitle": "These settings can be overridden by putting a config.json file in the root of this nerc site.",
5+
"footer left": "This page was generated by<a href=\"\">nerc</a>.",
6+
"footer right": "nerc is public domain/0BSD software."
7+
}

src/res/styles.css

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
* {
2+
font-family: 'Liver';
3+
margin: 0px;
4+
padding: 0px;
5+
}
6+
7+
body {
8+
width: 100%;
9+
height: 100%;
10+
display: flex;
11+
flex-direction: column;
12+
position: absolute;
13+
background: #737573;
14+
}
15+
16+
.spacer {
17+
flex-grow: 1;
18+
}
19+
20+
.nerc {
21+
margin:5px;
22+
box-shadow: 5px 5px 0 0 rgba(0, 0, 0, 0.125);
23+
border: 4px solid;
24+
display: flex;
25+
}
26+
27+
#container {
28+
display: flex;
29+
flex-direction: column;
30+
height:100vh;
31+
padding: 5px;
32+
width: 1024px;
33+
margin: auto;
34+
}
35+
36+
#links {
37+
background: #efffef;
38+
border-color: #8ccf8c;
39+
padding-left: 8px;
40+
padding-right: 8px;
41+
}
42+
43+
#header {
44+
background: #efffff;
45+
border-color: #9cefef;
46+
padding-left: 8px;
47+
}
48+
49+
#body {
50+
width: 100%;
51+
display:flex;
52+
flex-grow: 1;
53+
flex-direction: row;
54+
}
55+
56+
#sidebar {
57+
font-family: 'Liver';
58+
background-color: #ffffef;
59+
border-color: #428a42;
60+
display: block;
61+
left: 0px;
62+
padding-top: 20px;
63+
padding-left: 40px;
64+
min-width:200px;
65+
flex-shrink:0;
66+
}
67+
#sidebar ul li {
68+
padding-left: 8px;
69+
font-size: 14pt;
70+
display: list-item;
71+
align-items: center;
72+
}
73+
74+
#content {
75+
background: #ffffff;
76+
border-color: #52aaad;
77+
display: block;
78+
flex-grow: 1;
79+
padding-left: 80px;
80+
padding-right: 80px;
81+
padding-top: 40px;
82+
padding-bottom: 40px;
83+
}
84+
#content h1 {
85+
display: block;
86+
text-align: center;
87+
border-bottom: 1px solid black;
88+
margin-bottom: 24px;
89+
}
90+
#content p {
91+
text-indent: 1.5em;
92+
display: block;
93+
max-width: 800px;
94+
margin: auto;
95+
}
96+
#content img {
97+
display: block;
98+
width: 100%;
99+
height: auto;
100+
margin: auto;
101+
}
102+
103+
#footer {
104+
background-color: #8c8ace;
105+
border-color: #00009c;
106+
padding-left:8px;
107+
padding-right: 8px;
108+
}

0 commit comments

Comments
 (0)