1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-20 09:26:23 -07:00

Completely redo front.html to make it more mobile-friendly

Also add Photon theme
This commit is contained in:
eggbertx 2019-02-16 19:18:00 -08:00
parent 06ec16938c
commit d558bcc0d0
22 changed files with 338 additions and 252 deletions

2
.gitignore vendored
View file

@ -7,6 +7,6 @@ vagrant/.vagrant/
vagrant/*.log
html/boards.json
html/index.html
html/test/
html/test*
templates/override/
**/*.bak

View file

@ -36,7 +36,8 @@
"Styles": [
{ "Name": "Pipes", "Filename": "pipes.css" },
{ "Name": "Burichan", "Filename": "burichan.css" }
{ "Name": "Burichan", "Filename": "burichan.css" },
{ "Name": "Photon", "Filename": "photon.css" }
],
"DefaultStyle": "pipes.css",
@ -79,6 +80,7 @@
"_comment": "set GeoIPDBlocation to cf to use Cloudflare's GeoIP",
"GeoIPDBlocation": "/usr/share/GeoIP/GeoIP.dat",
"MaxRecentPosts": 3,
"RecentPostsWithNoFile": false,
"Verbosity": 0,
"EnableAppeals": true,
"MaxLogDays": 14,

View file

@ -266,18 +266,28 @@ col#recent {
}
div#recent-posts {
margin-right: 8px;
margin: auto;
display: block;
width: 90%;
}
div#recent-posts div.recent-post {
vertical-align: top;
display: inline-block;
}
div#recent-posts img {
padding-right: 8px;
}
div#recent-posts div.section-body {
padding-top: 8px;
word-wrap: break-word;
overflow: hidden;
margin-top: 5px;
padding: 5px 0 3px;
position: relative;
width: 200px;
max-height: 320px;
margin-bottom: 10px;
text-align: center;
}
div#main {
div#frontpage {
overflow: hidden;
width: 80%;
margin: auto;
}
a.permalink {

59
html/css/photon.css Normal file
View file

@ -0,0 +1,59 @@
div.reply {
background-color: #ddd;
border: 1px solid #ccc;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
span.subject {
color: #024;
}
div.section-title-block {
background-color: #ccc;
}
div.section-block {
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
background-color: #FCFCFC;
border: 1px solid #D7D7D7;
}
body {
background-color: #eee;
font: 15px "Trebuchet MS", Trebuchet, sans-serif;
}
a {
text-decoration: none;
}
div#topbar, div.dropdown-menu {
background-color: #000;
opacity: 0.7;
padding: 2px;
}
div#topbar {
-moz-box-shadow: 0px 2px 2px 2px #292929;
-ms-box-shadow: 0px 2px 2px 2px #292929;
-webkit-box-shadow: 0px 2px 2px 2px #292929;
box-shadow: 0px 2px 2px 2px #292929;
}
div.dropdown-menu {
color: #FFF;
}
header, div#top-pane, a {
color: #f60;
}
span#site-title, div#board-title {
font-weight: 800;
}

View file

@ -7,6 +7,6 @@
<h1>404: File not found</h1>
<img src="/error/lol 404.gif" border="0" alt="">
<p>The requested file could not be found on this server. Are you just typing random stuff in the address bar? If you followed a link from this site here, then post <a href="/site">here</a></p>
<hr><address>http://gochan.org powered by Gochan v2.5</address>
<hr><address>http://gochan.org powered by Gochan v2.6</address>
</body>
</html>

View file

@ -7,6 +7,6 @@
<h1>500: Internal Server error</h1>
<img src="/error/derpy server.gif" border="0" alt="">
<p>The server encountered an error while trying to serve the page, and we apologize for the inconvenience. The <a href="https://en.wikipedia.org/wiki/Idiot">system administrator</a> will try to fix things as soon has he/she/it can.</p>
<hr><address>http://gochan.org powered by Gochan v2.5</address>
<hr><address>http://gochan.org powered by Gochan v2.6</address>
</body>
</html>

View file

