local PANEL = {} local COLOR_BG = Color(30, 30, 30, 240) local COLOR_HEADER = Color(20, 20, 20, 255) local COLOR_ACCENT = Color(200, 50, 50) -- Red for warnings local COLOR_TEXT = Color(240, 240, 240) local COLOR_TEXT_DIM = Color(180, 180, 180) function PANEL:Init() self:SetSize(ScrW() * 0.6, ScrH() * 0.7) self:Center() self:MakePopup() self:SetTitle("") self:ShowCloseButton(false) self.admins = {} self.warns = {} -- Close Button local closeBtn = self:Add("DButton") closeBtn:SetSize(40, 30) closeBtn:SetPos(self:GetWide() - 40, 0) closeBtn:SetText("X") closeBtn:SetFont("ixMediumFont") closeBtn:SetTextColor(COLOR_TEXT) closeBtn.Paint = function(s, w, h) if (s:IsHovered()) then draw.RoundedBox(0, 0, 0, w, h, Color(200, 50, 50)) end end closeBtn.DoClick = function() self:Close() end -- Container self.container = self:Add("Panel") self.container:Dock(FILL) self.container:DockMargin(10, 35, 10, 10) -- Left: Admin List self.leftPanel = self.container:Add("Panel") self.leftPanel:Dock(LEFT) self.leftPanel:SetWide(self:GetWide() * 0.4) self.leftPanel:DockMargin(0, 0, 10, 0) self.scroll = self.leftPanel:Add("DScrollPanel") self.scroll:Dock(FILL) -- Right: Details & History self.rightPanel = self.container:Add("Panel") self.rightPanel:Dock(FILL) self.rightPanel.Paint = function(s, w, h) draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40, 255)) end self.details = self.rightPanel:Add("Panel") self.details:Dock(TOP) self.details:SetTall(150) self.details:DockPadding(15, 15, 15, 15) self.historyScroll = self.rightPanel:Add("DScrollPanel") self.historyScroll:Dock(FILL) self.historyScroll:DockMargin(10, 10, 10, 10) self.noSelected = self.rightPanel:Add("DLabel") self.noSelected:SetText("Выберите администратора из списка слева") self.noSelected:SetFont("ixMediumFont") self.noSelected:Dock(FILL) self.noSelected:SetContentAlignment(5) self.noSelected:SetTextColor(COLOR_TEXT_DIM) end function PANEL:Populate(admins, warns) self.admins = admins self.warns = warns local sortedAdmins = {} for k, v in pairs(admins) do table.insert(sortedAdmins, v) end table.sort(sortedAdmins, function(a, b) if (a.online != b.online) then return a.online end return a.name < b.name end) for _, admin in ipairs(sortedAdmins) do local btn = self.scroll:Add("DButton") btn:Dock(TOP) btn:SetTall(50) btn:DockMargin(0, 0, 0, 5) btn:SetText("") local warnCount = (warns[admin.steamID] and warns[admin.steamID].count) or 0 btn.Paint = function(s, w, h) local bg = s:IsHovered() and Color(60, 60, 60) or Color(45, 45, 45) draw.RoundedBox(4, 0, 0, w, h, bg) -- Online/Offline Indicator surface.SetDrawColor(admin.online and Color(100, 255, 100) or Color(150, 150, 150)) surface.DrawRect(3, 3, 4, h - 6) draw.SimpleText(admin.name, "ixMediumFont", 15, h/2 - 8, COLOR_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) draw.SimpleText(admin.rank, "ixSmallFont", 15, h/2 + 10, COLOR_TEXT_DIM, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) local warnCol = warnCount > 0 and COLOR_ACCENT or COLOR_TEXT_DIM draw.SimpleText("Warns: " .. warnCount .. "/3", "ixMediumFont", w - 15, h/2, warnCol, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) end btn.DoClick = function() self:ShowAdminDetails(admin) end end end function PANEL:ShowAdminDetails(admin) self.noSelected:SetVisible(false) self.details:Clear() self.historyScroll:Clear() local name = self.details:Add("DLabel") name:SetText(admin.name) name:SetFont("ixMediumFont") -- Fixed font name:Dock(TOP) name:SetTextColor(COLOR_TEXT) name:SizeToContents() local steamid = self.details:Add("DLabel") steamid:SetText(admin.steamID) steamid:SetFont("ixSmallFont") steamid:Dock(TOP) steamid:SetTextColor(COLOR_TEXT_DIM) steamid:SetMouseInputEnabled(true) steamid:SetCursor("hand") steamid.DoClick = function() SetClipboardText(admin.steamID) surface.PlaySound("ui/buttonclick.wav") LocalPlayer():Notify("SteamID скопирован: " .. admin.steamID) end local actionPanel = self.details:Add("Panel") actionPanel:Dock(BOTTOM) actionPanel:SetTall(40) local addWarn = actionPanel:Add("ixMenuButton") addWarn:SetText("ВЫДАТЬ ВЫГОВОР") addWarn:Dock(LEFT) addWarn:SetWide(150) addWarn.DoClick = function() Derma_StringRequest("Выдача выговора", "Введите причину выговора для " .. admin.name, "", function(text) net.Start("ixWarnAdd") net.WriteString(admin.steamID) net.WriteString(text) net.SendToServer() self:Close() end) end -- History local warnData = self.warns[admin.steamID] if (warnData and warnData.history) then for i = #warnData.history, 1, -1 do local h = warnData.history[i] local entry = self.historyScroll:Add("Panel") entry:Dock(TOP) entry:SetTall(60) entry:DockMargin(0, 0, 0, 5) entry.Paint = function(s, w, h_tall) draw.RoundedBox(4, 0, 0, w, h_tall, Color(50, 50, 50)) local typeText = h.type == "add" and "[ВЫДАНО]" or "[СНЯТО]" local typeCol = h.type == "add" and COLOR_ACCENT or Color(100, 200, 100) draw.SimpleText(typeText .. " От: " .. h.admin, "ixSmallFont", 10, 15, typeCol) draw.SimpleText(os.date("%d/%m/%Y %H:%M", h.time), "ixSmallFont", w - 10, 15, COLOR_TEXT_DIM, TEXT_ALIGN_RIGHT) draw.SimpleText(h.reason, "ixMediumFont", 10, 40, COLOR_TEXT) end if (h.type == "add" and admin.online) then local remove = entry:Add("DButton") remove:SetText("Снять") remove:SetSize(60, 20) remove:SetPos(self.historyScroll:GetWide() - 70, 35) remove.DoClick = function() net.Start("ixWarnRemove") net.WriteString(admin.steamID) net.WriteInt(i, 16) net.SendToServer() self:Close() end end end end end function PANEL:Paint(w, h) draw.RoundedBox(4, 0, 0, w, h, COLOR_BG) draw.RoundedBoxEx(4, 0, 0, w, 30, COLOR_HEADER, true, true, false, false) draw.SimpleText("СИСТЕМА ВЫГОВОРОВ (WARN SYSTEM)", "ixMediumFont", 10, 15, COLOR_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end vgui.Register("ixWarnMenu", PANEL, "DFrame")