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);
}
+