Compare commits

...

4 commits

Author SHA1 Message Date
b781b34029 style and typo fixes 2022-12-10 02:52:11 -08:00
25cd5f982b Escape HTML 2022-12-10 02:52:11 -08:00
bbbaa3f8b0 Use default avatar on signup page 2022-12-10 02:52:11 -08:00
0777ea83bb Add default avatar 2022-12-10 02:51:59 -08:00
5 changed files with 107 additions and 36 deletions

View file

@ -5,6 +5,8 @@ const sql = @import("sql");
const DateTime = util.DateTime; const DateTime = util.DateTime;
const Uuid = util.Uuid; const Uuid = util.Uuid;
const default_avatar = "static/default_avi.png";
const services = struct { const services = struct {
const communities = @import("./services/communities.zig"); const communities = @import("./services/communities.zig");
const actors = @import("./services/actors.zig"); const actors = @import("./services/actors.zig");
@ -52,7 +54,10 @@ pub const UserResponse = struct {
bio: []const u8, bio: []const u8,
avatar_file_id: ?Uuid, avatar_file_id: ?Uuid,
avatar_url: []const u8,
header_file_id: ?Uuid, header_file_id: ?Uuid,
header_url: ?[]const u8,
profile_fields: []const ProfileField, profile_fields: []const ProfileField,
@ -459,6 +464,28 @@ fn ApiConn(comptime DbConn: type) type {
fn getUserUnchecked(self: *Self, db: anytype, user_id: Uuid) !UserResponse { fn getUserUnchecked(self: *Self, db: anytype, user_id: Uuid) !UserResponse {
const user = try services.actors.get(db, user_id, self.allocator); 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{ return UserResponse{
.id = user.id, .id = user.id,
@ -469,7 +496,10 @@ fn ApiConn(comptime DbConn: type) type {
.bio = user.bio, .bio = user.bio,
.avatar_file_id = user.avatar_file_id, .avatar_file_id = user.avatar_file_id,
.avatar_url = avatar_url,
.header_file_id = user.header_file_id, .header_file_id = user.header_file_id,
.header_url = header_url,
.profile_fields = user.profile_fields, .profile_fields = user.profile_fields,

View file

@ -10,17 +10,20 @@
<div> <div>
<div>You are about to accept an invite from:</div> <div>You are about to accept an invite from:</div>
<div class="user-mini"> <div class="user-mini">
<div> <img class="avatar" src="{$invite.creator.avatar_url}" />
<div class="details">
<div class="display_name">
{=#if $invite.creator.display_name |$name|=} {=#if $invite.creator.display_name |$name|=}
{$name} {$name}
{= #else =} {= #else =}
{$invite.creator.username} {$invite.creator.username}
{= /if =} {= /if =}
</div> </div>
<div>@{$invite.creator.username}@{$invite.creator.host}</div> <div class="handle">@{$invite.creator.username}@{$invite.creator.host}</div>
</div>
</div> </div>
{#if @isTag($invite.kind, community_owner) =} {#if @isTag($invite.kind, community_owner) =}
<div>This act will make your new account the owner of { %community.name }</div> <div>This act will make your new account the owner of { %community.name }.</div>
{/if =} {/if =}
</div> </div>
{=/if} {=/if}
@ -44,7 +47,7 @@
<div>Email</div> <div>Email</div>
<div class="textinput"> <div class="textinput">
<span class="prefix"><i class="fa-solid fa-envelope fa-fw"></i></span> <span class="prefix"><i class="fa-solid fa-envelope fa-fw"></i></span>
<input type="email" name="email" placeholder="me@exmaple.com" /> <input type="email" name="email" placeholder="me@example.com" />
</div> </div>
</label> </label>
{#if .invite |$invite| =} {#if .invite |$invite| =}

View file

@ -7,7 +7,7 @@ pub fn main() !void {
.{ .test_tmpl = "{.x} {%context_foo}" }, .{ .test_tmpl = "{.x} {%context_foo}" },
@embedFile("./test.tmp.html"), @embedFile("./test.tmp.html"),
.{ .{
.community = .{ .name = "abcd" }, .community = .{ .name = "<abcd>" },
.foo = [_][]const u8{ "5", "4", "3", "2", "1" }, .foo = [_][]const u8{ "5", "4", "3", "2", "1" },
.baz = [_][]const []const u8{ .baz = [_][]const []const u8{
&.{ "5", "4", "3", "2", "1" }, &.{ "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("&lt;"),
'>' => try writer.writeAll("&gt;"),
'"' => try writer.writeAll("&quot;"),
'&' => try writer.writeAll("&amp;"),
else => try writer.writeByte(ch),
};
}
fn print(writer: anytype, arg: anytype) !void { fn print(writer: anytype, arg: anytype) !void {
const T = @TypeOf(arg); 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}); if (comptime std.meta.trait.isNumber(T)) return std.fmt.format(writer, "{}", .{arg});
@compileLog(@TypeOf(arg)); @compileLog(@TypeOf(arg));

3
static/default_avi.png Normal file
View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:54247347d90cecd9e6d598e1d74fae31f874ebb5c5e4dff7b4acc6a606acceef
size 40812

View file

@ -43,56 +43,79 @@ nav > ul > li.title > a {
main { main {
padding: 1em; 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 { form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
max-width: 400px; max-width: 400px;
}
.textinput {
display: inline-block;
padding: 6px;
border: solid 1px black;
border-radius: 8px;
/* max-width: 300px;*/
}
form {
padding: 1em; padding: 1em;
} }
form > * { form > * {
margin: 5px 0px; margin: 5px 0px;
} }
form .textinput {
form[action*=login] .textinput {
display: flex; display: flex;
padding: 6px;
border: solid 1px black;
border-radius: 8px;
outline: solid 2px transparent; outline: solid 2px transparent;
transition: outline 0.2s; transition: outline 0.2s;
cursor: text;
} }
form[action*=login] .textinput input { form .textinput input {
flex-grow: 1; 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); outline: solid 2px var(--theme-color);
} }
form[action*=login] .textinput span.prefix, form .textinput span.prefix {
form[action*=login] .textinput span.suffix {
user-select: none; user-select: none;
flex-basis: 1.5em; flex-basis: 1.5em;
text-align: center; text-align: center;
} }
.textinput > input { form .textinput span.suffix {
appearance: none; user-select: none;
border: none; flex-basis: 3em;
} flex-grow: 1;
.textinput > input:focus-visible{ max-width: min-content;
outline: none; 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; font-size: small;
} }
@ -103,9 +126,11 @@ button, a.button {
color: #fff; color: #fff;
background-color: var(--theme-color); background-color: var(--theme-color);
font-weight: bold; font-weight: bold;
transition: background-color 0.2s;
cursor: pointer;
} }
button:hover, a.button:hover { button:hover, a.button:hover {
cursor: pointer;
background-color: var(--theme-color-highlight); background-color: var(--theme-color-highlight);
} }