diff options
| author | pep <yes@peepee.me> | 2020-07-21 20:46:56 +0000 |
|---|---|---|
| committer | pep <yes@peepee.me> | 2020-07-21 20:46:56 +0000 |
| commit | 97bee7fe1a48acb4c34e207863af56894c198151 (patch) | |
| tree | 7a03bacd383319f2e4af70beb57ff0f9ae31b010 | |
| parent | d93c099733afff27fbf7c172a40eca87519d38b7 (diff) | |
| parent | 8a3178339ad407ec85ef0cd014a6ad13bfb4cadd (diff) | |
attempt at merge
| -rw-r--r-- | bucky/app/api.js | 25 | ||||
| -rw-r--r-- | bucky/app/bucky.js | 64 | ||||
| -rw-r--r-- | bucky/app/pages.js | 11 | ||||
| -rw-r--r-- | bucky/db/index.js | 36 | ||||
| -rw-r--r-- | fortune/titles | 25 | ||||
| -rw-r--r-- | package.json | 3 | ||||
| -rw-r--r-- | public/assets/css/bucky.css | 79 | ||||
| -rw-r--r-- | public/assets/js/lib/router.js | 14 | ||||
| -rw-r--r-- | public/assets/js/lib/views/details/comments.js | 8 | ||||
| -rw-r--r-- | public/assets/js/lib/views/details/files.js | 5 | ||||
| -rw-r--r-- | public/assets/js/lib/views/keywords/keywords.js | 13 | ||||
| -rw-r--r-- | public/assets/js/lib/views/users/users.js | 88 | ||||
| -rw-r--r-- | public/assets/js/util/color.js | 16 | ||||
| -rw-r--r-- | public/assets/js/util/format.js | 57 | ||||
| -rw-r--r-- | sdk/auth.js | 1 | ||||
| -rw-r--r-- | sdk/index.js | 28 | ||||
| -rw-r--r-- | views/pages/keywords.ejs | 12 | ||||
| -rw-r--r-- | views/pages/users.ejs | 139 | ||||
| -rw-r--r-- | views/partials/hootbox.ejs | 2 | ||||
| -rw-r--r-- | views/partials/scripts.ejs | 2 | ||||
| -rw-r--r-- | views/partials/threads.ejs | 1 |
21 files changed, 584 insertions, 45 deletions
diff --git a/bucky/app/api.js b/bucky/app/api.js index 75cdbd7..d2472c3 100644 --- a/bucky/app/api.js +++ b/bucky/app/api.js @@ -34,6 +34,19 @@ function route (app){ function(req, res){ res.json(util.sanitizeUser(res.user)) }) + app.get("/api/users", + middleware.ensureAuthenticated, + bucky.ensureUserlist, + bucky.ensureUserThreadCounts, + bucky.ensureUserFileCounts, + bucky.ensureUserCommentCounts, + bucky.ensureUserStatistics, + function(req, res) { + res.json({ + users: res.users, + userStats: res.userStats, + }) + }) app.get("/api/profile/:username", middleware.ensureAuthenticated, bucky.ensureUser, @@ -153,6 +166,16 @@ function route (app){ function(req, res){ res.send({ status: 'ok' }) }) + app.get("/api/thread/:id/bury", + middleware.ensureAuthenticated, + bucky.ensureThread, + privacy.checkThreadPrivacy, + bucky.buryThread, + function(req, res){ + res.json({ + thread: res.thread, + }) + }) /* comments */ @@ -259,9 +282,11 @@ function route (app){ middleware.ensureAuthenticated, bucky.ensureKeywords, bucky.ensureThreadGroups, + bucky.ensureLatestKeywordThreads, function(req, res){ res.json({ keywords: res.keywords, + threads: res.threads, threadGroups: res.threadGroups, }) }) diff --git a/bucky/app/bucky.js b/bucky/app/bucky.js index 8d9839f..ab153f9 100644 --- a/bucky/app/bucky.js +++ b/bucky/app/bucky.js @@ -227,6 +227,10 @@ var bucky = module.exports = { next() }) }, + buryThread: function (req, res, next){ + res.thread.set('lastmodified', util.now() - (14 * 86400)) + res.thread.save().then( () => next() ) + }, // ensureInterestedUsers: function(req, res, next){ // // given a thread, find people who might be interested in it // // - other people who have been in threads with you @@ -296,6 +300,12 @@ var bucky = module.exports = { next() }) }, + ensureLatestKeywordThreads: function (req, res, next){ + db.getLatestKeywordThreads().then(function(threads){ + res.threads = threads + next() + }) + }, ensureThreadGroups: function (req, res, next){ db.getThreadGroups().then(function(threadGroups){ res.threadGroups = threadGroups @@ -571,6 +581,60 @@ var bucky = module.exports = { } }) }, + ensureUserlist: function (req, res, next){ + db.getUsers().then(function(users){ + if (! users) { + return res.sendStatus(404) + } + res.users = users + next() + }) + }, + ensureUserThreadCounts: function (req, res, next) { + db.getUserThreadCounts().then(function(counts){ + if (!counts) { + return res.sendStatus(404) + } + res.threadCounts = counts + next() + }) + }, + ensureUserCommentCounts: function (req, res, next) { + db.getUserCommentCounts().then(function(counts){ + if (!counts) { + return res.sendStatus(404) + } + res.commentCounts = counts + next() + }) + }, + ensureUserFileCounts: function (req, res, next) { + db.getUserFileCounts().then(function(counts){ + if (!counts) { + return res.sendStatus(404) + } + res.fileCounts = counts + next() + }) + }, + ensureUserStatistics: function (req, res, next) { + var stats = {} + res.threadCounts.forEach(function(user){ + stats[user.username] = stats[user.username] || {} + stats[user.username].threads = user.count + }) + res.commentCounts.forEach(function(user){ + stats[user.username] = stats[user.username] || {} + stats[user.username].comments = user.count + }) + res.fileCounts.forEach(function(user){ + stats[user.username] = stats[user.username] || {} + stats[user.username].files = user.count + stats[user.username].fileSize = user.size + }) + res.userStats = stats + next() + }, sanitizeUser: function(req, res, next) { res.user = util.sanitizeUser(res.user) next() diff --git a/bucky/app/pages.js b/bucky/app/pages.js index 7f666be..5d8551e 100644 --- a/bucky/app/pages.js +++ b/bucky/app/pages.js @@ -73,6 +73,17 @@ function route (app){ res.render("pages/profile_form", {title: "edit your profile"}) }) + app.get("/users", + middleware.ensureAuthenticated, + function(req, res){ + res.render("pages/users", {}) + }) + app.get("/users/all", + middleware.ensureAuthenticated, + function(req, res){ + res.render("pages/users", {}) + }) + app.get("/search/", middleware.ensureAuthenticated, function(req, res){ diff --git a/bucky/db/index.js b/bucky/db/index.js index f454c92..312ca13 100644 --- a/bucky/db/index.js +++ b/bucky/db/index.js @@ -55,8 +55,13 @@ db.createUser = function(data){ } db.getUsers = function () { return User.query(function(qb){ - qb.orderBy("id", "desc") - }).fetchAll() + qb.orderBy("username", "asc") + }).fetchAll({ + columns: [ + "id", "username", "realname", "firstseen", "lastseen", + "location", "website", "avatar", + ] + }) } db.getUser = function(id) { var model = new User({'id': id}) @@ -143,6 +148,15 @@ db.getThreadUsers = function(thread_id){ db.getUserThreadIds = function(user_id){ return ThreadUser.query("where", "user_id", "=", user_id).fetch() } +db.getUserThreadCounts = function(ids){ + return knex.column('username').count('* as count').select().from('threads').groupBy('username') +} +db.getUserCommentCounts = function(ids){ + return knex.column('username').count('* as count').select().from('comments').groupBy('username') +} +db.getUserFileCounts = function(ids){ + return knex.column('username').sum('size as size').count('* as count').select().from('files').groupBy('username') +} /* FILES */ @@ -281,8 +295,24 @@ db.getKeyword = function (keyword) { return Keyword.query("where", "keyword", "=", keyword).fetch() } db.getThreadGroups = function (keyword) { - return knex.column('keyword').sum('viewed').as('viewed').count('*').as('count').column('id').column('title').column('lastmodified').column('privacy').select().from('threads').groupBy('keyword') + return ( + knex.column('keyword') + .sum('viewed').as('viewed') + .count('*').as('count') + .select().from('threads').groupBy('keyword') + ) +} +db.getLatestKeywordThreads = function (keyword) { + var ids = knex('threads').max('id').groupBy('keyword') + return ( + knex.select('id', 'keyword', 'title', 'lastmodified', 'privacy').from('threads').where('id', 'in', ids) + ) } + // .column('id') + // .column('title') + // .column('lastmodified') + // .column('privacy') + db.createKeyword = function(data){ return new db.Keyword(data).save() } diff --git a/fortune/titles b/fortune/titles index 1a68d5e..d682a14 100644 --- a/fortune/titles +++ b/fortune/titles @@ -397,8 +397,31 @@ bucky pulls up the traps bucky casts the line bucky leaps from the high rock bucky crisps up some smores -bucky's raw vegan rhapsody +bucky's vegan rhapsody bucky's new attitude bucky has so many ideas bucky welcomes you bucky's friends forever +bucky's pedal board +bucky layers the chorus +bucky hides in tall grass +bucky tweaks the filter +bucky's no scope melee +bucky fills the table +bucky's cable salad +enough detune on there, bucky? +bucky tweezes the filter +bucky opens the hat +bucky rides the cymbal +bucky's midi masterpiece +bucky solders the pots +bucky's intricate drum line +bucky's reverse polyphony +bucky shreds in 7/8 +bucky's vegan delicacies +bucky's raw delight +bucky commmunicates with lobsters +bucky's snake adventure +bucky accounts for bloom +bucky's attack release +bucky refuses to wing it diff --git a/package.json b/package.json index 0ff9faf..97e5b9f 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ "berkeleydb": "^0.2.1", "body-parser": "^1.19.0", "bookshelf": "^0.13.3", - "connect-mongo": "^2.0.3", "connect-redis": "^5.0.0", "cookie-parser": "^1.4.4", "csurf": "^1.10.0", @@ -35,7 +34,6 @@ "knox": "^0.9.2", "lodash": "^4.17.15", "mock-express": "^1.3.0", - "mongodb": "^2.2.36", "multer": "^1.4.2", "multiparty": "^4.2.1", "mysql2": "^0.15.8", @@ -44,6 +42,7 @@ "passport": "^0.3.0", "passport-local": "^1.0.0", "redis": "^3.0.2", + "pm2": "^3.5.1", "serve-favicon": "^2.5.0", "sessionstore": "^1.3.5", "skipper": "^0.8.7", diff --git a/public/assets/css/bucky.css b/public/assets/css/bucky.css index 9c9aa8a..bc35ddd 100644 --- a/public/assets/css/bucky.css +++ b/public/assets/css/bucky.css @@ -7,6 +7,7 @@ html { min-height: 100%; margin: 0; padding: 0; + margin-bottom: 150px; } body { min-width: 100%; @@ -17,7 +18,7 @@ body { font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif; margin: 0; - padding: 20px 30px 200px 30px; + padding: 20px 30px 30px 30px; transition: opacity 100ms; } body.loading { @@ -507,6 +508,15 @@ code br, pre br { display: none; } +tt, kbd { + max-width: 580px; + display: inline-block; + font-family: Menlo, monospace; + background: #fefefe; + border: 1px solid #ddd; + padding: 2px; + font-size: 11px; +} #thread_form form { width: 530px; @@ -1244,3 +1254,70 @@ audio { padding-right: 2px; } } +@media (prefers-color-scheme: dark) { + body { + background: #180808; + color: #f8f8f8; + } + button:not(.hoot), input[type=submit] { + color: #f8f8f8; + border: 2px #eee solid; + padding: 2px; + margin: 3px; + background-color: #18202c; + text-transform: uppercase; + cursor: pointer; + } + .desktop button:not(.hoot):hover, + .desktop input[type=submit] { + color: #fff; + background-color: #28303c; + } + hr { + border-color: #fff; + } + a.headline:link, + a.headline:visited { color: #eee; text-decoration: none; } + .desktop a.headline:hover { color: #fff; text-decoration: none; } + .ledger .row td:nth-child(1) a { color: #ddd; } + #threads .keyword td a { color: #ddd; text-decoration: none; } + .desktop #threads .keyword td a:hover { color: #fff; text-decoration: underline; } + #threads .keyword td b a { color: #ddd; } + .desktop #threads .keyword td b a:hover { color: #fff; } + .subtitle a { color: #eee; text-decoration: none; } + .desktop.subtitle a:hover { color: #fff; text-decoration: underline; } + .ledger .new { color: #ffffff; font-weight: bold; } + .ledger .recent { color: #f8f0f0; } + .ledger .med { color: #e8e0e0; } + .ledger .old { color: #d8d0d0; } + .ledger .older { color: #b8b0b0; } + .ledger .quiet { color: #a7a4a4; } + + .files .new { color: #000000; } + .files .recent { color: #001111; } + .files .med { color: #203838; } + .files .old { color: #425050; } + .files .older { color: #5D6464; } + .files .quiet { color: #787878; } + .files .total a { color: #fff; } + + .bluebox { box-shadow: 0 0px 1.5px rgba(238,238,255,1.0), 0 0px 1.5px rgba(238,238,255,1.0); } + .search_form input[type='text']:focus { + border-bottom-color: #888; + } + .search_form input[type='text']:invalid { + caret-color: #888; + } + #comment_form textarea.empty { + border-bottom-color: #fff; + } + #comment_form textarea.empty::placeholder { + color: #fff; + } + #search { + color: #eee; + } + #search b { + color: #fff; + } +} diff --git a/public/assets/js/lib/router.js b/public/assets/js/lib/router.js index b6eff73..ebdfa78 100644 --- a/public/assets/js/lib/router.js +++ b/public/assets/js/lib/router.js @@ -22,7 +22,9 @@ var SiteRouter = Router.extend({ "/mail/compose/:username": 'compose', "/mail/read/:id": 'message', "/mail/reply/:id": 'compose', - "/profile": 'profile', + "/users": 'users', + "/users/all": 'usersAll', + "/profile": 'profile', "/profile/:username": 'profile', "/profile/:username/edit": 'editProfile', "/adminz": 'adminz', @@ -85,6 +87,16 @@ var SiteRouter = Router.extend({ app.view.load(keyword || "") }, + users: function(username){ + app.view = new UsersView () + app.view.load() + }, + + usersAll: function(username){ + app.view = new UsersView ({ all: true }) + app.view.load() + }, + profile: function(username){ app.view = new ProfileView () app.view.load(username || auth.user.username) diff --git a/public/assets/js/lib/views/details/comments.js b/public/assets/js/lib/views/details/comments.js index b1c86bb..1e8d127 100644 --- a/public/assets/js/lib/views/details/comments.js +++ b/public/assets/js/lib/views/details/comments.js @@ -14,8 +14,8 @@ var CommentsView = FormView.extend({ this.$formRow = this.$("#comment_form") }, - load: function(comments, thread){ -console.log(comments) + load: function(comments, thread) { + // console.log(comments) thread = this.thread = thread || this.thread if (thread.settings.hootbox) { comments @@ -35,13 +35,13 @@ console.log(comments) } }, - parse: function(comment){ + parse: function(comment) { if (! comment.comment.length) return $('') var datetime = verbose_date(comment.date, true) var t = this.template.replace(/{{image}}/g, profile_image(comment.username)) .replace(/{{username}}/g, comment.username) .replace(/{{id}}/g, comment.id) - .replace(/{{comment}}/g, tidy_urls(comment.comment)) + .replace(/{{comment}}/g, function(){ return tidy_urls(comment.comment) }) .replace(/{{date}}/g, datetime[0]) .replace(/{{time}}/g, datetime[1]) var $t = $(t) diff --git a/public/assets/js/lib/views/details/files.js b/public/assets/js/lib/views/details/files.js index 44c65c4..98b9350 100644 --- a/public/assets/js/lib/views/details/files.js +++ b/public/assets/js/lib/views/details/files.js @@ -171,10 +171,15 @@ var FilesView = FormView.extend({ if (dateClass && this.reverse) { dateClass += ' italic' } + var sizeClass = this.sort === 'size' ? 'bold' : '' + if (sizeClass && this.reverse) { + sizeClass += ' italic' + } var t = this.templateTotal.replace(/{{size_class}}/g, size[0]) .replace(/{{size}}/g, size[1]) .replace(/{{nameClass}}/g, nameClass) .replace(/{{dateClass}}/g, dateClass) + .replace(/{{sizeClass}}/g, sizeClass) this.$el.append(t) }, diff --git a/public/assets/js/lib/views/keywords/keywords.js b/public/assets/js/lib/views/keywords/keywords.js index 12bd5a8..c5a9491 100644 --- a/public/assets/js/lib/views/keywords/keywords.js +++ b/public/assets/js/lib/views/keywords/keywords.js @@ -19,16 +19,21 @@ var KeywordsView = View.extend({ populate: function(data){ // console.log(data) var keywordThreads = {} - data.threadGroups.forEach(kw => { + var keywordStats = {} + data.threads.forEach(kw => { keywordThreads[kw.keyword] = kw }) + data.threadGroups.forEach(kw => { + keywordStats[kw.keyword] = kw + }) data.keywords .map(a => [parseInt((keywordThreads[a.keyword] || {})['sum(`viewed`)']) || 0, a]) .sort((b,a) => cmp(a[0], b[0])) .map(a => a[1]) .forEach(keyword => { var thread = keywordThreads[keyword.keyword.toLowerCase()] || { - title: '', + } + var stats = keywordStats[keyword.keyword.toLowerCase()] || { } // { // keyword: "warez", @@ -38,9 +43,9 @@ var KeywordsView = View.extend({ // lastmodified: 1192401724 // }, // console.log(keyword, thread) - var viewed = thread['sum(`viewed`)'] + var viewed = stats['sum(`viewed`)'] var views = viewed ? hush_views(viewed) : ['',''] - var threadCountNum = thread['count(*)'] + var threadCountNum = stats['count(*)'] var threadCount = threadCountNum ? hush_threads(threadCountNum) : ['',''] var dot = privacy_dot(thread.privacy) var datetime = verbose_date(keyword.createdate) diff --git a/public/assets/js/lib/views/users/users.js b/public/assets/js/lib/views/users/users.js new file mode 100644 index 0000000..b7e6450 --- /dev/null +++ b/public/assets/js/lib/views/users/users.js @@ -0,0 +1,88 @@ +var UsersView = View.extend({ + + el: "#user_list", + + events: { + }, + + action: "/api/users", + + initialize: function(opt){ + opt = opt || {} + this.showAll = !!opt.all + this.template = this.$(".template").html() + this.form = new NewKeywordForm ({ parent: this }) + if (!this.showAll) { + $('.all_link').attr('href', '/users/all').html('Show all users') + } else { + $('.all_link').attr('href', '/users').html('Show active users') + } + }, + + load: function(){ + $.get(this.action, this.populate.bind(this)) + }, + + populate: function(data){ + console.log(data) + // var keywordThreads = {} + // data.threadGroups.forEach(kw => { + // keywordThreads[kw.keyword] = kw + // }) + var showAll = this.showAll + var userStats = data.userStats + data.users + // .map(a => [parseInt((keywordThreads[a.keyword] || {})['sum(`viewed`)']) || 0, a]) + // .sort((b,a) => cmp(a[0], b[0])) + // .map(a => a[1]) + .map(user => { + // var user = users[user.username.toLowerCase()] || return + // var viewed = thread['sum(`viewed`)'] + // var views = viewed ? hush_views(viewed) : ['',''] + // var threadCountNum = thread['count(*)'] + // var threadCount = threadCountNum ? hush_threads(threadCountNum) : ['',''] + // "id", "username", "realname", "firstseen", "lastseen", + // "location", "website", "avatar", + var stats = userStats[user.username] || {} + if (!showAll && !stats.threads && !stats.files && !stats.comments) { + return + } + var threadCount = stats.threads ? hush_threads(stats.threads) : ['',''] + var fileCount = stats.files ? hush_null(stats.files, 'f') : ['',''] + var fileSize = stats.files ? hush_size(stats.fileSize) : ['',''] + var commentCount = stats.comments ? hush_null(stats.comments, 'c') : ['',''] + var firstseen_datetime = verbose_date(user.firstseen) + var lastseen = get_age(user.lastseen, true) + var avatar = profile_image(user.username) + var t = this.template + .replace(/{{username}}/g, sanitizeHTML(user.username)) + .replace(/{{id}}/g, user.id) + .replace(/{{avatar}}/g, user.avatar) + .replace(/{{location}}/g, sanitizeHTML(user.location)) + .replace(/{{realname}}/g, sanitizeHTML(user.realname)) + .replace(/{{firstseen_date}}/g, firstseen_datetime[0]) + .replace(/{{firstseen_time}}/g, firstseen_datetime[1]) + .replace(/{{firstseen_date_class}}/g, carbon_date(user.firstseen) ) + .replace(/{{lastseen}}/g, lastseen ) + .replace(/{{lastseen_date_class}}/g, carbon_date(lastseen) ) + .replace(/{{threadcount}}/, threadCount[1]) + .replace(/{{threadcount_class}}/, threadCount[0]) + .replace(/{{filecount}}/, fileCount[1]) + .replace(/{{filecount_class}}/, fileCount[0]) + .replace(/{{filesize}}/, fileSize[1]) + .replace(/{{filesize_class}}/, fileSize[0]) + .replace(/{{commentcount}}/, commentCount[1]) + .replace(/{{commentcount_class}}/, commentCount[0]) + var $t = $(t) + if (!user.firstseen) { + $t.find('.date').html('') + } + // if (!user.avatar) { + // $t.find('.avatar').addClass('hidden') + // } + this.$el.append($t) + }) + $("body").removeClass('loading') + }, + +}) diff --git a/public/assets/js/util/color.js b/public/assets/js/util/color.js index 6d33a72..ec21925 100644 --- a/public/assets/js/util/color.js +++ b/public/assets/js/util/color.js @@ -65,6 +65,19 @@ var COLORS = { black: new Color(32,32,37), } +var DARK_COLORS = { + plain: new Color(24,10,10), + ivory: new Color(18,18,18), + pink: new Color(40,23,35), + red: new Color(40,24,23), + orange: new Color(40,32,23), + yellow: new Color(40,40,31), + green: new Color(33,40,31), + blue: new Color(24,26,40), + purple: new Color(35,31,40), + black: new Color(0,0,0), +} + function nighttime_quotient() { var q = -10; var date = new Date() @@ -111,7 +124,8 @@ function set_background_color_from_time(){ } function set_background_color(color_name){ color_name = color_name || "plain" - var color = COLORS[color_name] + var color_set = window.matchMedia('(prefers-color-scheme: dark)').matches ? DARK_COLORS : COLORS + var color = color_set[color_name] .clone() .mottleRGB(4,4,8) // .add(nighttime_quotient()) diff --git a/public/assets/js/util/format.js b/public/assets/js/util/format.js index b04c056..d868ddd 100644 --- a/public/assets/js/util/format.js +++ b/public/assets/js/util/format.js @@ -23,19 +23,20 @@ function querystring(opt){ }).join("&") } function commatize (n, radix) { - radix = radix || 1024 + radix = radix || 1000 var nums = [], i, counter = 0, r = Math.floor - if (n > radix) { + if (radix !== -1 && n > radix) { n /= radix nums.unshift(r((n * 10) % 10)) nums.unshift(".") } do { - i = n % 10 + i = r(n % 10) n = r(n / 10) - if (n && ! (++counter % 3)) + counter += 1 + if (n && ! (counter % 3)) { i = ' ' + r(i) } - nums.unshift(r(i)) + nums.unshift(i) } while (n) return nums.join("") @@ -102,14 +103,14 @@ function hush_views (n, bias, no_bold) { n = n || 0 if (n < 30) { return["quiet", n + " v."] } if (n < 200) { return ["quiet", txt + " v."] } - else if (n < 500) { return ["quiet", txt + " v."] } - else if (n < 1000) { return ["old", txt + " v."] } - else if (n < 5000) { return ["med", txt + " kv."] } + else if (n < 500) { return ["old", txt + " v."] } + else if (n < 1000) { return ["med", txt + " v."] } + else if (n < 5000) { return ["recent", txt + " kv."] } else if (no_bold || n < 10000) { return ["recent", txt + " kv."] } else { return ["new", txt + " kv."] } } function hush_threads (n, bias, no_bold) { - var txt = commatize(n, 1000) + var txt = commatize(n, -1) bias = bias || 1 n = n || 0 if (n < 10) { return["quiet", n + " t."] } @@ -120,33 +121,37 @@ function hush_threads (n, bias, no_bold) { } function hush_size (n, bias, no_bold) { - var txt = commatize(Math.floor(n / 1024)) + var txt = commatize(Math.floor(n / 1024), 1000) bias = 1 || bias n = n || 0 if (n < 1024) { return ["quiet", n + " b."] } - if (n < 1024*1024) { + if (n < 1000*1000) { return ["quiet", txt + " kb."] } - else if (n < (20000000/bias)) { + if (n < (20000000/bias)) { return ["quiet", txt + " mb."] } - else if (n < (50000000/bias)) { + if (n < (50000000/bias)) { return ["old", txt + " mb."] } - else if (n < (80000000/bias)) { + if (n < (80000000/bias)) { return ["med", txt + " mb."] } - else if (no_bold || n < (170000000/bias)) { + if (no_bold || n < (170000000/bias)) { return ["recent", txt + " mb."] } - else { - return ["new", txt + " mb."] + if (n >= 10000*1000*1000) { + console.log(n) + txt = commatize(Math.floor(n / (1024 * 1024 * 1024))) + return ["new", txt + " gb."] } + return ["new", txt + " mb."] } function hush_null (n, unit, no_bold) { + n = commatize(n, -1) var s = unit ? n + " " + unit + "." : n if (n < 3) { return ["quiet", s] @@ -185,26 +190,26 @@ function get_revision (thread) { return digits } -function get_age (t) { +function get_age (t, long) { var age = Math.abs( Date.now()/1000 - t) var r = Math.floor var m if (age < 5) { return "now" } - if (age < 60) { return r(age) + "s" } + if (age < 60) { return r(age) + (long ? ' seconds' : "s") } age /= 60 - if (age < 60) { return r(age) + "m" } + if (age < 60) { return r(age) + (long ? ' minutes' : "m") } m = r(age % 60) age /= 60 - if (m > 0 && age < 2) { return r(age) + "h" + m + "m" } - if (age < 24) { return r(age) + "h" } + if (m > 0 && age < 2) { return r(age) + (long ? ' hours ' + m + ' minutes' : "h" + m + "m") } + if (age < 24) { return r(age) + (long ? ' hours' : "h") } age /= 24 - if (age < 7) { return r(age) + "d" } + if (age < 7) { return r(age) + (long ? ' days' : "d") } age /= 7 - if (age < 12) { return r(age) + "w" } + if (age < 12) { return r(age) + (long ? ' weeks' : "w") } age /= 4 - if (age < 12) { return r(age) + "m" } + if (age < 12) { return r(age) + (long ? ' months' : "m") } age /= 12 - return r(age) + "y" + return r(age) + (long ? ' years' : "y") } function tidy_urls (s, short_urls) { diff --git a/sdk/auth.js b/sdk/auth.js new file mode 100644 index 0000000..72d38f1 --- /dev/null +++ b/sdk/auth.js @@ -0,0 +1 @@ +auth.js
\ No newline at end of file diff --git a/sdk/index.js b/sdk/index.js new file mode 100644 index 0000000..0c92f0c --- /dev/null +++ b/sdk/index.js @@ -0,0 +1,28 @@ +// bucky 3.0.0 sdk + +let env = 'development' +let endpoint = 'http://localhost:5000/' + +export function init(opt){ + env = opt.env || env + endpoint = opt.endpoint || endpoint + + switch (env) { + case 'test': + break + default: + case 'development': + break + case 'production': + break + } +} + +export function path(api){ + return endpoint + api +} + +export function image(file, size){ + return "https://" + sdk.opt.s3.bucket + sdk.opt.s3.path + "/data/" + file.thread + "/" + file.id +} + diff --git a/views/pages/keywords.ejs b/views/pages/keywords.ejs index 89f44a2..9a1f90a 100644 --- a/views/pages/keywords.ejs +++ b/views/pages/keywords.ejs @@ -1,6 +1,16 @@ <% include ../partials/header %> -<div class="subtitle"></div> +<div class="subtitle"> + <a href="/">< Home</a> + · + <a href="/keywords">Keywords</a> + · + <a href="/users">Users</a> + · + <a href="/inbox">Inbox</a> + · + <a href="/profile">Profile</a> +</div> <div id="content"> <div id="keyword_list"> diff --git a/views/pages/users.ejs b/views/pages/users.ejs new file mode 100644 index 0000000..7c8f417 --- /dev/null +++ b/views/pages/users.ejs @@ -0,0 +1,139 @@ +<% include ../partials/header %> + +<div class="subtitle"> + <a href="/">< Home</a> + · + <a href="/keywords">Keywords</a> + · + <a href="/users">Users</a> + · + <a href="/inbox">Inbox</a> + · + <a href="/profile">Profile</a> + ·:· + <a class='all_link'></a> +</div> + +<div id="content"> + <div id="user_list" class="ledger"> + <script type="text/html" class="template"> + <div class="user_main_row"> + <div><a href="/profile/{{username}}" class="avatar" style="background-image:url({{avatar}})"></a></div> + <div> + <div class="user_row"> + <div class="username"><a href="/profile/{{username}}">{{username}}</a></div> + <div class='realname'> + {{realname}} + </div> + <div class="count {{threadcount_class}}"> + {{threadcount}} + </div> + <div class="count {{commentcount_class}}"> + {{commentcount}} + </div> + <div class="count {{filecount_class}}"> + {{filecount}} + </div> + <div class="size {{filesize_class}}"> + {{filesize}} + </div> + </div> + <div class="user_sub_row"> + <div class="location"> + {{location}} + </div> + <div class="date {{lastseen_date_class}}"> + seen {{lastseen}} ago + </div> + <div class="date {{firstseen_date_class}}"> + joined {{firstseen_date}} <small>{{firstseen_time}}</small> + </div> + </div> + </div> + </div> + </script> + </div> +</div> + +<% include ../partials/footer %> + +<style> +.user_main_row { + display: flex; + flex-flow: row; + margin-bottom: 10px; +} +.user_row { + display: flex; + flex-flow: row wrap; + align-items: center; + margin-top: 10px; +} +.user_sub_row { + padding-left: 110px; +} +.user_sub_row div { + margin-top: 5px; +} +.user_main_row .avatar { + display: block; + width: 40px; + height: 40px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} +.user_main_row .avatar.hidden { + opacity: 0; + height: 0; +} +.user_row .username { + min-width: 100px; + margin-left: 10px; +} +.user_row .username a { + font-size: 12px; + font-weight: bold; + display: block; + text-align: right; + margin-right: 5px; + margin-top: -3px; +} +@media (prefers-color-scheme: dark) { + .user_row .username a { + color: #fff; + } +} +.user_row .realname { + min-width: 150px; +} +.user_row .location { + min-width: 150px; +} +.user_row .date { + min-width: 160px; +} +.user_row div { + display: flex; +} +.user_row .dot { + margin-right: 5px; +} +.user_row .date small { + font-size: 9px; + margin-left: 3px; +} +.user_row .views { + min-width: 40px; + justify-content: center; +} +.user_row .count { + min-width: 50px; + justify-content: flex-end; + margin-right: 10px; +} +.user_row .size { + min-width: 60px; + justify-content: flex-end; +} +</style> diff --git a/views/partials/hootbox.ejs b/views/partials/hootbox.ejs index fe0298b..826b89a 100644 --- a/views/partials/hootbox.ejs +++ b/views/partials/hootbox.ejs @@ -1,7 +1,7 @@ <div class="bluebox" id="hootbox"> <form autocomplete="off"> <input type="text" name="comment" autocomplete="off"> - <button><%= hoot_text %></button> + <button class="hoot"><%= hoot_text %></button> <div class="errors"></div> </form> <table id="hoots"> diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 7a8e8da..ce606f8 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -37,6 +37,8 @@ <script src="/assets/js/lib/views/profile/profile.js"></script> <script src="/assets/js/lib/views/profile/profile_edit.js"></script> +<script src="/assets/js/lib/views/users/users.js"></script> + <script src="/assets/js/lib/views/details/details.js"></script> <script src="/assets/js/lib/views/details/settings.js"></script> <script src="/assets/js/lib/views/details/comments.js"></script> diff --git a/views/partials/threads.ejs b/views/partials/threads.ejs index bf065f5..a5f5bee 100644 --- a/views/partials/threads.ejs +++ b/views/partials/threads.ejs @@ -9,6 +9,7 @@ <td colspan="4"> <a href="/post/">Start a new thread!</a> | <a href="/keywords">Keywords</a> | + <a href="/users">Users</a> | <a href="/mail">Inbox</a> | <a href="/profile">Profile</a> | <a href="/logout" class="logout">Logout</a> |
