diff --git a/go-backend/internal/web/handlers/auth.go b/go-backend/internal/web/handlers/auth.go index bd8dbab..7b7df0c 100644 --- a/go-backend/internal/web/handlers/auth.go +++ b/go-backend/internal/web/handlers/auth.go @@ -98,9 +98,9 @@ func (h *AuthHandler) GetHome() http.HandlerFunc { content := views.OverviewMainContent(user.DisplayName, user.Email, projects) var renderErr error if isHXRequest(r) { - renderErr = views.DashboardContentSwap("/", content).Render(r.Context(), w) + renderErr = views.DashboardContentSwap("/", tablos, content).Render(r.Context(), w) } else { - renderErr = views.DashboardPage("/", content).Render(r.Context(), w) + renderErr = views.DashboardPage("/", tablos, content).Render(r.Context(), w) } if renderErr != nil { http.Error(w, "failed to render app page", http.StatusInternalServerError) @@ -152,16 +152,24 @@ func (h *AuthHandler) GetNotFound() http.HandlerFunc { return } + tablos, err := h.repo.ListTablos(r.Context(), ListTablosInput{ + OwnerID: user.ID, + }) + if err != nil { + http.Error(w, "failed to load projects", http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusNotFound) content := views.NotFoundContent(user.DisplayName) - var err error + var renderErr error if isHXRequest(r) { - err = views.DashboardContentSwap("", content).Render(r.Context(), w) + renderErr = views.DashboardContentSwap("", tablos, content).Render(r.Context(), w) } else { - err = views.DashboardPage("", content).Render(r.Context(), w) + renderErr = views.DashboardPage("", tablos, content).Render(r.Context(), w) } - if err != nil { + if renderErr != nil { http.Error(w, "failed to render not found page", http.StatusInternalServerError) } } @@ -175,15 +183,23 @@ func (h *AuthHandler) renderAppPage(activePath string, content func(user PublicU return } + tablos, err := h.repo.ListTablos(r.Context(), ListTablosInput{ + OwnerID: user.ID, + }) + if err != nil { + http.Error(w, "failed to load projects", http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") pageContent := content(user) - var err error + var renderErr error if isHXRequest(r) { - err = views.DashboardContentSwap(activePath, pageContent).Render(r.Context(), w) + renderErr = views.DashboardContentSwap(activePath, tablos, pageContent).Render(r.Context(), w) } else { - err = views.DashboardPage(activePath, pageContent).Render(r.Context(), w) + renderErr = views.DashboardPage(activePath, tablos, pageContent).Render(r.Context(), w) } - if err != nil { + if renderErr != nil { http.Error(w, "failed to render app page", http.StatusInternalServerError) } } diff --git a/go-backend/internal/web/handlers/auth_test.go b/go-backend/internal/web/handlers/auth_test.go index ad27bbd..43f5641 100644 --- a/go-backend/internal/web/handlers/auth_test.go +++ b/go-backend/internal/web/handlers/auth_test.go @@ -1,6 +1,7 @@ package handlers import ( + "context" "bytes" "net/http" "net/http/httptest" @@ -114,6 +115,59 @@ func TestLogoutLogsSessionDeletion(t *testing.T) { } } +func TestTasksPageSidebarShowsRealTablos(t *testing.T) { + repo := NewInMemoryAuthRepository() + handler := NewAuthHandler(repo) + sessionCookie := loginTestUser(t, handler, "demo@xtablo.com", "xtablo-demo") + + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.AddCookie(sessionCookie) + userID, ok := handler.currentUserID(req.Context(), req) + if !ok { + t.Fatal("expected user session") + } + + for _, tablo := range []CreateTabloInput{ + {OwnerID: userID, Name: "Blue", Color: "#3B82F6", Status: TabloStatusTodo}, + {OwnerID: userID, Name: "Green", Color: "#22C55E", Status: TabloStatusTodo}, + {OwnerID: userID, Name: "Purple", Color: "#A855F7", Status: TabloStatusTodo}, + {OwnerID: userID, Name: "Red", Color: "#EF4444", Status: TabloStatusTodo}, + {OwnerID: userID, Name: "Hidden Fifth", Color: "#EAB308", Status: TabloStatusTodo}, + } { + if _, err := repo.CreateTablo(context.Background(), tablo); err != nil { + t.Fatalf("create tablo %q: %v", tablo.Name, err) + } + } + + pageReq := httptest.NewRequest(http.MethodGet, "/tasks", nil) + pageReq.AddCookie(sessionCookie) + rec := httptest.NewRecorder() + + handler.GetTasksPage().ServeHTTP(rec, pageReq) + + if rec.Code != http.StatusOK { + t.Fatalf("expected status 200, got %d", rec.Code) + } + + body := rec.Body.String() + for _, want := range []string{ + "Green", + "Purple", + "Red", + "Hidden Fifth", + } { + if !strings.Contains(body, want) { + t.Fatalf("expected sidebar to contain %q, got %q", want, body) + } + } + if strings.Contains(body, "Blue") { + t.Fatalf("expected sidebar to limit to the four most recent tablos, got %q", body) + } + if !strings.Contains(body, `href="/tablos/`) { + t.Fatalf("expected sidebar project links, got %q", body) + } +} + func newTestAuthHandler(t *testing.T) *AuthHandler { t.Helper() return NewAuthHandler(NewInMemoryAuthRepository()) diff --git a/go-backend/internal/web/handlers/tablos.go b/go-backend/internal/web/handlers/tablos.go index 3d1811c..e724e4b 100644 --- a/go-backend/internal/web/handlers/tablos.go +++ b/go-backend/internal/web/handlers/tablos.go @@ -7,13 +7,13 @@ import ( "net/http" "net/url" "regexp" - "strconv" "strings" "time" "github.com/google/uuid" tablomodel "xtablo-backend/internal/tablos" "xtablo-backend/internal/web/dates" + "xtablo-backend/internal/web/tabloicons" "xtablo-backend/internal/web/views" ) @@ -24,29 +24,6 @@ var tabloColorPattern = regexp.MustCompile(`^#[0-9A-Fa-f]{6}$`) const defaultTabloColor = "#3B82F6" const tabloColorValidationMessage = "La couleur du projet doit être un code hexadécimal au format #RRGGBB" -type tabloPaletteEntry struct { - icon string - bg string - fg string - accent string - r int - g int - b int -} - -var tabloIconPalette = []tabloPaletteEntry{ - {icon: "bolt", bg: "bg-blue-500", fg: "text-white", accent: "blue", r: 59, g: 130, b: 246}, - {icon: "leaf", bg: "bg-green-500", fg: "text-white", accent: "green", r: 34, g: 197, b: 94}, - {icon: "gem", bg: "bg-purple-500", fg: "text-white", accent: "purple", r: 168, g: 85, b: 247}, - {icon: "flame", bg: "bg-red-500", fg: "text-white", accent: "red", r: 239, g: 68, b: 68}, - {icon: "star", bg: "bg-yellow-500", fg: "text-gray-700", accent: "yellow", r: 234, g: 179, b: 8}, - {icon: "compass", bg: "bg-indigo-500", fg: "text-white", accent: "indigo", r: 99, g: 102, b: 241}, - {icon: "heart", bg: "bg-pink-500", fg: "text-white", accent: "pink", r: 236, g: 72, b: 153}, - {icon: "waves", bg: "bg-teal-500", fg: "text-white", accent: "teal", r: 20, g: 184, b: 166}, - {icon: "sun", bg: "bg-orange-500", fg: "text-white", accent: "orange", r: 249, g: 115, b: 22}, - {icon: "sparkles", bg: "bg-cyan-500", fg: "text-gray-700", accent: "cyan", r: 6, g: 182, b: 212}, -} - type TabloStatus = tablomodel.Status const ( @@ -152,7 +129,7 @@ func (h *AuthHandler) PostTablos() http.HandlerFunc { http.Error(w, "failed to list tablos", http.StatusInternalServerError) return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, name, r.FormValue("color"), "Le nom du projet est requis"), http.StatusUnprocessableEntity) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, name, r.FormValue("color"), "Le nom du projet est requis"), http.StatusUnprocessableEntity) return } @@ -163,7 +140,7 @@ func (h *AuthHandler) PostTablos() http.HandlerFunc { http.Error(w, "failed to list tablos", http.StatusInternalServerError) return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, name, r.FormValue("color"), tabloColorValidationMessage), http.StatusUnprocessableEntity) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, name, r.FormValue("color"), tabloColorValidationMessage), http.StatusUnprocessableEntity) return } @@ -184,7 +161,7 @@ func (h *AuthHandler) PostTablos() http.HandlerFunc { return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, "", "", ""), http.StatusOK) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, "", "", ""), http.StatusOK) } } @@ -218,7 +195,7 @@ func (h *AuthHandler) GetEditTabloModal() http.HandlerFunc { return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, tablo.Name, tablo.Color, ""), http.StatusOK) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, tablo.Name, tablo.Color, ""), http.StatusOK) } } @@ -252,7 +229,7 @@ func (h *AuthHandler) PostTabloUpdate() http.HandlerFunc { http.Error(w, "failed to list tablos", http.StatusInternalServerError) return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, name, r.FormValue("color"), "Le nom du projet est requis"), http.StatusUnprocessableEntity) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, name, r.FormValue("color"), "Le nom du projet est requis"), http.StatusUnprocessableEntity) return } @@ -263,7 +240,7 @@ func (h *AuthHandler) PostTabloUpdate() http.HandlerFunc { http.Error(w, "failed to list tablos", http.StatusInternalServerError) return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, name, r.FormValue("color"), tabloColorValidationMessage), http.StatusUnprocessableEntity) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, name, r.FormValue("color"), tabloColorValidationMessage), http.StatusUnprocessableEntity) return } @@ -289,7 +266,7 @@ func (h *AuthHandler) PostTabloUpdate() http.HandlerFunc { return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, "", "", ""), http.StatusOK) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, "", "", ""), http.StatusOK) } } @@ -323,7 +300,7 @@ func (h *AuthHandler) DeleteTablo() http.HandlerFunc { return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, "", "", ""), http.StatusOK) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, "", "", ""), http.StatusOK) } } @@ -341,7 +318,7 @@ func (h *AuthHandler) renderTablosPage(w http.ResponseWriter, r *http.Request) { return } - renderTablosResponse(w, r, "/tablos", tablosPageViewModel(user, state, tablos, "", "", ""), http.StatusOK) + renderTablosResponse(w, r, "/tablos", tablos, tablosPageViewModel(user, state, tablos, "", "", ""), http.StatusOK) } func tablosPageViewModel(user PublicUser, state TablosPageState, tablos []TabloRecord, formName string, formColor string, errorMessage string) views.TablosPageViewModel { @@ -374,16 +351,16 @@ func findTabloByID(tablos []TabloRecord, targetID uuid.UUID) (TabloRecord, bool) return TabloRecord{}, false } -func renderTablosResponse(w http.ResponseWriter, r *http.Request, activePath string, vm views.TablosPageViewModel, statusCode int) { +func renderTablosResponse(w http.ResponseWriter, r *http.Request, activePath string, tablos []TabloRecord, vm views.TablosPageViewModel, statusCode int) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(statusCode) var err error content := views.TablosPageContent(vm) if isHXRequest(r) { - err = views.DashboardContentSwapWithMainClass(activePath, "flex-1 overflow-auto", content).Render(r.Context(), w) + err = views.DashboardContentSwapWithMainClass(activePath, tablos, "flex-1 overflow-auto", content).Render(r.Context(), w) } else { - err = views.DashboardPageWithMainClass(activePath, "flex-1 overflow-auto", content).Render(r.Context(), w) + err = views.DashboardPageWithMainClass(activePath, tablos, "flex-1 overflow-auto", content).Render(r.Context(), w) } if err != nil { http.Error(w, "failed to render tablos page", http.StatusInternalServerError) @@ -538,52 +515,8 @@ func tabloStatusPresentation(status TabloStatus) (string, string, int, string) { } func tabloIconPresentation(color string) (string, string, string, string) { - r, g, b, ok := parseHexColor(color) - if !ok { - fallback := tabloIconPalette[0] - return fallback.icon, fallback.bg, fallback.fg, fallback.accent - } - - best := tabloIconPalette[0] - bestDistance := colorDistanceSquared(r, g, b, best.r, best.g, best.b) - for _, entry := range tabloIconPalette[1:] { - distance := colorDistanceSquared(r, g, b, entry.r, entry.g, entry.b) - if distance < bestDistance { - best = entry - bestDistance = distance - } - } - - return best.icon, best.bg, best.fg, best.accent -} - -func parseHexColor(color string) (int, int, int, bool) { - trimmed := strings.TrimSpace(color) - if len(trimmed) != 7 || trimmed[0] != '#' { - return 0, 0, 0, false - } - - r, err := strconv.ParseInt(trimmed[1:3], 16, 0) - if err != nil { - return 0, 0, 0, false - } - g, err := strconv.ParseInt(trimmed[3:5], 16, 0) - if err != nil { - return 0, 0, 0, false - } - b, err := strconv.ParseInt(trimmed[5:7], 16, 0) - if err != nil { - return 0, 0, 0, false - } - - return int(r), int(g), int(b), true -} - -func colorDistanceSquared(r1 int, g1 int, b1 int, r2 int, g2 int, b2 int) int { - dr := r1 - r2 - dg := g1 - g2 - db := b1 - b2 - return dr*dr + dg*dg + db*db + presentation := tabloicons.ForColor(color) + return presentation.Icon, presentation.Bg, presentation.Fg, presentation.Accent } func formatFrenchDate(value time.Time) string { diff --git a/go-backend/internal/web/tabloicons/presentation.go b/go-backend/internal/web/tabloicons/presentation.go new file mode 100644 index 0000000..90871f8 --- /dev/null +++ b/go-backend/internal/web/tabloicons/presentation.go @@ -0,0 +1,81 @@ +package tabloicons + +import ( + "strconv" + "strings" +) + +type Presentation struct { + Icon string + Bg string + Fg string + Accent string +} + +type paletteEntry struct { + Presentation + r int + g int + b int +} + +var palette = []paletteEntry{ + {Presentation: Presentation{Icon: "bolt", Bg: "bg-blue-500", Fg: "text-white", Accent: "blue"}, r: 59, g: 130, b: 246}, + {Presentation: Presentation{Icon: "leaf", Bg: "bg-green-500", Fg: "text-white", Accent: "green"}, r: 34, g: 197, b: 94}, + {Presentation: Presentation{Icon: "gem", Bg: "bg-purple-500", Fg: "text-white", Accent: "purple"}, r: 168, g: 85, b: 247}, + {Presentation: Presentation{Icon: "flame", Bg: "bg-red-500", Fg: "text-white", Accent: "red"}, r: 239, g: 68, b: 68}, + {Presentation: Presentation{Icon: "star", Bg: "bg-yellow-500", Fg: "text-gray-700", Accent: "yellow"}, r: 234, g: 179, b: 8}, + {Presentation: Presentation{Icon: "compass", Bg: "bg-indigo-500", Fg: "text-white", Accent: "indigo"}, r: 99, g: 102, b: 241}, + {Presentation: Presentation{Icon: "heart", Bg: "bg-pink-500", Fg: "text-white", Accent: "pink"}, r: 236, g: 72, b: 153}, + {Presentation: Presentation{Icon: "waves", Bg: "bg-teal-500", Fg: "text-white", Accent: "teal"}, r: 20, g: 184, b: 166}, + {Presentation: Presentation{Icon: "sun", Bg: "bg-orange-500", Fg: "text-white", Accent: "orange"}, r: 249, g: 115, b: 22}, + {Presentation: Presentation{Icon: "sparkles", Bg: "bg-cyan-500", Fg: "text-gray-700", Accent: "cyan"}, r: 6, g: 182, b: 212}, +} + +func ForColor(color string) Presentation { + r, g, b, ok := parseHexColor(color) + if !ok { + return palette[0].Presentation + } + + best := palette[0] + bestDistance := colorDistanceSquared(r, g, b, best.r, best.g, best.b) + for _, entry := range palette[1:] { + distance := colorDistanceSquared(r, g, b, entry.r, entry.g, entry.b) + if distance < bestDistance { + best = entry + bestDistance = distance + } + } + + return best.Presentation +} + +func parseHexColor(color string) (int, int, int, bool) { + trimmed := strings.TrimSpace(color) + if len(trimmed) != 7 || trimmed[0] != '#' { + return 0, 0, 0, false + } + + r, err := strconv.ParseInt(trimmed[1:3], 16, 0) + if err != nil { + return 0, 0, 0, false + } + g, err := strconv.ParseInt(trimmed[3:5], 16, 0) + if err != nil { + return 0, 0, 0, false + } + b, err := strconv.ParseInt(trimmed[5:7], 16, 0) + if err != nil { + return 0, 0, 0, false + } + + return int(r), int(g), int(b), true +} + +func colorDistanceSquared(r1 int, g1 int, b1 int, r2 int, g2 int, b2 int) int { + dr := r1 - r2 + dg := g1 - g2 + db := b1 - b2 + return dr*dr + dg*dg + db*db +} diff --git a/go-backend/internal/web/ui/app.css b/go-backend/internal/web/ui/app.css index 026863b..9056499 100644 --- a/go-backend/internal/web/ui/app.css +++ b/go-backend/internal/web/ui/app.css @@ -1004,6 +1004,11 @@ td.text-right .borderless-icon-button.ui-icon-button-ghost.ui-icon-button-danger width: 3rem; } +.project-avatar > svg { + height: 1.25rem; + width: 1.25rem; +} + .project-list-icon { background: var(--project-color, var(--color-project-fallback)); color: var(--color-text-inverse); diff --git a/go-backend/internal/web/views/dashboard_components.templ b/go-backend/internal/web/views/dashboard_components.templ index 2734eae..b93466c 100644 --- a/go-backend/internal/web/views/dashboard_components.templ +++ b/go-backend/internal/web/views/dashboard_components.templ @@ -1,13 +1,14 @@ package views import "strconv" +import tablomodel "xtablo-backend/internal/tablos" import "xtablo-backend/internal/web/ui" -templ DashboardPage(activePath string, content templ.Component) { - @DashboardPageWithMainClass(activePath, "dashboard-main flex-1 overflow-auto", content) +templ DashboardPage(activePath string, tablos []tablomodel.Record, content templ.Component) { + @DashboardPageWithMainClass(activePath, tablos, "dashboard-main flex-1 overflow-auto", content) } -templ DashboardPageWithMainClass(activePath string, mainClass string, content templ.Component) { +templ DashboardPageWithMainClass(activePath string, tablos []tablomodel.Record, mainClass string, content templ.Component) { @@ -20,7 +21,7 @@ templ DashboardPageWithMainClass(activePath string, mainClass string, content te
- @DashboardSidebar(activePath) + @DashboardSidebar(activePath, tablos) @DashboardMainContentWithClass(mainClass, content)
@@ -28,7 +29,7 @@ templ DashboardPageWithMainClass(activePath string, mainClass string, content te } templ DashboardNotFoundPage(displayName string, email string) { - @DashboardPage("", NotFoundContent(displayName)) + @DashboardPage("", nil, NotFoundContent(displayName)) } templ DashboardMainContent(content templ.Component) { @@ -41,16 +42,16 @@ templ DashboardMainContentWithClass(mainClass string, content templ.Component) { } -templ DashboardContentSwap(activePath string, content templ.Component) { - @DashboardContentSwapWithMainClass(activePath, "dashboard-main flex-1 overflow-auto", content) +templ DashboardContentSwap(activePath string, tablos []tablomodel.Record, content templ.Component) { + @DashboardContentSwapWithMainClass(activePath, tablos, "dashboard-main flex-1 overflow-auto", content) } -templ DashboardContentSwapWithMainClass(activePath string, mainClass string, content templ.Component) { +templ DashboardContentSwapWithMainClass(activePath string, tablos []tablomodel.Record, mainClass string, content templ.Component) { @DashboardMainContentWithClass(mainClass, content) - @DashboardNavOOB(activePath) + @DashboardNavOOB(activePath, tablos) } -templ DashboardSidebar(activePath string) { +templ DashboardSidebar(activePath string, tablos []tablomodel.Record) { } -templ DashboardNavOOB(activePath string) { +templ DashboardNavOOB(activePath string, tablos []tablomodel.Record) { for _, item := range sidebarPrimaryNavItems(activePath) { @SidebarNavItemOOB(item) } + @SidebarProjectsSectionOOB(tablos) for _, item := range sidebarFooterNavItems(activePath) { @SidebarNavItemOOB(item) } } +templ SidebarProjectsSection(tablos []tablomodel.Record) { + +} + +templ SidebarProjectsSectionOOB(tablos []tablomodel.Record) { + +} + templ SidebarOrganization() { ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -345,7 +336,7 @@ func DashboardSidebar(activePath string) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -353,7 +344,7 @@ func DashboardSidebar(activePath string) templ.Component { }) } -func DashboardNavOOB(activePath string) templ.Component { +func DashboardNavOOB(activePath string, tablos []tablomodel.Record) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -380,6 +371,10 @@ func DashboardNavOOB(activePath string) templ.Component { return templ_7745c5c3_Err } } + templ_7745c5c3_Err = SidebarProjectsSectionOOB(tablos).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } for _, item := range sidebarFooterNavItems(activePath) { templ_7745c5c3_Err = SidebarNavItemOOB(item).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { @@ -390,6 +385,100 @@ func DashboardNavOOB(activePath string) templ.Component { }) } +func SidebarProjectsSection(tablos []tablomodel.Record) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var12 := templ.GetChildren(ctx) + if templ_7745c5c3_Var12 == nil { + templ_7745c5c3_Var12 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "

Projets
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func SidebarProjectsSectionOOB(tablos []tablomodel.Record) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var13 := templ.GetChildren(ctx) + if templ_7745c5c3_Var13 == nil { + templ_7745c5c3_Var13 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

Projets
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + func SidebarOrganization() templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context @@ -406,12 +495,12 @@ func SidebarOrganization() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var12 := templ.GetChildren(ctx) - if templ_7745c5c3_Var12 == nil { - templ_7745c5c3_Var12 = templ.NopComponent + templ_7745c5c3_Var14 := templ.GetChildren(ctx) + if templ_7745c5c3_Var14 == nil { + templ_7745c5c3_Var14 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -435,12 +524,12 @@ func OverviewMainContent(displayName string, email string, tablos []TabloCardVie }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var13 := templ.GetChildren(ctx) - if templ_7745c5c3_Var13 == nil { - templ_7745c5c3_Var13 = templ.NopComponent + templ_7745c5c3_Var15 := templ.GetChildren(ctx) + if templ_7745c5c3_Var15 == nil { + templ_7745c5c3_Var15 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -460,7 +549,7 @@ func OverviewMainContent(displayName string, email string, tablos []TabloCardVie if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -484,9 +573,9 @@ func TasksMainContent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var14 := templ.GetChildren(ctx) - if templ_7745c5c3_Var14 == nil { - templ_7745c5c3_Var14 = templ.NopComponent + templ_7745c5c3_Var16 := templ.GetChildren(ctx) + if templ_7745c5c3_Var16 == nil { + templ_7745c5c3_Var16 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = AppSectionMainContent("Tâches", "Suivez les tâches de votre équipe, les priorités en cours et ce qui reste à livrer.").Render(ctx, templ_7745c5c3_Buffer) @@ -513,9 +602,9 @@ func TablosMainContent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var15 := templ.GetChildren(ctx) - if templ_7745c5c3_Var15 == nil { - templ_7745c5c3_Var15 = templ.NopComponent + templ_7745c5c3_Var17 := templ.GetChildren(ctx) + if templ_7745c5c3_Var17 == nil { + templ_7745c5c3_Var17 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = AppSectionMainContent("Projets", "Gardez une vue claire sur vos tablos, leur état d'avancement et les prochaines décisions à prendre.").Render(ctx, templ_7745c5c3_Buffer) @@ -542,9 +631,9 @@ func PlanningMainContent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var16 := templ.GetChildren(ctx) - if templ_7745c5c3_Var16 == nil { - templ_7745c5c3_Var16 = templ.NopComponent + templ_7745c5c3_Var18 := templ.GetChildren(ctx) + if templ_7745c5c3_Var18 == nil { + templ_7745c5c3_Var18 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = AppSectionMainContent("Planning", "Visualisez le rythme de l'équipe, les jalons à venir et les arbitrages de charge.").Render(ctx, templ_7745c5c3_Buffer) @@ -571,9 +660,9 @@ func ChatMainContent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var17 := templ.GetChildren(ctx) - if templ_7745c5c3_Var17 == nil { - templ_7745c5c3_Var17 = templ.NopComponent + templ_7745c5c3_Var19 := templ.GetChildren(ctx) + if templ_7745c5c3_Var19 == nil { + templ_7745c5c3_Var19 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = AppSectionMainContent("Discussions", "Retrouvez les conversations importantes, les décisions récentes et les échanges à relancer.").Render(ctx, templ_7745c5c3_Buffer) @@ -600,9 +689,9 @@ func FilesMainContent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var18 := templ.GetChildren(ctx) - if templ_7745c5c3_Var18 == nil { - templ_7745c5c3_Var18 = templ.NopComponent + templ_7745c5c3_Var20 := templ.GetChildren(ctx) + if templ_7745c5c3_Var20 == nil { + templ_7745c5c3_Var20 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = AppSectionMainContent("Fichiers", "Centralisez les documents utiles, les pièces partagées et les ressources de travail.").Render(ctx, templ_7745c5c3_Buffer) @@ -629,9 +718,9 @@ func FeedbackMainContent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var19 := templ.GetChildren(ctx) - if templ_7745c5c3_Var19 == nil { - templ_7745c5c3_Var19 = templ.NopComponent + templ_7745c5c3_Var21 := templ.GetChildren(ctx) + if templ_7745c5c3_Var21 == nil { + templ_7745c5c3_Var21 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = AppSectionMainContent("Feedback", "Collectez les retours produit, priorisez les signaux et transformez-les en actions concrètes.").Render(ctx, templ_7745c5c3_Buffer) @@ -658,38 +747,38 @@ func AppSectionMainContent(title string, description string) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var20 := templ.GetChildren(ctx) - if templ_7745c5c3_Var20 == nil { - templ_7745c5c3_Var20 = templ.NopComponent + templ_7745c5c3_Var22 := templ.GetChildren(ctx) + if templ_7745c5c3_Var22 == nil { + templ_7745c5c3_Var22 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "
Espace de travail

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
Espace de travail

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var21 string - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(title) + var templ_7745c5c3_Var23 string + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 162, Col: 14} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 182, Col: 14} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var22 string - templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(description) + var templ_7745c5c3_Var24 string + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(description) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 163, Col: 19} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 183, Col: 19} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -713,25 +802,25 @@ func NotFoundContent(displayName string) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var23 := templ.GetChildren(ctx) - if templ_7745c5c3_Var23 == nil { - templ_7745c5c3_Var23 = templ.NopComponent + templ_7745c5c3_Var25 := templ.GetChildren(ctx) + if templ_7745c5c3_Var25 == nil { + templ_7745c5c3_Var25 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
Erreur de navigation
404

Page introuvable

Cette page n'existe pas ou n'est plus disponible.

Retour à l'aperçu
Connecté en tant que ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
Erreur de navigation
404

Page introuvable

Cette page n'existe pas ou n'est plus disponible.

Retour à l'aperçu
Connecté en tant que ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var24 string - templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(dashboardGreetingName(displayName)) + var templ_7745c5c3_Var26 string + templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(dashboardGreetingName(displayName)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 183, Col: 48} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 203, Col: 48} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -755,38 +844,38 @@ func OverviewHeader(displayName string) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var25 := templ.GetChildren(ctx) - if templ_7745c5c3_Var25 == nil { - templ_7745c5c3_Var25 = templ.NopComponent + templ_7745c5c3_Var27 := templ.GetChildren(ctx) + if templ_7745c5c3_Var27 == nil { + templ_7745c5c3_Var27 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var26 string - templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(dashboardTodayLabel()) + var templ_7745c5c3_Var28 string + templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(dashboardTodayLabel()) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 191, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 211, Col: 50} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "

Bonjour, ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "

Bonjour, ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var27 string - templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(dashboardGreetingName(displayName)) + var templ_7745c5c3_Var29 string + templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(dashboardGreetingName(displayName)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 193, Col: 84} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 213, Col: 84} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "!

Founder
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "!

Founder") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -800,7 +889,7 @@ func OverviewHeader(displayName string) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -824,12 +913,12 @@ func OverviewActions(actions []quickAction) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var28 := templ.GetChildren(ctx) - if templ_7745c5c3_Var28 == nil { - templ_7745c5c3_Var28 = templ.NopComponent + templ_7745c5c3_Var30 := templ.GetChildren(ctx) + if templ_7745c5c3_Var30 == nil { + templ_7745c5c3_Var30 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -839,7 +928,7 @@ func OverviewActions(actions []quickAction) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -863,12 +952,12 @@ func OverviewProjectsSection(projects []TabloCardView) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var29 := templ.GetChildren(ctx) - if templ_7745c5c3_Var29 == nil { - templ_7745c5c3_Var29 = templ.NopComponent + templ_7745c5c3_Var31 := templ.GetChildren(ctx) + if templ_7745c5c3_Var31 == nil { + templ_7745c5c3_Var31 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "

Mes Projets

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "

Mes Projets

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -887,7 +976,7 @@ func OverviewProjectsSection(projects []TabloCardView) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -895,7 +984,7 @@ func OverviewProjectsSection(projects []TabloCardView) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -923,39 +1012,39 @@ func SeeMoreProjects(hiddenCount int) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var30 := templ.GetChildren(ctx) - if templ_7745c5c3_Var30 == nil { - templ_7745c5c3_Var30 = templ.NopComponent + templ_7745c5c3_Var32 := templ.GetChildren(ctx) + if templ_7745c5c3_Var32 == nil { + templ_7745c5c3_Var32 = templ.NopComponent } ctx = templ.ClearChildren(ctx) if hiddenCount > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, " de plus ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -980,12 +1069,12 @@ func OverviewProjectsScript() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var33 := templ.GetChildren(ctx) - if templ_7745c5c3_Var33 == nil { - templ_7745c5c3_Var33 = templ.NopComponent + templ_7745c5c3_Var35 := templ.GetChildren(ctx) + if templ_7745c5c3_Var35 == nil { + templ_7745c5c3_Var35 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1009,12 +1098,12 @@ func OverviewTasks(tasks []dashboardTask) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var34 := templ.GetChildren(ctx) - if templ_7745c5c3_Var34 == nil { - templ_7745c5c3_Var34 = templ.NopComponent + templ_7745c5c3_Var36 := templ.GetChildren(ctx) + if templ_7745c5c3_Var36 == nil { + templ_7745c5c3_Var36 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "

Mes Tâches

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "

Mes Tâches

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1024,7 +1113,7 @@ func OverviewTasks(tasks []dashboardTask) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1048,12 +1137,12 @@ func QuickActionCard(action quickAction) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var35 := templ.GetChildren(ctx) - if templ_7745c5c3_Var35 == nil { - templ_7745c5c3_Var35 = templ.NopComponent + templ_7745c5c3_Var37 := templ.GetChildren(ctx) + if templ_7745c5c3_Var37 == nil { + templ_7745c5c3_Var37 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1111,39 +1200,17 @@ func TaskRow(task dashboardTask) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var38 := templ.GetChildren(ctx) - if templ_7745c5c3_Var38 == nil { - templ_7745c5c3_Var38 = templ.NopComponent + templ_7745c5c3_Var40 := templ.GetChildren(ctx) + if templ_7745c5c3_Var40 == nil { + templ_7745c5c3_Var40 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - var templ_7745c5c3_Var39 = []any{taskRowClass(task.Completed)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var39...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var41 = []any{taskCheckClass(task.Completed)} + var templ_7745c5c3_Var41 = []any{taskRowClass(task.Completed)} templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var41...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var43 string - templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(task.Title) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 338, Col: 18} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var44 = []any{"task-project-badge " + projectAccentClass(task.ProjectHue)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var44...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var45 string - templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var44).String()) + templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(task.Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 1, Col: 0} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 358, Col: 18} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var45) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "\">") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var46 string - templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(task.ProjectKey) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 341, Col: 28} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46)) + var templ_7745c5c3_Var46 = []any{"task-project-badge " + projectAccentClass(task.ProjectHue)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var46...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var48 string - templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(task.Date) + templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(task.ProjectKey) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 344, Col: 39} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 361, Col: 28} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var49 = []any{"task-status " + toneClass(task.StatusTone)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var49...) + var templ_7745c5c3_Var49 string + templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(task.Project) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 363, Col: 50} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var50 string - templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var49).String()) + templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(task.Date) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 364, Col: 39} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var51 = []any{"task-status " + toneClass(task.StatusTone)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var51...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var51 string - templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(task.Status) + var templ_7745c5c3_Var53 string + templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinStringErrs(task.Status) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 347, Col: 75} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 367, Col: 75} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1299,69 +1388,69 @@ func SidebarNavItem(item sidebarNavItem) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var52 := templ.GetChildren(ctx) - if templ_7745c5c3_Var52 == nil { - templ_7745c5c3_Var52 = templ.NopComponent + templ_7745c5c3_Var54 := templ.GetChildren(ctx) + if templ_7745c5c3_Var54 == nil { + templ_7745c5c3_Var54 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - var templ_7745c5c3_Var53 = []any{sidebarNavItemClass(item.Active)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var53...) + var templ_7745c5c3_Var55 = []any{sidebarNavItemClass(item.Active)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var55...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1406,69 +1495,69 @@ func SidebarNavItemOOB(item sidebarNavItem) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var59 := templ.GetChildren(ctx) - if templ_7745c5c3_Var59 == nil { - templ_7745c5c3_Var59 = templ.NopComponent + templ_7745c5c3_Var61 := templ.GetChildren(ctx) + if templ_7745c5c3_Var61 == nil { + templ_7745c5c3_Var61 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - var templ_7745c5c3_Var60 = []any{sidebarNavItemClass(item.Active)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var60...) + var templ_7745c5c3_Var62 = []any{sidebarNavItemClass(item.Active)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var62...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1513,25 +1602,25 @@ func SidebarProjectItem(item sidebarProjectItem) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var66 := templ.GetChildren(ctx) - if templ_7745c5c3_Var66 == nil { - templ_7745c5c3_Var66 = templ.NopComponent + templ_7745c5c3_Var68 := templ.GetChildren(ctx) + if templ_7745c5c3_Var68 == nil { + templ_7745c5c3_Var68 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1539,20 +1628,20 @@ func SidebarProjectItem(item sidebarProjectItem) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var68 string - templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label) + var templ_7745c5c3_Var70 string + templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 382, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/dashboard_components.templ`, Line: 402, Col: 50} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/go-backend/internal/web/views/dashboard_components_test.go b/go-backend/internal/web/views/dashboard_components_test.go index 7d67bd5..4a9ce94 100644 --- a/go-backend/internal/web/views/dashboard_components_test.go +++ b/go-backend/internal/web/views/dashboard_components_test.go @@ -16,7 +16,7 @@ func TestOverviewProjectsFromTablosCarriesColorAndEditURL(t *testing.T) { record := tablomodel.Record{ ID: uuid.MustParse("11111111-1111-1111-1111-111111111111"), Name: "Palette", - Color: "#3B82F6", + Color: "#22C55E", Status: tablomodel.StatusTodo, CreatedAt: time.Date(2026, time.May, 10, 9, 0, 0, 0, time.UTC), } @@ -27,7 +27,7 @@ func TestOverviewProjectsFromTablosCarriesColorAndEditURL(t *testing.T) { } project := projects[0] - if project.Color != "#3B82F6" { + if project.Color != "#22C55E" { t.Fatalf("expected color to be preserved, got %q", project.Color) } if project.EditRequestURL != "/tablos/11111111-1111-1111-1111-111111111111/edit" { @@ -36,13 +36,16 @@ func TestOverviewProjectsFromTablosCarriesColorAndEditURL(t *testing.T) { if project.CardDateLabel != "10 mai 2026" { t.Fatalf("expected French card date label, got %q", project.CardDateLabel) } + if project.IconKind != "leaf" { + t.Fatalf("expected color presentation icon to be preserved, got %q", project.IconKind) + } } func TestOverviewProjectsSectionRendersColorAndEditAction(t *testing.T) { record := tablomodel.Record{ ID: uuid.MustParse("11111111-1111-1111-1111-111111111111"), Name: "Palette", - Color: "#3B82F6", + Color: "#22C55E", Status: tablomodel.StatusTodo, CreatedAt: time.Date(2026, time.May, 10, 9, 0, 0, 0, time.UTC), } @@ -50,9 +53,10 @@ func TestOverviewProjectsSectionRendersColorAndEditAction(t *testing.T) { html := renderViewToString(t, OverviewProjectsSection(OverviewProjectsFromTablos([]tablomodel.Record{record}))) for _, want := range []string{ - `style="--project-color:#3B82F6;"`, + `style="--project-color:#22C55E;"`, `aria-label="Modifier le projet"`, `hx-get="/tablos/11111111-1111-1111-1111-111111111111/edit"`, + ``, } { if !strings.Contains(html, want) { t.Fatalf("expected %q in %q", want, html) @@ -83,6 +87,36 @@ func TestTabloListRowRendersLeafIconKind(t *testing.T) { } } +func TestSidebarProjectItemsUsesFirstFourRealTablos(t *testing.T) { + tablos := []tablomodel.Record{ + {ID: uuid.MustParse("11111111-1111-1111-1111-111111111111"), Name: "Alpha", Color: "#3B82F6"}, + {ID: uuid.MustParse("22222222-2222-2222-2222-222222222222"), Name: "Beta", Color: "#22C55E"}, + {ID: uuid.MustParse("33333333-3333-3333-3333-333333333333"), Name: "Gamma", Color: "#A855F7"}, + {ID: uuid.MustParse("44444444-4444-4444-4444-444444444444"), Name: "Delta", Color: "#EF4444"}, + {ID: uuid.MustParse("55555555-5555-5555-5555-555555555555"), Name: "Epsilon", Color: "#EAB308"}, + } + + items := sidebarProjectItems(tablos) + if len(items) != 4 { + t.Fatalf("expected 4 sidebar items, got %d", len(items)) + } + + for i, want := range []struct { + href string + label string + icon string + }{ + {href: "/tablos/11111111-1111-1111-1111-111111111111", label: "Alpha", icon: "bolt"}, + {href: "/tablos/22222222-2222-2222-2222-222222222222", label: "Beta", icon: "leaf"}, + {href: "/tablos/33333333-3333-3333-3333-333333333333", label: "Gamma", icon: "gem"}, + {href: "/tablos/44444444-4444-4444-4444-444444444444", label: "Delta", icon: "flame"}, + } { + if items[i].Href != want.href || items[i].Label != want.label || items[i].Icon != want.icon { + t.Fatalf("item %d = %#v, want href=%q label=%q icon=%q", i, items[i], want.href, want.label, want.icon) + } + } +} + func TestTabloListRowDoesNotRenderSpacerBetweenEditAndDelete(t *testing.T) { component := TabloListRow(TabloCardView{ ID: "11111111-1111-1111-1111-111111111111", diff --git a/go-backend/internal/web/views/home.go b/go-backend/internal/web/views/home.go index a7de2eb..e190716 100644 --- a/go-backend/internal/web/views/home.go +++ b/go-backend/internal/web/views/home.go @@ -7,6 +7,7 @@ import ( tablomodel "xtablo-backend/internal/tablos" "xtablo-backend/internal/web/dates" + "xtablo-backend/internal/web/tabloicons" "github.com/a-h/templ" ) @@ -112,6 +113,7 @@ func OverviewProjectsFromTablos(tablos []tablomodel.Record) []TabloCardView { projects := make([]TabloCardView, 0, len(tablos)) for _, tablo := range tablos { statusLabel, statusTone, progress := overviewProjectStatus(tablo.Status) + presentation := tabloicons.ForColor(tablo.Color) projects = append(projects, TabloCardView{ ID: tablo.ID.String(), Name: tablo.Name, @@ -119,8 +121,9 @@ func OverviewProjectsFromTablos(tablos []tablomodel.Record) []TabloCardView { Status: string(tablo.Status), StatusLabel: statusLabel, StatusTone: statusTone, + IconKind: presentation.Icon, Initial: projectInitial(tablo.Name), - Accent: overviewProjectAccent(tablo.Name), + Accent: presentation.Accent, CardDateLabel: dates.FormatFrenchDate(tablo.CreatedAt), Progress: progress, ProgressLabel: progressPercentLabel(progress), @@ -163,13 +166,21 @@ func sidebarPrimaryNavItems(activePath string) []sidebarNavItem { } } -func sidebarProjectItems() []sidebarProjectItem { - return []sidebarProjectItem{ - {Href: "/tablos/hello", Label: "Hello", Icon: "bolt"}, - {Href: "/tablos/atelier", Label: "Atelier Produit", Icon: "gem"}, - {Href: "/tablos/arthur", Label: "Arthur Belleville", Icon: "bolt"}, - {Href: "/tablos/equipe", Label: "Equipe Design", Icon: "bolt"}, +func sidebarProjectItems(tablos []tablomodel.Record) []sidebarProjectItem { + limit := len(tablos) + if limit > 4 { + limit = 4 } + + items := make([]sidebarProjectItem, 0, limit) + for _, tablo := range tablos[:limit] { + items = append(items, sidebarProjectItem{ + Href: fmt.Sprintf("/tablos/%s", tablo.ID), + Label: tablo.Name, + Icon: tabloicons.ForColor(tablo.Color).Icon, + }) + } + return items } func sidebarFooterNavItems(activePath string) []sidebarNavItem { @@ -233,17 +244,6 @@ func overviewProjectStatus(status tablomodel.Status) (string, string, int) { } } -func overviewProjectAccent(name string) string { - switch len(strings.TrimSpace(name)) % 3 { - case 1: - return "purple" - case 2: - return "red" - default: - return "blue" - } -} - func projectInitial(name string) string { name = strings.TrimSpace(name) if name == "" { diff --git a/go-backend/internal/web/views/tablos.templ b/go-backend/internal/web/views/tablos.templ index 589ea28..c943e63 100644 --- a/go-backend/internal/web/views/tablos.templ +++ b/go-backend/internal/web/views/tablos.templ @@ -189,7 +189,11 @@ templ TabloGridCardWithAttrs(tablo TabloCardView, attrs templ.Attributes) {
- { tablo.Initial } + if tablo.IconKind != "" { + @ActionIcon(tablo.IconKind) + } else { + { tablo.Initial } + }

{ tablo.Name }

diff --git a/go-backend/internal/web/views/tablos_templ.go b/go-backend/internal/web/views/tablos_templ.go index 7598de5..68af53a 100644 --- a/go-backend/internal/web/views/tablos_templ.go +++ b/go-backend/internal/web/views/tablos_templ.go @@ -569,33 +569,48 @@ func TabloGridCardWithAttrs(tablo TabloCardView, attrs templ.Attributes) templ.C if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var22 string - templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(tablo.Initial) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 192, Col: 25} + if tablo.IconKind != "" { + templ_7745c5c3_Err = ActionIcon(tablo.IconKind).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var22 string + templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(tablo.Initial) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 195, Col: 26} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var23 string templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(tablo.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 194, Col: 19} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 198, Col: 19} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -603,46 +618,46 @@ func TabloGridCardWithAttrs(tablo TabloCardView, attrs templ.Attributes) templ.C if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var24 string templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(tablo.CardDateLabel) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 198, Col: 30} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 202, Col: 30} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
Progression: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
Progression: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var25 string templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(tablo.ProgressLabel) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 203, Col: 33} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 207, Col: 33} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "\">
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -671,33 +686,33 @@ func TabloListRow(tablo TabloCardView) templ.Component { templ_7745c5c3_Var27 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "
svg]:w-4 [&>svg]:h-4\">") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "\">
svg]:w-4 [&>svg]:h-4\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -705,20 +720,20 @@ func TabloListRow(tablo TabloCardView) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var30 string templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(tablo.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 219, Col: 84} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 223, Col: 84} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -729,7 +744,7 @@ func TabloListRow(tablo TabloCardView) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "
svg]:w-4 [&>svg]:h-4 [&>svg]:shrink-0\">") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "
svg]:w-4 [&>svg]:h-4 [&>svg]:shrink-0\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -740,39 +755,39 @@ func TabloListRow(tablo TabloCardView) templ.Component { var templ_7745c5c3_Var31 string templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(tablo.CreatedAtLabel) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 231, Col: 26} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 235, Col: 26} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "\">
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var33 string templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(tablo.ProgressLabel) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 239, Col: 109} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 243, Col: 109} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -784,7 +799,7 @@ func TabloListRow(tablo TabloCardView) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -845,7 +860,7 @@ func InitProjectFilterScript() templ.Component { templ_7745c5c3_Var35 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -874,7 +889,7 @@ func TabloListHead() templ.Component { templ_7745c5c3_Var36 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "ProjetStatutCréé leProgression") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "ProjetStatutCréé leProgression") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -934,51 +949,51 @@ func CreateTabloModalBody(vm TablosPageViewModel) templ.Component { templ_7745c5c3_Var38 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "\"> ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if vm.ErrorMessage != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var41 string templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(vm.ErrorMessage) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 335, Col: 112} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 339, Col: 112} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1015,33 +1030,33 @@ func CreateTabloModalBody(vm TablosPageViewModel) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "
Annuler") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "\" hx-target=\"#app-main-content\" hx-swap=\"outerHTML\" hx-push-url=\"true\" class=\"ui-button ui-button-solid ui-button-neutral ui-button-md\">Annuler") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1054,7 +1069,7 @@ func CreateTabloModalBody(vm TablosPageViewModel) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1115,7 +1130,7 @@ func EditTabloColorField(vm TablosPageViewModel) templ.Component { templ_7745c5c3_Var45 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1134,20 +1149,20 @@ func EditTabloColorField(vm TablosPageViewModel) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "\" class=\"ui-input tablo-color-picker\" oninput=\"document.getElementById('edit-tablo-color').value=this.value\">
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1176,64 +1191,64 @@ func EditTabloModalBody(vm TablosPageViewModel) templ.Component { templ_7745c5c3_Var47 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "\"> ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if vm.ErrorMessage != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var51 string templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(vm.ErrorMessage) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 425, Col: 112} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views/tablos.templ`, Line: 429, Col: 112} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1261,33 +1276,33 @@ func EditTabloModalBody(vm TablosPageViewModel) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "
Annuler") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "\" hx-target=\"#app-main-content\" hx-swap=\"outerHTML\" hx-push-url=\"true\" class=\"ui-button ui-button-solid ui-button-neutral ui-button-md\">Annuler") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1300,7 +1315,7 @@ func EditTabloModalBody(vm TablosPageViewModel) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/go-backend/static/styles.css b/go-backend/static/styles.css index bc2a6a9..9b89ab0 100644 --- a/go-backend/static/styles.css +++ b/go-backend/static/styles.css @@ -1909,6 +1909,11 @@ td.text-right .borderless-icon-button.ui-icon-button-ghost.ui-icon-button-danger width: 3rem; } +.project-avatar > svg { + height: 1.25rem; + width: 1.25rem; +} + .project-list-icon { background: var(--project-color, var(--color-project-fallback)); color: var(--color-text-inverse);