Gonçalo Rodrigues 26a7236494 style: global dark form inputs + team emoji avatars (#23)
Form inputs:
- Add a catch-all CSS rule targeting all text-type inputs, selects, and
  textareas not already covered by .form-group or .form-input — sets
  background:--bg2, color:--text, focus ring. Fixes white-box appearance
  in transactions, goals, settings, portfolio, import, people, and tax
  templates without touching any HTML.

Team avatars:
- OrgTeam.Avatar string (emoji) — persisted in MongoDB, defaults to 👥
- OrgTeamCreate handler reads "avatar" form field
- org_teams.html: emoji picker (30 options) in new-team modal; preview
  updates live; selected emoji highlighted with accent border
- avatarEmojis() and teamAvatar() template functions registered in FuncMap
- Team badges in org_members, org_events, org_event_detail, org_report
  all show the emoji inline with the team name

Co-authored-by: Gonçalo Rodrigues <guga@Goncalos-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 16:08:29 +01:00

118 lines
5.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{define "content"}}
{{$d := .}}
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:24px; flex-wrap:wrap; gap:12px;">
<div>
<div style="font-size:12px; color:var(--text3); margin-bottom:4px;">
<a href="/orgs" style="color:var(--text3); text-decoration:none;">Organisations</a> /
<a href="/orgs/{{$d.Org.Slug}}" style="color:var(--text3); text-decoration:none;">{{$d.Org.Name}}</a> /
</div>
<h1>Teams</h1>
</div>
{{if eq $d.MyRole "admin"}}
<button onclick="document.getElementById('new-team-modal').style.display='flex'" class="btn btn-primary">+ New team</button>
{{end}}
</div>
{{if $d.Teams}}
<div class="card animate-on-scroll" style="padding:0; overflow:hidden;">
<table>
<thead>
<tr>
<th>Team</th>
<th>Type</th>
<th>Members</th>
{{if eq $d.MyRole "admin"}}<th></th>{{end}}
</tr>
</thead>
<tbody>
{{range $t := $d.Teams}}
{{$count := 0}}
{{range $d.Members}}{{range .TeamIDs}}{{if eq . $t.ID}}{{$count = add $count 1}}{{end}}{{end}}{{end}}
<tr>
<td>
<div style="display:flex; align-items:center; gap:10px;">
<span class="team-avatar">{{if $t.Avatar}}{{$t.Avatar}}{{else}}👥{{end}}</span>
<span style="font-weight:600;">{{$t.Name}}</span>
</div>
</td>
<td>
{{if eq (print $t.Type) "guest"}}
<span style="font-size:11px; font-weight:600; padding:3px 9px; border-radius:20px; background:rgba(251,191,36,0.1); color:#fbbf24;">guest</span>
{{else}}
<span style="font-size:11px; font-weight:600; padding:3px 9px; border-radius:20px; background:var(--accent-glow); color:var(--accent2);">internal</span>
{{end}}
</td>
<td style="color:var(--text2);">{{$count}}</td>
{{if eq $d.MyRole "admin"}}
<td style="text-align:right;">
<form method="post" action="/orgs/{{$d.Org.Slug}}/teams/{{$t.ID}}/delete" style="display:inline;"
onsubmit="return confirm('Delete team {{$t.Name}}? Members will lose team assignment.')">
<button class="btn btn-outline btn-sm" style="color:var(--red); border-color:var(--red);">Delete</button>
</form>
</td>
{{end}}
</tr>
{{end}}
</tbody>
</table>
</div>
{{else}}
<div class="card empty-state animate-on-scroll">
<div style="font-size:36px; margin-bottom:12px;">👥</div>
<h3>No teams yet</h3>
<p style="margin-bottom:16px;">Teams group members and own events. Guest teams have scoped visibility.</p>
{{if eq $d.MyRole "admin"}}
<button onclick="document.getElementById('new-team-modal').style.display='flex'" class="btn btn-primary">Create first team</button>
{{end}}
</div>
{{end}}
{{if eq $d.MyRole "admin"}}
<div id="new-team-modal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.6); z-index:500; align-items:center; justify-content:center; padding:16px;">
<div class="card" style="width:100%; max-width:420px;">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
<h2>New team</h2>
<button onclick="document.getElementById('new-team-modal').style.display='none'" style="background:none; border:none; color:var(--text3); font-size:20px; cursor:pointer;">×</button>
</div>
<form method="post" action="/orgs/{{$d.Org.Slug}}/teams">
<!-- Avatar picker -->
<div style="margin-bottom:16px;">
<label class="form-label">Avatar</label>
<input type="hidden" name="avatar" id="avatar-val" value="👥">
<div style="display:flex; align-items:center; gap:12px; margin-bottom:10px;">
<span class="team-avatar team-avatar-lg" id="avatar-preview">👥</span>
<span style="font-size:12px; color:var(--text3);">Pick an emoji below</span>
</div>
<div class="emoji-picker">
{{range (avatarEmojis)}}
<button type="button" class="emoji-opt" onclick="pickEmoji(this, '{{.}}')">{{.}}</button>
{{end}}
</div>
</div>
<div style="margin-bottom:14px;">
<label class="form-label">Team name</label>
<input class="form-input" type="text" name="name" placeholder="Marketing" required autofocus>
</div>
<div style="margin-bottom:20px;">
<label class="form-label">Type</label>
<select class="form-input" name="type">
<option value="internal">Internal — full org visibility</option>
<option value="guest">Guest — sees own team data only</option>
</select>
</div>
<button type="submit" class="btn btn-primary" style="width:100%;">Create team</button>
</form>
</div>
</div>
<script>
function pickEmoji(btn, emoji) {
document.querySelectorAll('.emoji-opt').forEach(b => b.classList.remove('selected'));
btn.classList.add('selected');
document.getElementById('avatar-val').value = emoji;
document.getElementById('avatar-preview').textContent = emoji;
}
</script>
{{end}}
{{end}}