This commit is contained in:
@@ -172,30 +172,101 @@
|
|||||||
<ValidationMessage For="() => _application.Platforms" />
|
<ValidationMessage For="() => _application.Platforms" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Skills & What You Bring -->
|
<!-- Role-Specific Assessment -->
|
||||||
<div class="dev-section">
|
@if (_application.Role == ApplicationRole.Tester)
|
||||||
<h2 class="dev-section-title">What You Bring</h2>
|
{
|
||||||
<p class="dev-section-desc">Tell us about your skills and what you'd bring to the team.</p>
|
<div class="dev-section">
|
||||||
|
<h2 class="dev-section-title">About Your Experience</h2>
|
||||||
|
<p class="dev-section-desc">Help us understand your background — there are no wrong answers.</p>
|
||||||
|
|
||||||
@if (_application.Role == ApplicationRole.Developer)
|
<div class="form-group" style="margin-bottom: 1.5rem;">
|
||||||
{
|
<label>How well do you understand the internet and online services?</label>
|
||||||
<div class="form-group" style="margin-bottom: 1.25rem;">
|
<div class="star-rating">
|
||||||
<label for="skills">Technical Skills</label>
|
@for (int i = 1; i <= 5; i++)
|
||||||
<InputTextArea id="skills" @bind-Value="_application.Skills" class="form-input form-textarea"
|
{
|
||||||
placeholder="e.g. C#/.NET 5 years, Blazor, PostgreSQL, Docker, contributed to..." rows="4" />
|
var rating = i;
|
||||||
<span class="form-hint">Languages, frameworks, tools, and any open-source contributions</span>
|
<span class="star-rating-star @(rating <= (_internetHover > 0 ? _internetHover : (_application.InternetUnderstanding ?? 0)) ? "star-filled" : "")"
|
||||||
|
@onclick="() => _application.InternetUnderstanding = rating"
|
||||||
|
@onmouseover="() => _internetHover = rating"
|
||||||
|
@onmouseout="() => _internetHover = 0">@(rating <= (_internetHover > 0 ? _internetHover : (_application.InternetUnderstanding ?? 0)) ? "\u2605" : "\u2606")</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="rating-labels">
|
||||||
|
<span>Beginner</span>
|
||||||
|
<span>Expert</span>
|
||||||
|
</div>
|
||||||
|
<ValidationMessage For="() => _application.InternetUnderstanding" />
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group" style="margin-bottom: 1.5rem;">
|
||||||
<label for="motivation">How will you contribute?</label>
|
<label>How much do you enjoy trying new software and finding issues?</label>
|
||||||
<InputTextArea id="motivation" @bind-Value="_application.Motivation" class="form-input form-textarea"
|
<div class="star-rating">
|
||||||
placeholder="@(_application.Role == ApplicationRole.Developer
|
@for (int i = 1; i <= 5; i++)
|
||||||
? "What areas interest you? Architecture, frontend, backend, DevOps, security..."
|
{
|
||||||
: "What devices/platforms can you test on? What kind of testing experience do you have?")" rows="4" />
|
var rating = i;
|
||||||
<ValidationMessage For="() => _application.Motivation" />
|
<span class="star-rating-star @(rating <= (_testingHover > 0 ? _testingHover : (_application.EnjoysTesting ?? 0)) ? "star-filled" : "")"
|
||||||
|
@onclick="() => _application.EnjoysTesting = rating"
|
||||||
|
@onmouseover="() => _testingHover = rating"
|
||||||
|
@onmouseout="() => _testingHover = 0">@(rating <= (_testingHover > 0 ? _testingHover : (_application.EnjoysTesting ?? 0)) ? "\u2605" : "\u2606")</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="rating-labels">
|
||||||
|
<span>Not really</span>
|
||||||
|
<span>Love it</span>
|
||||||
|
</div>
|
||||||
|
<ValidationMessage For="() => _application.EnjoysTesting" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="additionalNotes">Anything else you'd like us to know? (optional)</label>
|
||||||
|
<InputTextArea id="additionalNotes" @bind-Value="_application.AdditionalNotes" class="form-input form-textarea"
|
||||||
|
placeholder="Previous testing experience, specific interests, etc." rows="3" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="dev-section">
|
||||||
|
<h2 class="dev-section-title">Your Skills</h2>
|
||||||
|
<p class="dev-section-desc">Select your experience level and the technologies you work with.</p>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-bottom: 1.5rem;">
|
||||||
|
<label>Experience Level</label>
|
||||||
|
<div class="experience-selector">
|
||||||
|
@foreach (var range in SkillCatalog.ExperienceRanges)
|
||||||
|
{
|
||||||
|
<button type="button"
|
||||||
|
class="exp-btn @(_application.ExperienceRange == range ? "exp-active" : "")"
|
||||||
|
@onclick="() => _application.ExperienceRange = range">@range</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<ValidationMessage For="() => _application.ExperienceRange" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-bottom: 1.5rem;">
|
||||||
|
<label>Technologies (select all that apply)</label>
|
||||||
|
@foreach (var category in SkillCatalog.SkillCategories)
|
||||||
|
{
|
||||||
|
<div class="skill-category-label">@category.Key</div>
|
||||||
|
<div class="skill-bubbles">
|
||||||
|
@foreach (var skill in category.Value)
|
||||||
|
{
|
||||||
|
<button type="button"
|
||||||
|
class="skill-bubble @(_application.SelectedSkills.Contains(skill) ? "skill-active" : "")"
|
||||||
|
@onclick="() => ToggleSkill(skill)">@skill</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<ValidationMessage For="() => _application.SelectedSkills" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="additionalNotes">Anything not listed above? (optional)</label>
|
||||||
|
<InputTextArea id="additionalNotes" @bind-Value="_application.AdditionalNotes" class="form-input form-textarea"
|
||||||
|
placeholder="Other skills, open-source contributions, areas of interest..." rows="3" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<!-- What You Get -->
|
<!-- What You Get -->
|
||||||
<div class="dev-section dev-perks">
|
<div class="dev-section dev-perks">
|
||||||
@@ -251,6 +322,8 @@
|
|||||||
private bool _submitted;
|
private bool _submitted;
|
||||||
private string? _resultMessage;
|
private string? _resultMessage;
|
||||||
private string? _errorMessage;
|
private string? _errorMessage;
|
||||||
|
private int _internetHover;
|
||||||
|
private int _testingHover;
|
||||||
|
|
||||||
private UsernameCheckState _usernameCheckState = UsernameCheckState.None;
|
private UsernameCheckState _usernameCheckState = UsernameCheckState.None;
|
||||||
private string? _usernameFormatError;
|
private string? _usernameFormatError;
|
||||||
@@ -329,6 +402,14 @@
|
|||||||
_application.Platforms.Add(platform);
|
_application.Platforms.Add(platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ToggleSkill(string skill)
|
||||||
|
{
|
||||||
|
if (_application.SelectedSkills.Contains(skill))
|
||||||
|
_application.SelectedSkills.Remove(skill);
|
||||||
|
else
|
||||||
|
_application.SelectedSkills.Add(skill);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnUsernameInput(ChangeEventArgs e)
|
private void OnUsernameInput(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
var username = e.Value?.ToString() ?? "";
|
var username = e.Value?.ToString() ?? "";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
|
|
||||||
namespace SilverLabs.Website.Models;
|
namespace SilverLabs.Website.Models;
|
||||||
|
|
||||||
public class DeveloperApplication
|
public class DeveloperApplication : IValidatableObject
|
||||||
{
|
{
|
||||||
[Required(ErrorMessage = "Full name is required")]
|
[Required(ErrorMessage = "Full name is required")]
|
||||||
[StringLength(100, MinimumLength = 2)]
|
[StringLength(100, MinimumLength = 2)]
|
||||||
@@ -25,8 +25,6 @@ public class DeveloperApplication
|
|||||||
[MinLength(1, ErrorMessage = "Please select at least one platform")]
|
[MinLength(1, ErrorMessage = "Please select at least one platform")]
|
||||||
public List<string> Platforms { get; set; } = new();
|
public List<string> Platforms { get; set; } = new();
|
||||||
|
|
||||||
public string? Skills { get; set; }
|
|
||||||
|
|
||||||
[Required(ErrorMessage = "Password is required")]
|
[Required(ErrorMessage = "Password is required")]
|
||||||
[StringLength(100, MinimumLength = 8, ErrorMessage = "Password must be at least 8 characters")]
|
[StringLength(100, MinimumLength = 8, ErrorMessage = "Password must be at least 8 characters")]
|
||||||
public string Password { get; set; } = string.Empty;
|
public string Password { get; set; } = string.Empty;
|
||||||
@@ -35,9 +33,36 @@ public class DeveloperApplication
|
|||||||
[Compare("Password", ErrorMessage = "Passwords do not match")]
|
[Compare("Password", ErrorMessage = "Passwords do not match")]
|
||||||
public string ConfirmPassword { get; set; } = string.Empty;
|
public string ConfirmPassword { get; set; } = string.Empty;
|
||||||
|
|
||||||
[Required(ErrorMessage = "Please tell us how you'll contribute")]
|
// Tester-specific
|
||||||
[StringLength(2000, MinimumLength = 20, ErrorMessage = "Please write at least 20 characters")]
|
public int? InternetUnderstanding { get; set; }
|
||||||
public string Motivation { get; set; } = string.Empty;
|
public int? EnjoysTesting { get; set; }
|
||||||
|
|
||||||
|
// Developer-specific
|
||||||
|
public string? ExperienceRange { get; set; }
|
||||||
|
public List<string> SelectedSkills { get; set; } = new();
|
||||||
|
|
||||||
|
// Shared optional
|
||||||
|
public string? AdditionalNotes { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
if (Role == ApplicationRole.Tester)
|
||||||
|
{
|
||||||
|
if (!InternetUnderstanding.HasValue || InternetUnderstanding < 1 || InternetUnderstanding > 5)
|
||||||
|
yield return new ValidationResult("Please rate your internet understanding", new[] { nameof(InternetUnderstanding) });
|
||||||
|
|
||||||
|
if (!EnjoysTesting.HasValue || EnjoysTesting < 1 || EnjoysTesting > 5)
|
||||||
|
yield return new ValidationResult("Please rate your enthusiasm for testing", new[] { nameof(EnjoysTesting) });
|
||||||
|
}
|
||||||
|
else if (Role == ApplicationRole.Developer)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(ExperienceRange))
|
||||||
|
yield return new ValidationResult("Please select your experience level", new[] { nameof(ExperienceRange) });
|
||||||
|
|
||||||
|
if (SelectedSkills.Count == 0)
|
||||||
|
yield return new ValidationResult("Please select at least one skill", new[] { nameof(SelectedSkills) });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ApplicationRole
|
public enum ApplicationRole
|
||||||
|
|||||||
37
BlazorApp/Models/SkillCatalog.cs
Normal file
37
BlazorApp/Models/SkillCatalog.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
namespace SilverLabs.Website.Models;
|
||||||
|
|
||||||
|
public static class SkillCatalog
|
||||||
|
{
|
||||||
|
public static readonly string[] ExperienceRanges =
|
||||||
|
{
|
||||||
|
"< 1 year",
|
||||||
|
"1-3 years",
|
||||||
|
"3-5 years",
|
||||||
|
"5-10 years",
|
||||||
|
"10+ years"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly Dictionary<string, string[]> SkillCategories = new()
|
||||||
|
{
|
||||||
|
["Languages"] = new[]
|
||||||
|
{
|
||||||
|
"C#", "Python", "JavaScript", "TypeScript", "Go", "Rust",
|
||||||
|
"Java", "C/C++", "PHP", "Ruby", "Swift", "Kotlin"
|
||||||
|
},
|
||||||
|
["Frameworks"] = new[]
|
||||||
|
{
|
||||||
|
".NET/Blazor", "React", "Angular", "Vue", "Django",
|
||||||
|
"Node.js", "Next.js", "Svelte", "Spring Boot", "Flask"
|
||||||
|
},
|
||||||
|
["Infrastructure"] = new[]
|
||||||
|
{
|
||||||
|
"Docker", "Kubernetes", "Linux", "Nginx", "Terraform",
|
||||||
|
"CI/CD", "AWS", "Azure", "Proxmox"
|
||||||
|
},
|
||||||
|
["Databases"] = new[]
|
||||||
|
{
|
||||||
|
"PostgreSQL", "MySQL", "SQLite", "MongoDB", "Redis",
|
||||||
|
"SQL Server", "Elasticsearch"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -121,8 +121,8 @@ public class DeveloperApplicationService
|
|||||||
timezone = application.Timezone,
|
timezone = application.Timezone,
|
||||||
appliedRole = application.Role.ToString(),
|
appliedRole = application.Role.ToString(),
|
||||||
platforms = application.Platforms,
|
platforms = application.Platforms,
|
||||||
skills = application.Skills ?? "",
|
skills = SerializeAssessment(application),
|
||||||
motivation = application.Motivation,
|
motivation = GenerateMotivationSummary(application),
|
||||||
status = 0, // Pending
|
status = 0, // Pending
|
||||||
silverDeskProvisioned = true
|
silverDeskProvisioned = true
|
||||||
};
|
};
|
||||||
@@ -158,6 +158,64 @@ public class DeveloperApplicationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serializes structured assessment data as JSON for the Skills column.
|
||||||
|
/// </summary>
|
||||||
|
internal static string SerializeAssessment(DeveloperApplication app)
|
||||||
|
{
|
||||||
|
object data;
|
||||||
|
|
||||||
|
if (app.Role == ApplicationRole.Tester)
|
||||||
|
{
|
||||||
|
data = new
|
||||||
|
{
|
||||||
|
type = "tester",
|
||||||
|
internetUnderstanding = app.InternetUnderstanding ?? 0,
|
||||||
|
enjoysTesting = app.EnjoysTesting ?? 0,
|
||||||
|
additionalNotes = app.AdditionalNotes ?? ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = new
|
||||||
|
{
|
||||||
|
type = "developer",
|
||||||
|
experienceRange = app.ExperienceRange ?? "",
|
||||||
|
selectedSkills = app.SelectedSkills,
|
||||||
|
additionalNotes = app.AdditionalNotes ?? ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonSerializer.Serialize(data, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a human-readable summary for the Motivation field (backward compatibility).
|
||||||
|
/// </summary>
|
||||||
|
internal static string GenerateMotivationSummary(DeveloperApplication app)
|
||||||
|
{
|
||||||
|
if (app.Role == ApplicationRole.Tester)
|
||||||
|
{
|
||||||
|
var summary = $"Internet understanding: {app.InternetUnderstanding}/5, Testing enthusiasm: {app.EnjoysTesting}/5";
|
||||||
|
if (!string.IsNullOrWhiteSpace(app.AdditionalNotes))
|
||||||
|
summary += $". Notes: {app.AdditionalNotes.Trim()}";
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var skills = app.SelectedSkills.Count > 0
|
||||||
|
? string.Join(", ", app.SelectedSkills)
|
||||||
|
: "None selected";
|
||||||
|
var summary = $"{app.ExperienceRange} experience. Skills: {skills}";
|
||||||
|
if (!string.IsNullOrWhiteSpace(app.AdditionalNotes))
|
||||||
|
summary += $". Notes: {app.AdditionalNotes.Trim()}";
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string ParseRegistrationError(string errorBody)
|
private static string ParseRegistrationError(string errorBody)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -198,15 +256,29 @@ public class DeveloperApplicationService
|
|||||||
sb.AppendLine($"**Platforms:** {string.Join(", ", app.Platforms)}");
|
sb.AppendLine($"**Platforms:** {string.Join(", ", app.Platforms)}");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
if (app.Role == ApplicationRole.Developer && !string.IsNullOrWhiteSpace(app.Skills))
|
if (app.Role == ApplicationRole.Tester)
|
||||||
{
|
{
|
||||||
sb.AppendLine("**Skills & Experience:**");
|
sb.AppendLine("### Assessment");
|
||||||
sb.AppendLine(app.Skills);
|
sb.AppendLine($"- Internet understanding: {"*".PadLeft(app.InternetUnderstanding ?? 0, '*')}{new string('-', 5 - (app.InternetUnderstanding ?? 0))} ({app.InternetUnderstanding}/5)");
|
||||||
|
sb.AppendLine($"- Testing enthusiasm: {"*".PadLeft(app.EnjoysTesting ?? 0, '*')}{new string('-', 5 - (app.EnjoysTesting ?? 0))} ({app.EnjoysTesting}/5)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.AppendLine("### Skills & Experience");
|
||||||
|
sb.AppendLine($"**Experience:** {app.ExperienceRange}");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
if (app.SelectedSkills.Count > 0)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"**Technologies:** {string.Join(", ", app.SelectedSkills)}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.AppendLine("**Motivation:**");
|
if (!string.IsNullOrWhiteSpace(app.AdditionalNotes))
|
||||||
sb.AppendLine(app.Motivation);
|
{
|
||||||
|
sb.AppendLine();
|
||||||
|
sb.AppendLine("### Additional Notes");
|
||||||
|
sb.AppendLine(app.AdditionalNotes.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -412,6 +412,119 @@
|
|||||||
color: #00B8D4;
|
color: #00B8D4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Star Rating */
|
||||||
|
.star-rating {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.35rem;
|
||||||
|
margin-top: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.star-rating-star {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
cursor: pointer;
|
||||||
|
color: rgba(255, 255, 255, 0.2);
|
||||||
|
transition: color 0.15s ease, transform 0.15s ease;
|
||||||
|
user-select: none;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.star-rating-star:hover {
|
||||||
|
transform: scale(1.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.star-rating-star.star-filled {
|
||||||
|
color: #4DD0E1;
|
||||||
|
text-shadow: 0 0 8px rgba(77, 208, 225, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rating-labels {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: rgba(255, 255, 255, 0.35);
|
||||||
|
max-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Experience Selector */
|
||||||
|
.experience-selector {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exp-btn {
|
||||||
|
padding: 0.45rem 1.1rem;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
border-radius: 100px;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
font-family: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exp-btn:hover {
|
||||||
|
border-color: rgba(77, 208, 225, 0.4);
|
||||||
|
background: rgba(77, 208, 225, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.exp-btn.exp-active {
|
||||||
|
background: rgba(77, 208, 225, 0.12);
|
||||||
|
border-color: #4DD0E1;
|
||||||
|
color: #4DD0E1;
|
||||||
|
box-shadow: 0 0 12px rgba(77, 208, 225, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skill Bubbles */
|
||||||
|
.skill-category-label {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
color: rgba(255, 255, 255, 0.4);
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-category-label:first-of-type {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-bubbles {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-bubble {
|
||||||
|
padding: 0.35rem 0.85rem;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
border-radius: 100px;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
font-size: 0.82rem;
|
||||||
|
font-family: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-bubble:hover {
|
||||||
|
border-color: rgba(77, 208, 225, 0.35);
|
||||||
|
background: rgba(77, 208, 225, 0.05);
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-bubble.skill-active {
|
||||||
|
background: rgba(77, 208, 225, 0.12);
|
||||||
|
border-color: #4DD0E1;
|
||||||
|
color: #4DD0E1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive */
|
/* Responsive */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.dev-header h1 {
|
.dev-header h1 {
|
||||||
|
|||||||
Reference in New Issue
Block a user