@ -197,63 +197,6 @@ function showMessage(msg) {
});
}
// organize front page into tabs
function changeFrontPage(page_name) {
var tabs = $jq(".tab");
var pages = $jq(".page");
var current_page = window.location.hash.replace("#","");
pages.hide();
if(current_page=="") {
$jq(pages[0]).show();
} else {
for(var p = 0; p < pages.length; p++) {
var page = $jq(pages[p]);
if(page.attr("id").replace("-page","").replace("page","") == current_page) {
page.show()
}
}
}
for(var i = 0; i < tabs.length; i++) {
var child = $jq(tabs[i]).children(0)
var tabname = child.text();
if(tabname.toLowerCase() == current_page) {
$jq("#current-tab").attr({"id":""});
child.parent().attr({"id":"current-tab"});
}
}
tabs.find("a").click(function(event) {
var current_page = this.href.substring(this.href.lastIndexOf("#")+1);
if(current_page == "") {
$jq("#current-tab").attr({"id":""});
$jq(tabs[0]).attr({"id":"current-tab"});
} else {
for(var i = 0; i < tabs.length; i++) {
var child = $jq(tabs[i]).children(0)
var tabname = child.text();
if(tabname.toLowerCase() == current_page) {
$jq("#current-tab").attr({"id":""});
$jq(tabs[i]).attr({"id":"current-tab"});
}
}
}
pages.hide()
if(current_page=="") {
$jq(pages[0]).show();
} else {
for(var p = 0; p < pages.length; p++) {
var page = $jq(pages[p]);
if(page.attr("id").replace("-page","").replace("page","") == current_page) {
page.show()
}
}
}
});
}
// heavily based on 4chan's quote() function, with a few tweaks
function quote(e) {
@ -614,8 +557,7 @@ $jq(document).ready(function() {
addStaffButtons();
}
if(pageThread.board == "") changeFrontPage(window.location.hash);
else {
if(pageThread.board != "") {
prepareThumbnails();
if(getCookie("useqr") == "true") initQR(pageThread);
}
@ -637,22 +579,21 @@ $jq(document).ready(function() {
var post_id = $jq(this).parent().parent().parent().attr("id");
var is_op = $jq(this).parent().parent().parent().attr("class") == "thread";
if(post_id != undefined) {
if($jq(this).parent().find("div.thread-ddown-menu").length == 0) {
$jq("div.thread-ddown-menu").remove();
if(post_id == undefined) return;
if($jq(this).parent().find("div.thread-ddown-menu").length == 0) {
$jq("div.thread-ddown-menu").remove();
menu_html = "<div class=\"thread-ddown-menu\" id=\""+post_id+"\">";
if(!is_op) menu_html += "<ul><li><a href=\"javascript:hidePost("+post_id+");\" class=\"hide-post\">Show/Hide post</a></li>";
menu_html +="<li><a href=\"javascript:deletePost("+post_id+");\" class=\"delete-post\">Delete post</a></li>" +
"<li><a href=\"javascript:reportPost("+post_id+");\" class=\"report-post\">Report Post</a></li></ul>" +
"</div>";
menu_html = "<div class=\"thread-ddown-menu\" id=\""+post_id+"\">";
if(!is_op) menu_html += "<ul><li><a href=\"javascript:hidePost("+post_id+");\" class=\"hide-post\">Show/Hide post</a></li>";
menu_html +="<li><a href=\"javascript:deletePost("+post_id+");\" class=\"delete-post\">Delete post</a></li>" +
"<li><a href=\"javascript:reportPost("+post_id+");\" class=\"report-post\">Report Post</a></li></ul>" +
"</div>";
$jq(this).parent().append(menu_html);
thread_menu_open = true;
} else {
$jq("div.thread-ddown-menu").remove();
thread_menu_open = false;
}
$jq(this).parent().append(menu_html);
thread_menu_open = true;
} else {
$jq("div.thread-ddown-menu").remove();
thread_menu_open = false;
}
});
});

View file

@ -46,20 +46,30 @@ col#recent {
}
div#recent-posts {
margin-right: 8px;
display: inline-block;
img {
padding-right: 8px;
}
div.section-body {
padding-top: 8px;
margin:auto;
display: block;
width:90%;
div.recent-post {
vertical-align: top;
display: inline-block;
word-wrap: break-word;
overflow: hidden;
margin-top: 5px;
padding: 5px 0 3px;
position: relative;
width: 200px;
max-height: 320px;
margin-bottom: 10px;
text-align:center;
}
}
div#main {
overflow: hidden
div#frontpage {
overflow: hidden;
width: 80%;
margin:auto;
}
a.permalink {
float: right;
}
}

34
sass/photon.scss Normal file
View file

