Added a custom auto-link parser rather than using a regex.

Added the Tempra Cursive theme. A fork of Tempra Simple which is less boxy and uses the cursive font.
Improved the theme manager. Primary themes and variant themes (themes based upon another) are now seperate.
plugin_bbcode has been modified to use the URL parsing facilities of the core rather than implementing them itself.
git:// and ftp:// links are now supported by plugin_bbcode.
Added the simple quote BBCode.
Fixed a bug in route_like_topic where the no row error type isn't handled properly.
Moved the rowhead class onto the right element in the topic template.
Removed a couple of linebreaks in the topic template in favour of pure CSS.
Converted some inline CSS in the topic template into new CSS classes.

alerts.png contains some alert types for features which haven't been implemented yet, this is mainly to test if the alert system would work under the presence of those alert types. Think of this as my plans for the future.
This commit is contained in:
Azareal 2017-03-07 07:22:29 +00:00
parent 905a51d294
commit ea63768a8e
21 changed files with 897 additions and 87 deletions

View File

@ -9,9 +9,7 @@ More moderation features. E.g. Move, Approval Queue (Posts made by users in cert
Add a simple anti-spam measure. I have quite a few ideas in mind, but it'll take a while to implement the more advanced ones, so I'd like to put off some of those to a later date and focus on the basics. E.g. CAPTCHAs, hidden fields, etc.
Add a modern alert system.
Add per-forum permissions to finish up the foundations of the permissions system.
Add more granular permissions management to the Forum Manager.
Add a *better* plugin system. E.g. Allow for plugins written in Javascript and ones written in Go. Also, we need to add many, many, many more plugin hooks.

BIN
images/alerts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

BIN
images/tempra-cursive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

View File

@ -1410,15 +1410,21 @@ func route_panel_themes(w http.ResponseWriter, r *http.Request){
return
}
var themeList []interface{}
var pThemeList []Theme
var vThemeList []Theme
for _, theme := range themes {
if theme.HideFromThemes {
continue
}
themeList = append(themeList,theme)
if theme.ForkOf == "" {
pThemeList = append(pThemeList,theme)
} else {
vThemeList = append(vThemeList,theme)
}
pi := Page{"Theme Manager",user,noticeList,themeList,nil}
}
pi := ThemesPage{"Theme Manager",user,noticeList,pThemeList,vThemeList,nil}
err := templates.ExecuteTemplate(w,"panel-themes.html",pi)
if err != nil {
log.Print(err)

241
pages.go
View File

@ -1,4 +1,6 @@
package main
//import "fmt"
import "bytes"
import "strings"
import "regexp"
@ -73,6 +75,16 @@ type CreateTopicPage struct
ExtData interface{}
}
type ThemesPage struct
{
Title string
CurrentUser User
NoticeList []string
PrimaryThemes []Theme
VariantThemes []Theme
ExtData interface{}
}
type PageSimple struct
{
Title string
@ -85,6 +97,12 @@ type AreYouSure struct
Message string
}
var space_gap []byte = []byte(" ")
var http_prot_b []byte = []byte("http://")
var invalid_url []byte = []byte("<span style='color: red;'>[Invalid URL]</span>")
var url_open []byte = []byte("<a href='")
var url_open2 []byte = []byte("'>")
var url_close []byte = []byte("</a>")
var urlpattern string = `(?s)([ {1}])((http|https|ftp|mailto)*)(:{??)\/\/([\.a-zA-Z\/]+)([ {1}])`
var url_reg *regexp.Regexp
@ -144,6 +162,89 @@ func preparse_message(msg string) string {
}
func parse_message(msg string) string {
msg = strings.Replace(msg,":)","😀",-1)
msg = strings.Replace(msg,":D","😃",-1)
msg = strings.Replace(msg,":P","😛",-1)
//msg = url_reg.ReplaceAllString(msg,"<a href=\"$2$3//$4\" rel=\"nofollow\">$2$3//$4</a>")
// Search for URLs in the messages...
var msgbytes = []byte(msg)
outbytes := make([]byte, len(msgbytes))
msgbytes = append(msgbytes,space_gap...)
//fmt.Println(`"`+string(msgbytes)+`"`)
lastItem := 0
i := 0
for ; len(msgbytes) > (i + 1); i++ {
if i==0 || msgbytes[i] == 10 || (msgbytes[i] == ' ' && msgbytes[i + 1] != ' ') {
i++
if msgbytes[i] != 'h' && msgbytes[i] != 'f' && msgbytes[i] != 'g' && msgbytes[i + 1] != 't' {
continue
}
if msgbytes[i + 2] == 't' && msgbytes[i + 3] == 'p' {
if msgbytes[i + 4] == 's' && msgbytes[i + 5] == ':' && msgbytes[i + 6] == '/' && msgbytes[i + 7] == '/' {
// Do nothing
} else if msgbytes[i + 4] == ':' && msgbytes[i + 5] == '/' && msgbytes[i + 6] == '/' {
// Do nothing
} else {
continue
}
} else if msgbytes[i + 2] == 'p' && msgbytes[i + 3] == ':' && msgbytes[i + 4] == '/' && msgbytes[i + 5] == '/' {
// Do nothing
} else if msgbytes[i + 1] == 'i' && msgbytes[i + 2] == 't' && msgbytes[i + 3] == ':' && msgbytes[i + 4] == '/' && msgbytes[i + 5] == '/' {
// Do nothing
} else {
continue
}
outbytes = append(outbytes,msgbytes[lastItem:i]...)
url_len := partial_url_bytes_len(msgbytes[i:])
if msgbytes[i + url_len] != ' ' && msgbytes[i + url_len] != 10 {
outbytes = append(outbytes,invalid_url...)
i += url_len
continue
}
//fmt.Println("Parsed URL:")
//fmt.Println("`"+string(msgbytes[i:i + url_len])+"`")
//fmt.Println("-----")
outbytes = append(outbytes, url_open...)
outbytes = append(outbytes, msgbytes[i:i + url_len]...)
outbytes = append(outbytes, url_open2...)
outbytes = append(outbytes, msgbytes[i:i + url_len]...)
outbytes = append(outbytes, url_close...)
i += url_len
lastItem = i
}
}
if lastItem != i && len(outbytes) != 0 {
//fmt.Println("lastItem:")
//fmt.Println(msgbytes[lastItem])
//fmt.Println("lastItem index:")
//fmt.Println(lastItem)
//fmt.Println("i:")
//fmt.Println(i)
//fmt.Println("lastItem to end:")
//fmt.Println(msgbytes[lastItem:])
//fmt.Println("-----")
calclen := len(msgbytes) - 10
if calclen <= lastItem {
calclen = lastItem
}
outbytes = append(outbytes, msgbytes[lastItem:calclen]...)
msg = string(outbytes)
}
//fmt.Println(`"`+string(outbytes)+`"`)
//fmt.Println(`"`+msg+`"`)
msg = strings.Replace(msg,"\n","<br>",-1)
if hooks["parse_assign"] != nil {
out := run_hook("parse_assign", msg)
msg = out.(string)
}
return msg
}
func regex_parse_message(msg string) string {
msg = strings.Replace(msg,":)","😀",-1)
msg = strings.Replace(msg,":D","😃",-1)
msg = strings.Replace(msg,":P","😛",-1)
@ -155,3 +256,143 @@ func parse_message(msg string) string {
}
return msg
}
// 6, 7, 8, 6, 7
// ftp://, http://, https:// git://, mailto: (not a URL, just here for length comparison purposes)
func validate_url_bytes(data []byte) bool {
datalen := len(data)
i := 0
if datalen >= 6 {
if bytes.Equal(data[0:6],[]byte("ftp://")) || bytes.Equal(data[0:6],[]byte("git://")) {
i = 6
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
i = 7
} else if datalen >= 8 && bytes.Equal(data[0:8],[]byte("https://")) {
i = 8
}
}
for ;datalen > i; i++ {
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
return false
}
}
return true
}
func validated_url_bytes(data []byte) (url []byte) {
datalen := len(data)
i := 0
if datalen >= 6 {
if bytes.Equal(data[0:6],[]byte("ftp://")) || bytes.Equal(data[0:6],[]byte("git://")) {
i = 6
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
i = 7
} else if datalen >= 8 && bytes.Equal(data[0:8],[]byte("https://")) {
i = 8
}
}
for ;datalen > i; i++ {
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
return invalid_url
}
}
url = append(url, data...)
return url
}
func partial_url_bytes(data []byte) (url []byte) {
datalen := len(data)
i := 0
end := datalen - 1
if datalen >= 6 {
if bytes.Equal(data[0:6],[]byte("ftp://")) || bytes.Equal(data[0:6],[]byte("git://")) {
i = 6
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
i = 7
} else if datalen >= 8 && bytes.Equal(data[0:8],[]byte("https://")) {
i = 8
}
}
for ;end >= i; i++ {
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
end = i
}
}
url = append(url, data[0:end]...)
return url
}
func partial_url_bytes_len(data []byte) int {
datalen := len(data)
i := 0
if datalen >= 6 {
//fmt.Println(data[0:5])
//fmt.Println(string(data[0:5]))
if bytes.Equal(data[0:6],[]byte("ftp://")) || bytes.Equal(data[0:6],[]byte("git://")) {
i = 6
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
i = 7
//fmt.Println("http")
} else if datalen >= 8 && bytes.Equal(data[0:8],[]byte("https://")) {
i = 8
} else {
//fmt.Println("no protocol")
}
}
for ;datalen > i; i++ {
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
//fmt.Println("Trimmed Length")
//fmt.Println(i)
//fmt.Println("Full Length")
//fmt.Println(i)
//fmt.Println("Data Length:")
//fmt.Println(datalen)
//fmt.Println("Bad Character:")
//fmt.Println(data[i])
return i
}
}
//fmt.Println("Data Length:")
//fmt.Println(datalen)
return datalen
}
func parse_media_bytes(data []byte) (protocol []byte, url []byte) {
datalen := len(data)
i := 0
if datalen >= 6 {
if bytes.Equal(data[0:6],[]byte("ftp://")) || bytes.Equal(data[0:6],[]byte("git://")) {
i = 6
protocol = data[0:2]
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
i = 7
protocol = []byte("http")
} else if datalen >= 8 && bytes.Equal(data[0:8],[]byte("https://")) {
i = 8
protocol = []byte("https")
}
}
for ;datalen > i; i++ {
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
return []byte(""), invalid_url
}
}
if len(protocol) == 0 {
protocol = []byte("http")
}
return protocol, data[i:]
}

