Replaces the OS/window icon with the new dark-background logo design, and derives a transparent shield-mark cutout (via chroma-key against the flat background) for the in-app login/sidebar mark and the web loading-screen logo. Brand.ranaze_mark_texture() no longer needs the AtlasTexture crop since the new source asset is already tightly cropped to the mark.
193 lines
6.3 KiB
GDScript
193 lines
6.3 KiB
GDScript
extends RefCounted
|
|
|
|
const DEEP_NAVY := Color("0b1324")
|
|
const ROYAL_BLUE := Color("2563eb")
|
|
const SKY_BLUE := Color("38bdf8")
|
|
const PURPLE := Color("1d4ed8")
|
|
const MAGENTA := Color("ef4444")
|
|
const TEAL := Color("38bdf8")
|
|
const SUCCESS := Color("22c55e")
|
|
const AMBER := Color("f59e0b")
|
|
const SUN_ICON := preload("res://assets/icons/lucide/sun.svg")
|
|
const MOON_ICON := preload("res://assets/icons/lucide/moon.svg")
|
|
const SLATE := Color("94a3b8")
|
|
const DARK_TEXT := Color("f8fafc")
|
|
const LIGHT_TEXT := Color("0f172a")
|
|
const LIGHT_BACKGROUND := Color("f1f5f9")
|
|
const LIGHT_SURFACE := Color("ffffff")
|
|
const LIGHT_SURFACE_SUBTLE := Color("f8fafc")
|
|
const LIGHT_BORDER := Color("dbe3ef")
|
|
const LIGHT_MUTED := Color("64748b")
|
|
|
|
static var font: Font = preload("res://assets/fonts/Inter-Variable.ttf")
|
|
|
|
|
|
static func ranaze_mark_texture() -> Texture2D:
|
|
return preload("res://assets/branding/ranaze-mark.png")
|
|
|
|
|
|
static func text_color(dark: bool) -> Color:
|
|
return DARK_TEXT if dark else LIGHT_TEXT
|
|
|
|
|
|
static func muted_color(dark: bool) -> Color:
|
|
return Color("a9b5ca") if dark else LIGHT_MUTED
|
|
|
|
|
|
static func background_color(dark: bool) -> Color:
|
|
return DEEP_NAVY if dark else LIGHT_BACKGROUND
|
|
|
|
|
|
static func background_material(dark: bool) -> ShaderMaterial:
|
|
var shader := Shader.new()
|
|
shader.code = """
|
|
shader_type canvas_item;
|
|
uniform bool dark_mode = true;
|
|
|
|
void fragment() {
|
|
vec2 uv = UV;
|
|
vec3 base = dark_mode ? vec3(0.018, 0.043, 0.090) : vec3(0.965, 0.975, 0.990);
|
|
float left_glow = 1.0 - smoothstep(0.0, 0.58, distance(uv, vec2(-0.02, 0.12)));
|
|
float right_glow = 1.0 - smoothstep(0.0, 0.58, distance(uv, vec2(1.02, 0.92)));
|
|
vec3 blue = dark_mode ? vec3(0.035, 0.16, 0.42) : vec3(0.70, 0.84, 1.0);
|
|
vec3 purple = dark_mode ? vec3(0.02, 0.28, 0.55) : vec3(0.76, 0.90, 1.0);
|
|
vec3 color = base + blue * left_glow * (dark_mode ? 0.55 : 0.28);
|
|
color += purple * right_glow * (dark_mode ? 0.62 : 0.12);
|
|
COLOR = vec4(color, 1.0);
|
|
}
|
|
"""
|
|
var material := ShaderMaterial.new()
|
|
material.shader = shader
|
|
material.set_shader_parameter("dark_mode", dark)
|
|
return material
|
|
|
|
|
|
static func logo_cutout_material() -> ShaderMaterial:
|
|
var shader := Shader.new()
|
|
shader.code = """
|
|
shader_type canvas_item;
|
|
|
|
void fragment() {
|
|
vec4 source = texture(TEXTURE, UV);
|
|
float brightness = max(source.r, max(source.g, source.b));
|
|
float alpha = smoothstep(0.10, 0.24, brightness);
|
|
COLOR = vec4(source.rgb, source.a * alpha);
|
|
}
|
|
"""
|
|
var material := ShaderMaterial.new()
|
|
material.shader = shader
|
|
return material
|
|
|
|
|
|
static func panel_box(dark: bool) -> StyleBoxFlat:
|
|
var box := StyleBoxFlat.new()
|
|
box.bg_color = Color("0b1427cc") if dark else LIGHT_SURFACE
|
|
box.border_color = Color("33415d") if dark else LIGHT_BORDER
|
|
box.set_border_width_all(1)
|
|
box.set_corner_radius_all(26)
|
|
if not dark:
|
|
box.shadow_color = Color(0.15, 0.23, 0.38, 0.12)
|
|
box.shadow_size = 12
|
|
box.content_margin_left = 64
|
|
box.content_margin_right = 64
|
|
box.content_margin_top = 62
|
|
box.content_margin_bottom = 48
|
|
return box
|
|
|
|
|
|
static func field_box(dark: bool, focused: bool = false) -> StyleBoxFlat:
|
|
var box := StyleBoxFlat.new()
|
|
box.bg_color = Color("0d172a") if dark else LIGHT_SURFACE
|
|
box.border_color = ROYAL_BLUE if focused else (Color("33415d") if dark else LIGHT_BORDER)
|
|
box.set_border_width_all(1)
|
|
box.set_corner_radius_all(10)
|
|
box.content_margin_left = 22
|
|
box.content_margin_right = 22
|
|
box.content_margin_top = 18
|
|
box.content_margin_bottom = 18
|
|
return box
|
|
|
|
|
|
static func secondary_button_box(dark: bool, hover: bool = false) -> StyleBoxFlat:
|
|
var box := field_box(dark, hover)
|
|
box.bg_color = Color("111b30") if dark else Color("ffffff")
|
|
return box
|
|
|
|
|
|
static func shell_box(dark: bool, edge: String) -> StyleBoxFlat:
|
|
var box := StyleBoxFlat.new()
|
|
box.bg_color = Color("071224") if dark else LIGHT_SURFACE
|
|
box.border_color = Color("1c2b49") if dark else LIGHT_BORDER
|
|
if edge == "right":
|
|
box.border_width_right = 1
|
|
elif edge == "bottom":
|
|
box.border_width_bottom = 1
|
|
return box
|
|
|
|
|
|
static func content_card_box(dark: bool, active: bool, accent: Color = ROYAL_BLUE) -> StyleBoxFlat:
|
|
var box := StyleBoxFlat.new()
|
|
box.bg_color = (Color("07192c") if active else Color("11182e")) if dark else LIGHT_SURFACE
|
|
box.border_color = accent if active else (Color("2a365a") if dark else LIGHT_BORDER)
|
|
box.set_border_width_all(1)
|
|
box.set_corner_radius_all(12)
|
|
if not dark:
|
|
box.shadow_color = Color(0.15, 0.23, 0.38, 0.06)
|
|
box.shadow_size = 5
|
|
return box
|
|
|
|
|
|
static func icon_circle_box(dark: bool, accent: Color, radius: int, filled: bool = false) -> StyleBoxFlat:
|
|
var box := StyleBoxFlat.new()
|
|
box.bg_color = Color(accent, 0.62 if filled else (0.06 if dark else 0.045))
|
|
box.border_color = Color(accent, 0.48 if dark else 0.18)
|
|
box.set_border_width_all(1)
|
|
box.set_corner_radius_all(radius)
|
|
# A perfectly circular StyleBoxFlat (radius == half the box size, no straight edges
|
|
# between corners) is a known Godot degenerate case that can draw a faint seam through
|
|
# the middle when antialiasing is on; more corner segments plus disabling AA renders a
|
|
# clean circle instead at these small badge sizes.
|
|
box.corner_detail = 20
|
|
box.anti_aliasing = false
|
|
return box
|
|
|
|
|
|
static func badge_box(dark: bool, accent: Color) -> StyleBoxFlat:
|
|
var box := StyleBoxFlat.new()
|
|
box.bg_color = Color(accent, 0.12 if dark else 0.09)
|
|
box.set_corner_radius_all(7)
|
|
box.content_margin_left = 10
|
|
box.content_margin_right = 10
|
|
box.content_margin_top = 5
|
|
box.content_margin_bottom = 5
|
|
return box
|
|
|
|
|
|
static func gradient_button_box() -> StyleBoxTexture:
|
|
var gradient := Gradient.new()
|
|
gradient.colors = PackedColorArray([ROYAL_BLUE, SKY_BLUE])
|
|
var texture := GradientTexture2D.new()
|
|
texture.gradient = gradient
|
|
texture.width = 512
|
|
texture.height = 64
|
|
texture.fill_from = Vector2(0, 0.5)
|
|
texture.fill_to = Vector2(1, 0.5)
|
|
var box := StyleBoxTexture.new()
|
|
box.texture = texture
|
|
box.content_margin_top = 18
|
|
box.content_margin_bottom = 18
|
|
return box
|
|
|
|
|
|
static func apply_font(control: Control) -> void:
|
|
control.add_theme_font_override("font", font)
|
|
|
|
|
|
static func set_theme_toggle_icon(button: Button, dark: bool) -> void:
|
|
button.text = ""
|
|
button.icon = SUN_ICON if dark else MOON_ICON
|
|
button.expand_icon = false
|
|
button.add_theme_constant_override("icon_max_width", 22)
|
|
for color_name in ["icon_normal_color", "icon_hover_color", "icon_pressed_color", "icon_focus_color"]:
|
|
button.add_theme_color_override(color_name, AMBER)
|