@ -0,0 +1,34 @@
@import 'photon/colors';
@import 'photon/img';
@import 'util';
body {
background-color: $bgcol;
font: 15px $font;
}
a {
text-decoration: none;
}
div#topbar, div.dropdown-menu {
background-color: #000;
opacity: 0.7;
padding: 2px;
}
div#topbar {
@include box-shadow(0px 2px 2px 2px $shadowcol);
}
div.dropdown-menu {
color: #FFF;
}
header, div#top-pane, a {
color: $linkcol;
}
span#site-title, div#board-title {
font-weight: 800;
}

11
sass/photon/_colors.scss Normal file
View file

@ -0,0 +1,11 @@
$bgcol: #eee;
$replycol: #ddd;
$replyborder: #ccc;
$fontcol: #333;
$linkcol: #f60;
$subjectcol: #024;
$shadowcol: #292929;
$sectionbg: #FCFCFC;
$sectionborder: #D7D7D7;
$font: 'Trebuchet MS',Trebuchet,sans-serif;

0
sass/photon/_front.scss Normal file
View file

22
sass/photon/_img.scss Normal file
View file

@ -0,0 +1,22 @@
@import '../util';
@import 'colors';
div.reply {
background-color: $replycol;
border: 1px solid $replyborder;
@include border-radius(5px);
}
span.subject {
color: $subjectcol;
}
div.section-title-block {
background-color: $replyborder;
}
div.section-block {
@include border-radius(5px);
background-color: $sectionbg;
border: 1px solid $sectionborder;
}

View file

