diff --git a/src/api/lib.zig b/src/api/lib.zig index 00a16eb..e145fba 100644 --- a/src/api/lib.zig +++ b/src/api/lib.zig @@ -5,6 +5,8 @@ const sql = @import("sql"); const DateTime = util.DateTime; const Uuid = util.Uuid; +const default_avatar = "static/default_avi.png"; + const services = struct { const communities = @import("./services/communities.zig"); const actors = @import("./services/actors.zig"); @@ -52,7 +54,10 @@ pub const UserResponse = struct { bio: []const u8, avatar_file_id: ?Uuid, + avatar_url: []const u8, + header_file_id: ?Uuid, + header_url: ?[]const u8, profile_fields: []const ProfileField, @@ -459,6 +464,28 @@ fn ApiConn(comptime DbConn: type) type { fn getUserUnchecked(self: *Self, db: anytype, user_id: Uuid) !UserResponse { const user = try services.actors.get(db, user_id, self.allocator); + const avatar_url = if (user.avatar_file_id) |fid| + try std.fmt.allocPrint( + self.allocator, + "{s}://{s}/media/{}", + .{ @tagName(self.community.scheme), self.community.host, fid }, + ) + else + try std.fmt.allocPrint( + self.allocator, + "{s}://{s}/{s}", + .{ @tagName(self.community.scheme), self.community.host, default_avatar }, + ); + errdefer self.allocator.free(avatar_url); + const header_url = if (user.header_file_id) |fid| + try std.fmt.allocPrint( + self.allocator, + "{s}://{s}/media/{}", + .{ @tagName(self.community.scheme), self.community.host, fid }, + ) + else + null; + return UserResponse{ .id = user.id, @@ -469,7 +496,10 @@ fn ApiConn(comptime DbConn: type) type { .bio = user.bio, .avatar_file_id = user.avatar_file_id, + .avatar_url = avatar_url, + .header_file_id = user.header_file_id, + .header_url = header_url, .profile_fields = user.profile_fields, diff --git a/src/main/controllers/web/signup.tmpl.html b/src/main/controllers/web/signup.tmpl.html index f9a9254..e8f1f7a 100644 --- a/src/main/controllers/web/signup.tmpl.html +++ b/src/main/controllers/web/signup.tmpl.html @@ -10,17 +10,20 @@
You are about to accept an invite from:
-
- {=#if $invite.creator.display_name |$name|=} - {$name} - {= #else =} - {$invite.creator.username} - {= /if =} + +
+
+ {=#if $invite.creator.display_name |$name|=} + {$name} + {= #else =} + {$invite.creator.username} + {= /if =} +
+
@{$invite.creator.username}@{$invite.creator.host}
-
@{$invite.creator.username}@{$invite.creator.host}
{#if @isTag($invite.kind, community_owner) =} -
This act will make your new account the owner of { %community.name }
+
This act will make your new account the owner of { %community.name }.
{/if =}
{=/if} @@ -44,7 +47,7 @@
Email
- +
{#if .invite |$invite| =} diff --git a/src/template/lib.zig b/src/template/lib.zig index 33b55d3..9aa1cf0 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -7,7 +7,7 @@ pub fn main() !void { .{ .test_tmpl = "{.x} {%context_foo}" }, @embedFile("./test.tmp.html"), .{ - .community = .{ .name = "abcd" }, + .community = .{ .name = "" }, .foo = [_][]const u8{ "5", "4", "3", "2", "1" }, .baz = [_][]const []const u8{ &.{ "5", "4", "3", "2", "1" }, @@ -184,9 +184,19 @@ fn executeStatement( } } +fn htmlEscape(writer: anytype, str: []const u8) !void { + for (str) |ch| switch (ch) { + '<' => try writer.writeAll("<"), + '>' => try writer.writeAll(">"), + '"' => try writer.writeAll("""), + '&' => try writer.writeAll("&"), + else => try writer.writeByte(ch), + }; +} + fn print(writer: anytype, arg: anytype) !void { const T = @TypeOf(arg); - if (comptime std.meta.trait.isZigString(T)) return writer.writeAll(arg); + if (comptime std.meta.trait.isZigString(T)) return htmlEscape(writer, arg); if (comptime std.meta.trait.isNumber(T)) return std.fmt.format(writer, "{}", .{arg}); @compileLog(@TypeOf(arg)); diff --git a/static/default_avi.png b/static/default_avi.png new file mode 100644 index 0000000..edd1828 --- /dev/null +++ b/static/default_avi.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:54247347d90cecd9e6d598e1d74fae31f874ebb5c5e4dff7b4acc6a606acceef +size 40812 diff --git a/static/site.css b/static/site.css index 2eff495..da072d4 100644 --- a/static/site.css +++ b/static/site.css @@ -43,56 +43,79 @@ nav > ul > li.title > a { main { padding: 1em; + overflow: scroll; +} + +.user-mini { + display: flex; + margin: 0.5em 0px; +} + +.user-mini .avatar { + max-width: 3em; +} +.user-mini .details { + margin: 5px; +} + +.user-mini .handle { + font-size: small; } form { display: flex; flex-direction: column; max-width: 400px; -} -.textinput { - display: inline-block; - padding: 6px; - border: solid 1px black; - border-radius: 8px; -/* max-width: 300px;*/ -} - -form { padding: 1em; } - form > * { margin: 5px 0px; } - -form[action*=login] .textinput { +form .textinput { display: flex; + padding: 6px; + border: solid 1px black; + border-radius: 8px; outline: solid 2px transparent; transition: outline 0.2s; + cursor: text; } -form[action*=login] .textinput input { +form .textinput input { flex-grow: 1; + flex-basis: 3em; + width: 10px; + appearance: none; + border: none; } -form[action*=login] .textinput:focus-within { +form .textinput input:focus-visible{ + outline: none; +} +form .textinput:focus-within { outline: solid 2px var(--theme-color); } -form[action*=login] .textinput span.prefix, -form[action*=login] .textinput span.suffix { +form .textinput span.prefix { user-select: none; flex-basis: 1.5em; text-align: center; } -.textinput > input { - appearance: none; - border: none; -} -.textinput > input:focus-visible{ - outline: none; +form .textinput span.suffix { + user-select: none; + flex-basis: 3em; + flex-grow: 1; + max-width: min-content; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } -.form-helpinfo { +@media (max-width: 360px) { + form .textinput span.suffix { + display: none; + } +} + +form .form-helpinfo { font-size: small; } @@ -103,9 +126,11 @@ button, a.button { color: #fff; background-color: var(--theme-color); font-weight: bold; + transition: background-color 0.2s; + cursor: pointer; } button:hover, a.button:hover { - cursor: pointer; background-color: var(--theme-color-highlight); } +