View File

@ -9,13 +9,8 @@ import "time"
import "math/rand"
var random *rand.Rand
var bbcode_invalid_url []byte
var bbcode_invalid_number []byte
var bbcode_missing_tag []byte
var bbcode_url_open []byte
var bbcode_url_open2 []byte
var bbcode_url_close []byte
var bbcode_space_gap []byte
var bbcode_bold *regexp.Regexp
var bbcode_italic *regexp.Regexp
@ -23,6 +18,7 @@ var bbcode_underline *regexp.Regexp
var bbcode_strikethrough *regexp.Regexp
var bbcode_url *regexp.Regexp
var bbcode_url_label *regexp.Regexp
var bbcode_quotes *regexp.Regexp
func init() {
plugins["bbcode"] = NewPlugin("bbcode","BBCode","Azareal","http://github.com/Azareal","","","",init_bbcode,nil,deactivate_bbcode)
@ -32,13 +28,8 @@ func init_bbcode() {
//plugins["bbcode"].AddHook("parse_assign", bbcode_parse_without_code)
plugins["bbcode"].AddHook("parse_assign", bbcode_full_parse)
bbcode_invalid_url = []byte("<span style='color: red;'>[Invalid URL]</span>")
bbcode_invalid_number = []byte("<span style='color: red;'>[Invalid Number]</span>")
bbcode_missing_tag = []byte("<span style='color: red;'>[Missing Tag]</span>")
bbcode_url_open = []byte("<a href='")
bbcode_url_open2 = []byte("'>")
bbcode_url_close = []byte("</a>")
bbcode_space_gap = []byte(" ")
bbcode_bold = regexp.MustCompile(`(?s)\[b\](.*)\[/b\]`)
bbcode_italic = regexp.MustCompile(`(?s)\[i\](.*)\[/i\]`)
@ -47,6 +38,7 @@ func init_bbcode() {
urlpattern := `(http|https|ftp|mailto*)(:??)\/\/([\.a-zA-Z\/]+)`
bbcode_url = regexp.MustCompile(`\[url\]` + urlpattern + `\[/url\]`)
bbcode_url_label = regexp.MustCompile(`(?s)\[url=` + urlpattern + `\](.*)\[/url\]`)
bbcode_quotes = regexp.MustCompile(`\[quote\](.*)\[/quote\]`)
random = rand.New(rand.NewSource(time.Now().UnixNano()))
}
@ -64,6 +56,7 @@ func bbcode_regex_parse(data interface{}) interface{} {
msg = bbcode_strikethrough.ReplaceAllString(msg,"<s>$1</s>")
msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
msg = bbcode_quotes.ReplaceAllString(msg,"<div class=\"postQuote\">$1</div>")
return msg
}
@ -177,6 +170,7 @@ func bbcode_parse_without_code(data interface{}) interface{} {
if complex_bbc {
msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
msg = bbcode_quotes.ReplaceAllString(msg,"<div class=\"postQuote\">$1</div>")
}
return string(msgbytes)
}
@ -184,6 +178,9 @@ func bbcode_parse_without_code(data interface{}) interface{} {
// Does every type of BBCode
func bbcode_full_parse(data interface{}) interface{} {
msg := data.(string)
//fmt.Println("BBCode PrePre String:")
//fmt.Println("`"+msg+"`")
//fmt.Println("----")
msgbytes := []byte(msg)
has_u := false
has_b := false
@ -191,7 +188,10 @@ func bbcode_full_parse(data interface{}) interface{} {
has_s := false
has_c := false
complex_bbc := false
msgbytes = append(msgbytes,bbcode_space_gap...)
msgbytes = append(msgbytes,space_gap...)
//fmt.Println("BBCode Simple Pre:")
//fmt.Println("`"+string(msgbytes)+"`")
//fmt.Println("----")
for i := 0; i < len(msgbytes); i++ {
if msgbytes[i] == '[' {
if msgbytes[i + 2] != ']' {
@ -275,59 +275,36 @@ func bbcode_full_parse(data interface{}) interface{} {
var start int
var lastTag int
outbytes := make([]byte, len(msgbytes))
//fmt.Println(string(msgbytes))
//fmt.Println("BBCode Pre:")
//fmt.Println("`"+string(msgbytes)+"`")
//fmt.Println("----")
for ; i < len(msgbytes); i++ {
MainLoop:
if msgbytes[i] == '[' {
OuterComplex:
if msgbytes[i + 1] == 'u' {
if msgbytes[i+2] == 'r' && msgbytes[i+3] == 'l' && msgbytes[i+4] == ']' {
outbytes = append(outbytes, msgbytes[lastTag:i]...)
start = i + 5
outbytes = append(outbytes, msgbytes[lastTag:i]...)
i = start
if msgbytes[i] == 'h' {
if msgbytes[i+1] == 't' && msgbytes[i+2] == 't' && msgbytes[i+3] == 'p' {
if bytes.Equal(msgbytes[i + 4:i + 7],[]byte("s://")) {
i += 7
} else if msgbytes[i+4] == ':' && msgbytes[i+5] == '/' && msgbytes[i+6] == '/' {
i += 6
} else {
outbytes = append(outbytes, bbcode_invalid_url...)
continue
}
}
} else if msgbytes[i] == 'f' {
if bytes.Equal(msgbytes[i+1:i+5],[]byte("tp://")) {
i += 5
}
}
i += partial_url_bytes_len(msgbytes[start:])
for ;; i++ {
if len(msgbytes) < (i + 10) {
//fmt.Println(msglen)
//fmt.Println(i+6)
outbytes = append(outbytes, bbcode_missing_tag...)
goto OuterComplex
} else if msgbytes[i] == '[' {
if !bytes.Equal(msgbytes[i+1:i+6],[]byte("/url]")) {
//log.Print("Not the URL closing tag!")
//fmt.Println(msgbytes[i + 1:i + 6])
outbytes = append(outbytes, bbcode_missing_tag...)
goto OuterComplex
}
break
} else if msgbytes[i] != '\\' && msgbytes[i] != '_' && !(msgbytes[i] > 44 && msgbytes[i] < 58) && !(msgbytes[i] > 64 && msgbytes[i] < 91) && !(msgbytes[i] > 96 && msgbytes[i] < 123) {
outbytes = append(outbytes, bbcode_invalid_url...)
//log.Print("Weird character")
//fmt.Println(msgbytes[i])
//fmt.Println("Partial Bytes:")
//fmt.Println(string(msgbytes[start:]))
//fmt.Println("-----")
if !bytes.Equal(msgbytes[i:i+6],[]byte("[/url]")) {
//fmt.Println("Invalid Bytes:")
//fmt.Println(string(msgbytes[i:i+6]))
//fmt.Println("-----")
outbytes = append(outbytes, invalid_url...)
goto MainLoop
}
}
outbytes = append(outbytes, bbcode_url_open...)
outbytes = append(outbytes, url_open...)
outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, bbcode_url_open2...)
outbytes = append(outbytes, url_open2...)
outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, bbcode_url_close...)
outbytes = append(outbytes, url_close...)
i += 6
lastTag = i
}
@ -367,15 +344,25 @@ func bbcode_full_parse(data interface{}) interface{} {
//fmt.Println(string(outbytes))
if lastTag != i {
outbytes = append(outbytes, msgbytes[lastTag:]...)
}
if len(outbytes) != 0 {
return string(outbytes[0:len(msgbytes) - 10])
//fmt.Println("Outbytes:")
//fmt.Println(`"`+string(outbytes)+`"`)
//fmt.Println("----")
}
if len(outbytes) != 0 {
//fmt.Println("BBCode Post:")
//fmt.Println(`"`+string(outbytes[0:len(outbytes) - 10])+`"`)
//fmt.Println("----")
msg = string(outbytes[0:len(outbytes) - 10])
} else {
msg = string(msgbytes[0:len(msgbytes) - 10])
}
//msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
msg = bbcode_quotes.ReplaceAllString(msg,"<div class=\"postQuote\">$1</div>")
// Convert [code] into class="codequotes"
//fmt.Println("guuuaaaa")
} else {
msg = string(msgbytes[0:len(msgbytes) - 10])
}

View File

@ -780,7 +780,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
}
_, err = users.CascadeGet(createdBy)
if err != nil && err != sql.ErrNoRows {
if err != nil && err == sql.ErrNoRows {
LocalError("The target user doesn't exist",w,r,user)
return
} else if err != nil {

View File

@ -67,7 +67,7 @@ var topic_8 []byte = []byte(`
<div class="rowblock topic_block">
<form action='/topic/edit/submit/`)
var topic_9 []byte = []byte(`' method="post">
<div class="rowitem topic_item"`)
<div class="rowitem rowhead topic_item"`)
var topic_10 []byte = []byte(` style="background-color:#FFFFEA;"`)
var topic_11 []byte = []byte(` style="background-color:#eaeaea;"`)
var topic_12 []byte = []byte(`>
@ -100,7 +100,7 @@ var topic_24 []byte = []byte(`">
<p class="hide_on_edit topic_content user_content" style="margin:0;padding:0;">`)
var topic_25 []byte = []byte(`</p>
<textarea name="topic_content" class="show_on_edit topic_content_input">`)
var topic_26 []byte = []byte(`</textarea><br /><br />
var topic_26 []byte = []byte(`</textarea>
<a href="/user/`)
var topic_27 []byte = []byte(`" class="username real_username">`)
var topic_28 []byte = []byte(`</a>&nbsp;
@ -126,21 +126,21 @@ var topic_44 []byte = []byte(`<a class="username hide_on_micro" style="float: ri
var topic_45 []byte = []byte(`</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;margin-left:5px;" title="Like Count">😀</a>`)
var topic_46 []byte = []byte(`<a class="username hide_on_micro" style="float:right;color:#505050;font-size:16px;">`)
var topic_47 []byte = []byte(`</a>`)
var topic_48 []byte = []byte(`<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">`)
var topic_48 []byte = []byte(`<a class="username hide_on_micro level">`)
var topic_49 []byte = []byte(`</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;" title="Level">👑</a>`)
var topic_50 []byte = []byte(`
</div>
</div><br />
<div class="rowblock post_container" style="overflow: hidden;">`)
var topic_51 []byte = []byte(`
<div class="rowitem rowhead passive deletable_block editable_parent post_item" style="`)
<div class="rowitem passive deletable_block editable_parent post_item" style="`)
var topic_52 []byte = []byte(`background-image:url(`)
var topic_53 []byte = []byte(`), url(/static/white-dot.jpg);background-position: 0px `)
var topic_54 []byte = []byte(`-1`)
var topic_55 []byte = []byte(`0px;background-repeat:no-repeat, repeat-y;background-size:128px;padding-left:136px;`)
var topic_56 []byte = []byte(`">
<p class="editable_block user_content" style="margin: 0;padding: 0;">`)
var topic_57 []byte = []byte(`</p><br /><br />
var topic_57 []byte = []byte(`</p>
<a href="/user/`)
var topic_58 []byte = []byte(`" class="username real_username">`)
var topic_59 []byte = []byte(`</a>&nbsp;
@ -162,7 +162,7 @@ var topic_71 []byte = []byte(`<a class="username hide_on_micro" style="float: ri
var topic_72 []byte = []byte(`</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;margin-left:5px;" title="Like Count">😀</a>`)
var topic_73 []byte = []byte(`<a class="username hide_on_micro" style="float: right;color:#505050;font-size:16px;">`)
var topic_74 []byte = []byte(`</a>`)
var topic_75 []byte = []byte(`<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">`)
var topic_75 []byte = []byte(`<a class="username hide_on_micro level">`)
var topic_76 []byte = []byte(`</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;" title="Level">👑`)
var topic_77 []byte = []byte(`</a>
</div>

View File

@ -2,10 +2,28 @@
{{template "panel-menu.html" . }}
<style type="text/css">.rowitem::after {content:"";display:block;clear:both;}</style>
<div class="colblock_right">
<div class="rowitem rowhead"><a>Themes</a></div>
<div class="rowitem rowhead"><a>Primary Themes</a></div>
</div>
<div class="colblock_right">
{{range .ItemList}}
{{range .PrimaryThemes}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;{{if .FullImage}}background-image: url('/static/{{.FullImage}}');background-position: center;background-size: 50%;background-repeat: no-repeat;{{end}}">
<span style="float: left;">
<a href="/panel/themes/{{.Name}}" class="editable_block" style="font-size: 20px;">{{.FriendlyName}}</a><br />
<small style="margin-left: 2px;">Author: {{.Creator}}</small>
</span>
<span style="float: right;">
{{if .MobileFriendly}}<span class="username" title="Mobile Friendly">📱</span>{{end}}
{{if .Tag}}<span class="username">{{.Tag}}</span>{{end}}
{{if .Active}}<span class="username">Default</span>{{else}}<a href="/panel/themes/default/{{.Name}}?session={{$.CurrentUser.Session}}" class="username">Make Default</a>{{end}}
</span>
</div>
{{end}}
</div>
<div class="colblock_right">
<div class="rowitem rowhead"><a>Variant Themes</a></div>
</div>
<div class="colblock_right">
{{range .VariantThemes}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;{{if .FullImage}}background-image: url('/static/{{.FullImage}}');background-position: center;background-size: 50%;background-repeat: no-repeat;{{end}}">
<span style="float: left;">
<a href="/panel/themes/{{.Name}}" class="editable_block" style="font-size: 20px;">{{.FriendlyName}}</a><br />

View File

@ -4,7 +4,7 @@
<div id="nextFloat" class="next_button"><a class="next_link" href="/topic/{{.Topic.ID}}?page={{add .Page 1}}">&gt;</a></div>{{end}}
<div class="rowblock topic_block">
<form action='/topic/edit/submit/{{.Topic.ID}}' method="post">
<div class="rowitem topic_item"{{if .Topic.Sticky}} style="background-color:#FFFFEA;"{{else if .Topic.Is_Closed}} style="background-color:#eaeaea;"{{end}}>
<div class="rowitem rowhead topic_item"{{if .Topic.Sticky}} style="background-color:#FFFFEA;"{{else if .Topic.Is_Closed}} style="background-color:#eaeaea;"{{end}}>
<a class='topic_name hide_on_edit'>{{.Topic.Title}}</a>
{{if .Topic.Is_Closed}}<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='Status: Closed' style="font-weight:normal;float: right;position:relative;top:-5px;">&#x1F512;&#xFE0E</span>{{end}}
{{if .CurrentUser.Perms.EditTopic}}
@ -21,7 +21,7 @@
<div class="rowblock post_container">
<div class="rowitem passive editable_parent post_item" style="border-bottom: none;{{if .Topic.Avatar}}background-image:url({{.Topic.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .Topic.ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;background-size:128px;padding-left:136px;{{.Topic.Css}}{{end}}">
<p class="hide_on_edit topic_content user_content" style="margin:0;padding:0;">{{.Topic.Content}}</p>
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea><br /><br />
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea>
<a href="/user/{{.Topic.CreatedBy}}" class="username real_username">{{.Topic.CreatedByName}}</a>&nbsp;
{{if .CurrentUser.Perms.LikeItem}}<a href="/topic/like/submit/{{.Topic.ID}}" class="mod_button" title="Love it" style="color:#202020;"><button class="username" style="{{if .Topic.Liked}}background-color:/*#eaffea*/#D6FFD6;{{end}}">😀</button></a>&nbsp;{{end}}
{{if .CurrentUser.Perms.EditTopic}}<a href='/topic/edit/{{.Topic.ID}}' class="mod_button open_edit" style="font-weight:normal;" title="Edit Topic"><button class="username">🖊️</button></a>&nbsp;{{end}}
@ -29,19 +29,19 @@
{{if .CurrentUser.Perms.PinTopic}}{{if .Topic.Sticky}}<a class="mod_button" href='/topic/unstick/submit/{{.Topic.ID}}' style="font-weight:normal;" title="Unpin Topic"><button class="username" style="background-color:/*#eaffea*/#D6FFD6;">📌</button></a>{{else}}<a href='/topic/stick/submit/{{.Topic.ID}}' class="mod_button" style="font-weight:normal;" title="Pin Topic"><button class="username">📌</button></a>&nbsp;{{end}}{{end}}
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="mod_button report_item" style="font-weight:normal;" title="Flag Topic"><button class="username">🚩</button></a>&nbsp;
{{if .Topic.LikeCount}}<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">{{.Topic.LikeCount}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;margin-left:5px;" title="Like Count">😀</a>{{end}}
{{if .Topic.Tag}}<a class="username hide_on_micro" style="float:right;color:#505050;font-size:16px;">{{.Topic.Tag}}</a>{{else}}<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">{{.Topic.Level}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;" title="Level">👑</a>{{end}}
{{if .Topic.Tag}}<a class="username hide_on_micro" style="float:right;color:#505050;font-size:16px;">{{.Topic.Tag}}</a>{{else}}<a class="username hide_on_micro level">{{.Topic.Level}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;" title="Level">👑</a>{{end}}
</div>
</div><br />
<div class="rowblock post_container" style="overflow: hidden;">{{range .ItemList}}
<div class="rowitem rowhead passive deletable_block editable_parent post_item" style="{{if .Avatar}}background-image:url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;background-size:128px;padding-left:136px;{{.Css}}{{end}}">
<p class="editable_block user_content" style="margin: 0;padding: 0;">{{.ContentHtml}}</p><br /><br />
<div class="rowitem passive deletable_block editable_parent post_item" style="{{if .Avatar}}background-image:url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;background-size:128px;padding-left:136px;{{.Css}}{{end}}">
<p class="editable_block user_content" style="margin: 0;padding: 0;">{{.ContentHtml}}</p>
<a href="/user/{{.CreatedBy}}" class="username real_username">{{.CreatedByName}}</a>&nbsp;
{{if $.CurrentUser.Perms.LikeItem}}<a href="/reply/like/submit/{{.ID}}" class="mod_button" title="Love it" style="color:#202020;"><button class="username" style="{{if .Liked}}background-color:/*#eaffea*/#D6FFD6;{{end}}">😀</button></a>&nbsp;{{end}}
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="mod_button" title="Edit Reply"><button class="username edit_item">🖊️</button></a>&nbsp;{{end}}
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="mod_button" title="Delete Reply"><button class="username delete_item">🗑️</button></a>&nbsp;{{end}}
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="mod_button" title="Flag Reply"><button class="username report_item">🚩</button></a>&nbsp;
{{if .LikeCount}}<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">{{.LikeCount}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;margin-left:5px;" title="Like Count">😀</a>{{end}}
{{if .Tag}}<a class="username hide_on_micro" style="float: right;color:#505050;font-size:16px;">{{.Tag}}</a>{{else}}<a class="username hide_on_micro" style="float: right;color:#505050;border-left:none;padding-left:5px;padding-right:5px;font-size:17px;">{{.Level}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;" title="Level">👑{{end}}</a>
{{if .Tag}}<a class="username hide_on_micro" style="float: right;color:#505050;font-size:16px;">{{.Tag}}</a>{{else}}<a class="username hide_on_micro level">{{.Level}}</a><a class="username hide_on_micro" style="color:#505050;float:right;opacity:0.85;" title="Level">👑{{end}}</a>
</div>
{{end}}</div>
{{if .CurrentUser.Perms.CreateReply}}

View File

@ -27,6 +27,7 @@ type Theme struct
MobileFriendly bool
Disabled bool
HideFromThemes bool
ForkOf string
Tag string
Settings map[string]ThemeSetting
Templates []TemplateMapping

View File

@ -5,7 +5,7 @@
"Creator": "Azareal",
"Disabled": true,
"HideFromThemes": true,
"Tag": "WIP",
"Tag": "🏗️",
"Templates": [
{
"Name": "topic",

View File

@ -450,6 +450,15 @@ button .big { padding: 6px; }*/
font-size: 15px;
}
.postQuote {
padding: 5px;
border: 1px solid rgb(200,200,200);
display: inline-block;
margin-bottom: 5px;
width: 100%;
background: rgb(250,250,250);
}
.threadHidden { background: orange; }
.threadDeleted { background: rgba(255,0,0,0.5); }

View File

@ -4,6 +4,7 @@
"Version": "Coming Soon",
"Creator": "Azareal",
"FullImage": "cosmo-conflux.png",
"ForkOf": "cosmo",
"MobileFriendly": true,
"Templates": [
{

View File

@ -439,6 +439,16 @@ button .big { padding: 6px; }*/
font-size: 15px;
}
.postQuote {
border-radius: 4px;
padding: 5px;
border: 1px solid rgb(200,200,200);
display: inline-block;
margin-bottom: 5px;
width: 100%;
background: rgb(250,250,250);
}
.threadHidden { background: orange; }
.threadDeleted { background: rgba(255,0,0,0.5); }

View File

@ -353,6 +353,19 @@ button.username
position: relative;
top: -0.25px;
}
.postQuote {
border: rgb(200,200,210);
background: rgb(245,245,255);
padding: 3px;
margin: 0px;
display: inline-block;
width: 100%;
margin-bottom: 5px;
border-style: solid;
border-width: 1px;
}
.tag-mini
{
text-transform: none;

View File

@ -0,0 +1,497 @@
* {
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
body
{
font-family: cursive;
padding-bottom: 8px;
}
/* Patch for Edge */
@supports (-ms-ime-align:auto) {
.user_content { font-family: Segoe UI Emoji, arial; }
}
ul
{
padding-left: 0px;
padding-right: 0px;
height: 28px;
list-style-type: none;
border: 1px solid #ccc;
background-color: white;
}
li
{
height: 26px;
padding-left: 10px;
padding-top: 5px;
padding-bottom: 5px;
font-weight: bold;
text-transform: uppercase;
}
li:hover { background: rgb(250,250,250); }
li a
{
text-decoration: none;
color: #515151;
}
/*li a:hover { color: #7a7a7a; }*/
.menu_left
{
float: left;
border-right: 1px solid #ccc;
padding-right: 10px;
font-family: cursive;
padding-top: 2px;
}
.menu_right
{
float: right;
border-left: 1px solid #ccc;
padding-right: 10px;
}
.menu_alerts {
padding-left: 7px;
padding-top: 2px;
color: rgb(80,80,80);
}
.menu_alerts .alert_counter {
position:relative;
font-size: 9px;
top: -24px;
background-color: rgb(140,0,0);
color: white;
padding: 3px;
width: 14px;
left: 10px;
line-height: 8px;
border-radius: 20px;
padding-top: 2.5px;
height: 14px;
opacity: 0.8;
text-align: center;
}
.menu_alerts .alert_counter:empty {
display: none;
}
.selectedAlert {
background: white;
color: black;
}
.selectedAlert:hover {
background: white;
color: black;
}
.menu_alerts .alertList {
display: none;
text-transform: none;
}
.selectedAlert .alertList {
position: absolute;
top: 43px;
display: block;
background: white;
font-size: 10px;
line-height: 16px;
width: 135px;
right: calc(5% + 7px);
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.alertItem {
padding: 8px;
overflow: hidden;
text-overflow: ellipsis;
}
.alertItem.withAvatar {
background-size: auto 56px;
background-repeat: no-repeat;
text-align: right;
padding-right: 12px;
height: 46px;
}
.alertItem.withAvatar:not(:last-child) {
border-bottom: 1px solid rgb(230,230,230);
}
.alertItem.withAvatar .text {
overflow: hidden;
text-overflow: ellipsis;
float: right;
width: calc(100% - 20px);
height: 30px;
}
.container
{
width: 90%;
padding: 0px;
margin-left: auto;
margin-right: auto;
}
.rowblock
{
border: 1px solid #ccc;
width: 100%;
padding: 0px;
padding-top: 0px;
}
.rowblock:empty { display: none; }
.colblock_left
{
border: 1px solid #ccc;
padding: 0px;
padding-top: 0px;
width: 30%;
float: left;
margin-right: 8px;
}
.colblock_right
{
border: 1px solid #ccc;
padding: 0px;
padding-top: 0px;
width: 65%;
overflow: hidden;
word-wrap: break-word;
}
.colblock_left:empty { display: none; }
.colblock_right:empty { display: none; }
.rowhead { font-family: cursive; }
.rowitem
{
width: 100%;
padding-left: 8px;
padding-right: 8px;
padding-top: 17px;
padding-bottom: 12px;
font-weight: bold;
text-transform: uppercase;
background-color: white;
}
.rowitem.passive
{
font-weight: normal;
text-transform: none;
}
.rowitem:not(:last-child)
{
border-bottom: 1px dotted #ccc;
}
.rowitem a
{
text-decoration: none;
color: black;
}
.rowitem a:hover { color: silver; }
.opthead { display: none; }
.col_left
{
width: 30%;
float: left;
}
.col_right
{
width: 69%;
overflow: hidden;
}
.colitem
{
padding-left: 8px;
padding-right: 8px;
padding-top: 17px;
padding-bottom: 12px;
font-weight: bold;
text-transform: uppercase;
}
.colitem.passive
{
font-weight: normal;
text-transform: none;
}
.colitem a
{
text-decoration: none;
color: black;
}
.colitem a:hover { color: silver; }
.formrow
{
width: 100%;
background-color: white;
}
/* Clearfix */
.formrow:before, .formrow:after {
content: " ";
display: table;
}
.formrow:after { clear: both; }
.formrow:not(:last-child)
{
border-bottom: 1px dotted #ccc;
}
.formitem
{
float: left;
padding-left: 8px;
padding-right: 8px;
padding-top: 13px;
padding-bottom: 8px;
font-weight: bold;
}
.formitem:first-child { font-weight: bold; }
.formitem:not(:last-child) { border-right: 1px dotted #ccc; }
.formitem.invisible_border { border: none; }
/* Mostly for textareas */
.formitem:only-child { width: 100%; }
.formitem textarea
{
width: 100%;
height: 100px;
outline-color: #8e8e8e;
}
.formitem:has-child()
{
margin: 0 auto;
float: none;
}
button
{
background: white;
border: 1px solid #8e8e8e;
}
/* Topics */
.topic_status
{
text-transform: none;
margin-left: 8px;
padding-left: 2px;
padding-right: 2px;
padding-top: 2px;
padding-bottom: 2px;
background-color: #E8E8E8; /* 232,232,232. All three RGB colours being the same seems to create a shade of gray */
color: #505050; /* 80,80,80 */
border-radius: 2px;
}
.topic_status:empty { display: none; }
.username
{
text-transform: none;
margin-left: 0px;
padding-left: 0px;
padding-right: 0px;
padding-top: 2px;
padding-bottom: 2px;
color: #505050; /* 80,80,80 */
font-size: 15px;
background: none;
}
button.username
{
position: relative;
top: -0.25px;
}
.username.level { color: #303030; }
.username.real_username { color: #404040; font-size: 17px; padding-right: 4px; }
.username.real_username:hover { color: black; }
.tag-text {
padding-top: 23px;
display: inline-block;
}
.post_item > .username {
padding-top: 23px;
display: inline-block;
}
.tag-mini
{
text-transform: none;
margin-left: 0px;
padding-left: 3px;
padding-right: 3px;
padding-top: 1.5px;
padding-bottom: 0px;
color: #505050; /* 80,80,80 */
background-color: #FFFFFF;
border-style: dotted;
border-color: #505050; /* 232,232,232. All three RGB colours being the same seems to create a shade of gray */
border-width: 1px;
font-size: 10px;
}
.post_item > .mod_button > button {
font-size: 15px;
color: #202020;
opacity: 0.7;
border: none;
}
.post_item > .mod_button > button:hover {
opacity: 0.9;
}
.postQuote {
border: 1px solid #ccc;
background: white;
padding: 3px;
margin: 0px;
display: inline-block;
width: 100%;
margin-bottom: 5px;
}
.level {
float: right;
color: #505050;
border-left: none;
padding-left: 3px;
padding-right: 5px;
font-size: 16px;
}
.show_on_edit { display: none; }
.alert
{
display: block;
padding: 5px;
margin-bottom: 10px;
border: 1px solid #ccc;
}
.alert_success
{
display: block;
padding: 5px;
border: 1px solid A2FC00;
margin-bottom: 10px;
background-color: DAF7A6;
}
.alert_error
{
display: block;
padding: 5px;
border: 1px solid #FF004B;
margin-bottom: 8px;
background-color: #FEB7CC;
}
.prev_button, .next_button {
position: fixed;
top: 50%;
font-size: 30px;
border-width: 1px;
background-color: #FFFFFF;
border-style: dotted;
border-color: #505050;
padding: 0px;
padding-left: 5px;
padding-right: 5px;
z-index: 100;
}
.prev_button a, .next_button a {
line-height: 28px;
margin-top: 2px;
margin-bottom: 0px;
display: block;
text-decoration: none;
color: #505050;
}
.prev_button { left: 14px; }
.next_button { right: 14px; }
@media (max-width: 880px) {
li { height: 25px; font-size: 15px; padding-left: 7px; }
ul { height: 26px; margin-top: 8px; }
.menu_left { padding-right: 7px; }
.menu_right { padding-right: 7px; }
body { padding-left: 4px; padding-right: 4px; margin: 0px !important; width: 100% !important; height: 100% !important; overflow-x: hidden; }
.container { width: auto; }
.selectedAlert .alertList { top: 33px; right: 4px; }
}
@media (max-width: 810px) {
li { font-weight: normal; text-transform: none; }
.rowitem { text-transform: none; }
/*.rowhead { font-family: arial; }
.menu_left { font-family: arial; }*/
body { font-family: arial; }
.level { font-size: 17px; }
}
@media (max-width: 620px) {
li
{
padding-left: 5px;
padding-top: 2px;
padding-bottom: 2px;
height: 23px;
}
ul { height: 24px; }
.menu_left { padding-right: 5px; }
.menu_right { padding-right: 5px; }
.menu_create_topic { display: none;}
.menu_alerts { padding-left: 4px; padding-right: 4px; }
.hide_on_mobile { display: none; }
.prev_button, .next_button { top: auto; bottom: 5px; }
}
@media (max-width: 470px) {
.menu_overview { display: none; }
.menu_profile { display: none; }
.hide_on_micro { display: none; }
.post_container {
overflow: visible !important;
}
.post_item {
background-position: 0px 2px !important;
background-size: 64px 64px !important;
padding-left: 2px !important;
min-height: 96px;
position: relative !important;
}
.post_item > .user_content {
margin-left: 75px !important;
width: 100% !important;
}
.post_item > .mod_button {
float: right !important;
margin-left: 2px !important;
position: relative;
top: -14px;
}
.post_item > .mod_button > button {
opacity: 1;
}
.post_item > .real_username {
position: absolute;
top: 70px;
float: left;
margin-top: -2px;
padding-top: 3px !important;
margin-right: 2px;
width: 60px;
font-size: 15px;
text-align: center;
}
.container { width: 100% !important; }
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

View File

@ -0,0 +1,10 @@
{
"Name": "tempra-cursive",
"FriendlyName": "Tempra Cursive",
"Version": "0.0.1",
"Creator": "Azareal",
"FullImage": "tempra-cursive.png",
"ForkOf": "tempra-simple",
"Tag": "🏗️",
"MobileFriendly": true
}

View File

@ -316,6 +316,12 @@ button.username
.username.level { color: #303030; }
.username.real_username { color: #404040; font-size: 17px; }
.username.real_username:hover { color: black; }
.post_item > .username {
margin-top: 44.2px;
display: inline-block;
}
.tag-mini
{
text-transform: none;
@ -341,6 +347,25 @@ button.username
opacity: 0.9;
}
.postQuote {
border: 1px solid #ccc;
background: white;
padding: 3px;
margin: 0px;
display: inline-block;
width: 100%;
margin-bottom: 5px;
}
.level {
float: right;
color: #505050;
border-left: none;
padding-left: 5px;
padding-right: 5px;
font-size: 17px;
}
.show_on_edit { display: none; }
.alert
{
@ -401,11 +426,7 @@ button.username
}
@media (max-width: 810px) {
li
{
font-weight: normal;
text-transform: none;
}
li { font-weight: normal; text-transform: none; }
.rowitem { text-transform: none; }
}
@ -450,9 +471,7 @@ button.username
position: relative;
top: -14px;
}
.post_item > .mod_button > button {
opacity: 1;
}
.post_item > .mod_button > button { opacity: 1; }
.post_item > .real_username {
position: absolute;
top: 70px;