@ -13,11 +13,9 @@ import (
)
// build front page using templates/front.html
// TODO: provide alternative layouts (like 4chan, tinyboard, etc)
func buildFrontPage() (html string) {
initTemplates()
var front_arr []interface{}
var recent_posts_arr []interface{}
var recentPostsArr []interface{}
os.Remove(path.Join(config.DocumentRoot, "index.html"))
front_file, err := os.OpenFile(path.Join(config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
@ -26,54 +24,49 @@ func buildFrontPage() (html string) {
return handleError(1, "Failed opening front page for writing: "+err.Error()) + "<br />\n"
}
// get front pages
rows, err := querySQL("SELECT * FROM `" + config.DBprefix + "frontpage`")
defer closeRows(rows)
if err != nil {
return handleError(1, "Failed getting front page rows: "+err.Error())
}
for rows.Next() {
frontpage := new(FrontTable)
if err = rows.Scan(&frontpage.ID, &frontpage.Page, &frontpage.Order, &frontpage.Subject,
&frontpage.Message, &frontpage.Timestamp, &frontpage.Poster, &frontpage.Email); err != nil {
return handleError(1, err.Error())
}
front_arr = append(front_arr, frontpage)
}
// get recent posts
rows, err = querySQL("SELECT `"+config.DBprefix+"posts`.`id`, "+
"`"+config.DBprefix+"posts`.`parentid`, "+
"`"+config.DBprefix+"boards`.`dir` AS boardname, "+
"`"+config.DBprefix+"posts`.`boardid` AS boardid, "+
"`name`, `tripcode`, `message`, `filename`, `thumb_w`, `thumb_h` "+
"FROM `"+config.DBprefix+"posts`, `"+config.DBprefix+"boards` "+
"WHERE `"+config.DBprefix+"posts`.`deleted_timestamp` = ? "+
"AND `boardid` = `"+config.DBprefix+"boards`.`id` "+
"ORDER BY `timestamp` DESC LIMIT ?",
nilTimestamp, config.MaxRecentPosts,
)
recentQueryStr := "SELECT `" + config.DBprefix + "posts`.`id`, " +
"`" + config.DBprefix + "posts`.`parentid`, " +
"`" + config.DBprefix + "boards`.`dir` AS boardname, " +
"`" + config.DBprefix + "posts`.`boardid` AS boardid, " +
"`name`, `tripcode`, `message`, `filename`, `thumb_w`, `thumb_h` " +
"FROM `" + config.DBprefix + "posts`, `" + config.DBprefix + "boards` " +
"WHERE `" + config.DBprefix + "posts`.`deleted_timestamp` = ? "
if !config.RecentPostsWithNoFile {
recentQueryStr += "AND `" + config.DBprefix + "posts`.`filename` != '' AND `" + config.DBprefix + "posts`.filename != 'deleted' "
}
recentQueryStr += "AND `boardid` = `" + config.DBprefix + "boards`.`id` " +
"ORDER BY `timestamp` DESC LIMIT ?"
rows, err := querySQL(recentQueryStr, nilTimestamp, config.MaxRecentPosts)
defer closeRows(rows)
if err != nil {
return handleError(1, err.Error())
}
for rows.Next() {
recent_post := new(RecentPost)
err = rows.Scan(&recent_post.PostID, &recent_post.ParentID, &recent_post.BoardName, &recent_post.BoardID, &recent_post.Name, &recent_post.Tripcode, &recent_post.Message, &recent_post.Filename, &recent_post.ThumbW, &recent_post.ThumbH)
if err != nil {
recentPost := new(RecentPost)
if err = rows.Scan(
&recentPost.PostID, &recentPost.ParentID, &recentPost.BoardName, &recentPost.BoardID,
&recentPost.Name, &recentPost.Tripcode, &recentPost.Message, &recentPost.Filename, &recentPost.ThumbW, &recentPost.ThumbH,
); err != nil {
return handleError(1, "Failed getting list of recent posts for front page: "+err.Error())
}
recent_posts_arr = append(recent_posts_arr, recent_post)
recentPostsArr = append(recentPostsArr, recentPost)
}
for i := range allBoards {
board := allBoards[i].(BoardsTable)
if board.Section == 0 {
board.Section = 1
}
}
if err = front_page_tmpl.Execute(front_file, map[string]interface{}{
"config": config,
"fronts": front_arr,
"boards": allBoards,
"sections": allSections,
"recent_posts": recent_posts_arr,
"boards": allBoards,
"recent_posts": recentPostsArr,
}); err != nil {
return handleError(1, "Failed executing front page template: "+err.Error())
}

View file

@ -973,6 +973,7 @@ var manage_functions = map[string]ManageFunction{
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
initTemplates()
resetBoardSectionArrays()
return buildFrontPage() + "<hr />\n" +
buildBoardListJSON() + "<hr />\n" +
buildBoards(true, 0) + "<hr />\n"

View file

@ -58,6 +58,7 @@ func (s GochanServer) serveFile(writer http.ResponseWriter, request *http.Reques
writer.Header().Add("Content-Type", "image/gif")
writer.Header().Add("Cache-Control", "max-age=86400")
case "jpg":
case "jpeg":
writer.Header().Add("Content-Type", "image/jpeg")
writer.Header().Add("Cache-Control", "max-age=86400")
case "css":

View file

@ -9,6 +9,8 @@ import (
"strconv"
"strings"
"text/template"
x_html "golang.org/x/net/html"
)
var funcMap = template.FuncMap{
@ -112,6 +114,21 @@ var funcMap = template.FuncMap{
}
return msg
},
"stripHTML": func(htmlStr string) string {
dom := x_html.NewTokenizer(strings.NewReader(htmlStr))
for tokenType := dom.Next(); tokenType != x_html.ErrorToken; {
if tokenType != x_html.TextToken {
tokenType = dom.Next()
continue
}
txtContent := strings.TrimSpace(x_html.UnescapeString(string(dom.Text())))
if len(txtContent) > 0 {
return x_html.EscapeString(txtContent)
}
tokenType = dom.Next()
}
return ""
},
"truncateString": func(msg string, limit int, ellipsis bool) string {
if len(msg) > limit {
if ellipsis {
@ -138,6 +155,27 @@ var funcMap = template.FuncMap{
}
return
},
"getPostURL": func(post_i interface{}, typeOf string, withDomain bool) (postURL string) {
if withDomain {
postURL = config.SiteDomain
}
postURL += config.SiteWebfolder
if typeOf == "recent" {
post, ok := post_i.(*RecentPost)
if !ok {
return
}
postURL = post.GetURL(withDomain)
} else {
post, ok := post_i.(*PostTable)
if !ok {
return
}
postURL = post.GetURL(withDomain)
}
return
},
"getThreadThumbnail": func(img string) string {
return getThumbnailPath("thread", img)
},
@ -341,7 +379,7 @@ func initTemplates() error {
return templateError("manage_header.html", err)
}
front_page_tmpl, err = loadTemplate("front.html", "global_footer.html")
front_page_tmpl, err = loadTemplate("front.html", "front_intro.html", "img_header.html", "global_footer.html")
if err != nil {
return templateError("front.html", err)
}

View file

@ -7,6 +7,7 @@ import (
"log"
"os"
"path"
"strconv"
"time"
"github.com/frustra/bbcode"
@ -37,6 +38,21 @@ type RecentPost struct {
Timestamp time.Time
}
func (p *RecentPost) GetURL(includeDomain bool) string {
postURL := ""
if includeDomain {
postURL += config.SiteDomain
}
idStr := strconv.Itoa(p.PostID)
postURL += config.SiteWebfolder + p.BoardName + "/res/"
if p.ParentID == 0 {
postURL += idStr + ".html#" + idStr
} else {
postURL += strconv.Itoa(p.ParentID) + ".html#" + idStr
}
return postURL
}
type Thread struct {
OP PostTable
NumReplies int
@ -234,6 +250,27 @@ type PostTable struct {
Sillytag bool
}
func (p *PostTable) GetURL(includeDomain bool) string {
postURL := ""
if includeDomain {
postURL += config.SiteDomain
}
board, err := getBoardFromID(p.BoardID)
if err != nil {
return postURL
}
idStr := strconv.Itoa(p.ID)
postURL += config.SiteWebfolder + board.Dir + "/res/"
if p.ParentID == 0 {
postURL += idStr + ".html#" + idStr
} else {
postURL += strconv.Itoa(p.ParentID) + ".html#" + idStr
}
return postURL
}
// Sanitize escapes HTML strings in a post. This should be run immediately before
// the post is inserted into the database
func (p *PostTable) Sanitize() {
@ -421,11 +458,12 @@ type GochanConfig struct {
NewTabOnOutlinks bool `description:"If checked, links to external sites will open in a new tab." default:"checked"`
EnableQuickReply bool `description:"If checked, an optional quick reply box is used. This may end up being removed." default:"checked"`
DateTimeFormat string `description:"The format used for dates. See <a href=\"https://golang.org/pkg/time/#Time.Format\">here</a> for more info."`
AkismetAPIKey string `description:"The API key to be sent to Akismet for post spam checking. If the key is invalid, Akismet won't be used."`
EnableGeoIP bool `description:"If checked, this enables the usage of GeoIP for posts." default:"checked"`
GeoIPDBlocation string `description:"Specifies the location of the GeoIP database file. If you're using CloudFlare, you can set it to cf to rely on CloudFlare for GeoIP information." default:"/usr/share/GeoIP/GeoIP.dat"`
MaxRecentPosts int `description:"The maximum number of posts to show on the Recent Posts list on the front page." default:"3"`
DateTimeFormat string `description:"The format used for dates. See <a href=\"https://golang.org/pkg/time/#Time.Format\">here</a> for more info."`
AkismetAPIKey string `description:"The API key to be sent to Akismet for post spam checking. If the key is invalid, Akismet won't be used."`
EnableGeoIP bool `description:"If checked, this enables the usage of GeoIP for posts." default:"checked"`
GeoIPDBlocation string `description:"Specifies the location of the GeoIP database file. If you're using CloudFlare, you can set it to cf to rely on CloudFlare for GeoIP information." default:"/usr/share/GeoIP/GeoIP.dat"`
MaxRecentPosts int `description:"The maximum number of posts to show on the Recent Posts list on the front page." default:"3"`
RecentPostsWithNoFile bool `description:"If checked, recent posts with no image/upload are shown on the front page (as well as those with images" default:"unchecked"`
// Verbosity = 0 for no debugging info. Critical errors and general output only
// Verbosity = 1 for non-critical warnings and important info
// Verbosity = 2 for all debugging/benchmarks/warnings

View file

@ -1,108 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.config.SiteName}}</title>
<script type="text/javascript" src="{{.config.SiteWebfolder}}javascript/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
var styles = [{{range $ii, $style := .config.Styles}}{{if gt $ii 0}}, {{end}}{Name: "{{$style.Name}}", Filename: "{{$style.Filename}}"}{{end}}];
var defaultStyle = "{{.config.DefaultStyle}}";
var webroot = "{{.config.SiteWebfolder}}"
</script>
<script type="text/javascript" src="{{.config.SiteWebfolder}}javascript/gochan.js"></script>
<script type="text/javascript" src="{{.config.SiteWebfolder}}javascript/manage.js"></script>
<link rel="stylesheet" href="{{.config.SiteWebfolder}}css/global.css" />
<link id="theme" rel="stylesheet" href="{{.config.SiteWebfolder}}css/{{.config.DefaultStyle}}" />
<link rel="shortcut icon" href="{{.config.SiteWebfolder}}favicon.png">
</head>
<body>
<div id="topbar">{{range $i, $board := .boards}}
<a href="{{$.config.SiteWebfolder}}{{$board.Dir}}/" class="topbar-item">/{{$board.Dir}}/</a>{{end}}
</div>
{{template "img_header.html" .}}
<div id="top-pane">
<span id="site-title">{{.config.SiteName}}</span><br />
<span id="site-slogan">{{.config.SiteSlogan}}</span>
</div><br />
<div id="frontpage">
<div class="section-block" style="margin: 16px 64px 16px 64px;">
<div class="section-body">
{{template "front_intro.html" .}}
</div>
</div>
<div class="section-block">
<div class="section-title-block"><b>Boards</b></div>
<div class="section-body">
{{range $_, $section := .sections}}{{if not $section.Hidden}}<ul style="float:left; list-style: none">
<li style="text-align: center; font-weight: bold"><b><u>{{$section.Name}}</u></b></li>
{{range $_, $board := $.boards}}{{if and (eq $board.Section $section.ID) (ne $board.Dir $.config.Modboard)}}
<li><a href="{{$.config.SiteWebfolder}}{{$board.Dir}}/" title="{{$board.Description}}">/{{$board.Dir}}/</a> — {{$board.Title}}</li>
{{end}}{{end}}
</ul>{{end}}{{end}}
</div>
</div>
{{if gt .config.MaxRecentPosts 0}}
<div class="section-block">
<div class="section-title-block"><b>Recent Posts</b></div>
<div class="section-body">
<div id="recent-posts">
{{range $i, $post := $.recent_posts}}{{$postURL := getPostURL $post "recent" false}}
<div class="recent-post">
{{if and (ne $post.Filename "deleted") (ne $post.Filename "")}}<a href="{{$postURL}}" class="front-reply" target="_blank"><img src="{{$.config.SiteWebfolder}}{{$post.BoardName}}/thumb/{{getThreadThumbnail $post.Filename}}" alt="post thumbnail"/></a><br />
{{else}}<div class="file-deleted-box" style="text-align:center; float:none;"><a href="{{$.postURL}}" class="front-reply" target="_blank">No file</a></div>{{end}}<br />
<a href="{{$.config.SiteWebfolder}}{{$post.BoardName}}/">/{{$post.BoardName}}/</a>
<hr />
{{truncateMessage (stripHTML $post.Message) 40 4}}</div>{{end}}</div>
</div>{{end}}</div>
</div>
<div id="main">
<table style="width:100%" cellspacing="10">
<colgroup>
<col id="sections" />
<col id="recent" />
</colgroup>
<tr>
<td valign="top">
<ul id="tab-bar">
<li id="current-tab" class="tab">
<a href="#">News</a>
</li>
<li class="tab">
<a href="#boards">Boards</a>
</li>
<li class="tab">
<a href="#rules">Rules</a>
</li>
<li class="tab">
<a href="#faq">FAQ</a>
</li>
</ul>
<div id="first-page" class="page">{{range $ii, $page := .page_arr}}{{if eq $page.Page 0}}
<div class="section-block">
<div class="section-title-block" id="first-page0">
<b>{{$page.Subject}}</b> by <a href="mailto:{{$page.Email}}" >{{$page.Poster}}</a><a href="{{.config.SiteWebfolder}}#first-page{{$ii}}" class="permalink">#</a>
</div>
<div class="section-body">
{{$page.Message}}
</div>
</div>{{end}}{{end}}
</div>
<div id="boards-page" class="page">
<div class="section-block">
<div class="section-title-block">
<b>Boards</b>
</div>
<div class="section-body">
<ul>{{range $_, $board := .boards}}{{if eq $board.Dir $.config.Modboard}}{{else}}
<li><b>/{{$board.Dir}}/</b> {{$board.Description}}</li>{{end}}{{end}}
</ul>
</div>
</div>
</div>
<div id="rules-page" class="page">{{range $ii, $page := .page_arr}}{{if eq $page.Page 1}}
<div class="section-block">
<div class="section-title-block" id="first-page0">
<b>{{$page.Subject}}</b> by <a href="mailto:{{$page.Email}}" >{{$page.Poster}}</a><a href="{{.config.SiteWebfolder}}#first-page{{$ii}}" class="permalink">#</a>
</div>
<div class="section-body">
{{$page.Message}}
</div>
</div>{{end}}{{end}}
</div>
<div id="faq-page" class="page">{{range $ii, $page := .page_arr.Data}}{{if eq $page.Page 2}}
<div class="section-block">
<div class="section-title-block" id="first-page0">
<b>{{$page.Subject}}</b> by <a href="mailto:{{$page.Email}}" >{{$page.Poster}}</a><a href="{{.config.SiteWebfolder}}#first-page{{$ii}}" class="permalink">#</a>
</div>
<div class="section-body">
{{$page.Message}}
</div>
</div>{{end}}{{end}}
</div>
</td>
{{if gt .config.MaxRecentPosts 0}}<td>
<div id="recent-posts-header" class="section-title-block"><b>Recent Posts</b></div>
{{range $i, $post := $.recent_posts}}<div class="section-block">
<div class="section-title-block">
<span class="section-title"><a href="{{$post.BoardName}}/res/{{if eq $post.ParentID 0}}{{intToString $post.PostID}}.html{{else}}{{intToString $post.ParentID}}.html#{{intToString $post.PostID}}{{end}}">/{{$post.BoardName}}/</a></span> - {{$appended := stringAppend $post.Name $post.Tripcode}}{{if eq $appended ""}}<b>Anonymous</b>{{else}}<b>{{$post.Name}}</b>{{if ne $post.Tripcode ""}}!{{$post.Tripcode}}{{end}}{{end}}
</div>
<div class="section-body">
{{if ne $post.Filename ""}}<a href="{{$.config.SiteWebfolder}}{{$post.BoardName}}/src/{{$post.Filename}}" target="_blank"><img src="{{$.config.SiteWebfolder}}{{$post.BoardName}}/thumb/{{getThreadThumbnail $post.Filename}}" alt="post thumbnail"/></a>{{end}}
{{truncateMessage $post.Message 225 12}}
</div>
</div>{{end}}{{end}}
</td>
</tr>
</table>
</div>
{{template "global_footer.html" .}}
{{template "global_footer.html" .}}

View file

@ -0,0 +1 @@
Welcome to Gochan!

View file

@ -3,13 +3,10 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{with $.op.Subject}}
{{if ne $.op.Subject ""}}
<title>/{{$.board.Dir}}/ - {{truncateString $.op.Subject 20 true}}</title>
{{else if ne $.op.MessageHTML ""}}
<title>/{{$.board.Dir}}/ - {{truncateString $.op.MessageText 20 true}}</title>
{{end}}
{{else}}<title>/{{.board.Dir}}/ - {{.board.Title}}</title>{{end}}
{{with $.op.Subject}}{{if ne $.op.Subject ""}}<title>/{{$.board.Dir}}/ - {{truncateString $.op.Subject 20 true}}</title>
{{else if ne $.op.MessageHTML ""}}<title>/{{$.board.Dir}}/ - {{truncateString $.op.MessageText 20 true}}</title>
{{end}}{{else}}{{with $.recent_posts}}<title>{{$.config.SiteName}}</title>
{{else}}<title>/{{.board.Dir}}/ - {{.board.Title}}</title>{{end}}{{end}}
<script type="text/javascript" src="{{$.config.SiteWebfolder}}javascript/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
var styles = [{{range $ii, $style := .config.Styles}}{{if gt $ii 0}}, {{end}}{Name: "{{$style.Name}}", Filename: "{{$style.Filename}}"}{{end}}];

View file

@ -3,8 +3,7 @@
<table id="board-options">
<tr><th class="option-column">Option</th><th class="value-column">Value</th></tr>
<tr><td>Directory</td><td><input type="text" name="dir" value="" /></td></tr>
<tr><td>Section</td><td><select name="section" selected="0">
<option value="none">Select section...</option>{{range $_, $section := .section_arr}}
<tr><td>Section</td><td><select name="section" selected="0">{{range $_, $section := .section_arr}}
<option value="{{$section.ID}}">{{$section.Name}}</option>{{end}}
</select></td></tr>
<tr><td>Order</td><td><input type="text" name="order" value="0" /></td></tr>

View file

@ -1 +1 @@
2.5.0
2.6.0