diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 9da17fe..b244d35 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -11,6 +11,7 @@ @import "https://uchu.style/color.css"; @import "https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"; +@import "settings.css"; /* colors */ diff --git a/app/assets/stylesheets/settings.css b/app/assets/stylesheets/settings.css new file mode 100644 index 0000000..6aeb7da --- /dev/null +++ b/app/assets/stylesheets/settings.css @@ -0,0 +1,161 @@ +.settings-page .grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr)); + gap: 1rem; + margin-top: 2rem; +} + +.settings-page article { + background: var(--pico-card-background-color); + border: var(--pico-border-width) solid var(--pico-card-border-color); + border-radius: var(--pico-border-radius); + box-shadow: var(--pico-card-box-shadow); + transition: box-shadow var(--pico-transition); + margin: 0; +} + +.settings-page article header { + padding: 0.5rem; + border-bottom: 1px solid var(--pico-muted-border-color); +} + +.settings-page article header h2 { + margin-bottom: 0; + font-size: 1.25rem; + font-weight: 600; + color: var(--pico-color); +} + +.settings-page article header p { + margin-bottom: 0; + color: var(--pico-muted-color); + font-size: 0.875rem; +} + +.settings-page article section { + margin-top: 1.5rem; + padding-top: 1rem; + border-top: 1px solid var(--pico-muted-border-color); +} + +.settings-page article section:first-of-type { + margin-top: 0; + padding-top: 0; + border-top: none; +} + +.settings-page article section h3 { + margin-bottom: 0.75rem; + font-size: 1rem; + font-weight: 500; + color: var(--pico-color); +} + +.settings-page article .form-group { + margin-bottom: 1rem; +} + +.settings-page article .form-group:last-child { + margin-bottom: 0; +} + +.settings-page article button[role="button"], +.settings-page article input[type="submit"][role="button"] { + margin-top: 1rem; +} + +.settings-page article .secondary { + background-color: var(--pico-secondary-background); + border-color: var(--pico-secondary-border); + color: var(--pico-secondary-color); +} + +.settings-page article .secondary:hover { + background-color: var(--pico-secondary-hover-background); + border-color: var(--pico-secondary-hover-border); +} + +.settings-page article .code-example { + margin: 1rem 0; + background: var(--pico-code-background-color); + border-radius: var(--pico-border-radius); +} + +.settings-page article .code-example pre { + margin: 0; + background: transparent; + padding: 0; +} + +.settings-page article img { + max-width: 100%; + height: auto; + margin: 1rem 0; + border-radius: var(--pico-border-radius); +} + +.settings-page article pre:not(.code-example pre) { + background: var(--pico-code-background-color); + padding: 0.75rem; + border-radius: var(--pico-border-radius); + font-size: 0.875rem; + overflow-x: auto; +} + +.settings-page .mirror { + padding: 1rem; + background: var(--pico-card-sectioning-background-color); + border-radius: var(--pico-border-radius); + margin-bottom: 1rem; +} + +.settings-page .mirror:last-child { + margin-bottom: 0; +} + +.settings-page .email-form { + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px solid var(--pico-muted-border-color); +} + +.settings-page .email-form .field { + display: flex; + gap: 0.5rem; + align-items: end; +} + +.settings-page .email-form input[type="email"] { + flex: 1; + margin-bottom: 0; +} + +@media (max-width: 768px) { + .settings-page .grid { + grid-template-columns: 1fr; + gap: 1.5rem; + } + + .settings-page article { + padding: 1rem; + } + + .settings-page .email-form .field { + flex-direction: column; + align-items: stretch; + } +} + +@media (prefers-color-scheme: dark) { + .settings-page article { + background: var(--pico-card-background-color, #1e293b); + border-color: var(--pico-card-border-color, #334155); + } + + .settings-page article:hover { + box-shadow: var( + --pico-card-box-shadow-hover, + 0 0.125rem 1rem rgba(0, 0, 0, 0.3) + ); + } +} diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 23178f3..9da27b4 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -137,7 +137,7 @@ <%= Sentry.get_trace_propagation_meta.html_safe %> - + diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index a8fdf74..5828a53 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -2,173 +2,195 @@ <%= @is_own_settings ? "My Settings" : "Settings | #{@user.username}" %> <% end %> +<% content_for :body_class, "settings-page" %> +
-
+

<%= @is_own_settings ? "My Settings" : "Settings for #{@user.username}" %>

Change your settings for Hackatime and Sailors Log.

-
+
-
-

Time tracking wizard

- <%= link_to "Set up time tracking", my_wakatime_setup_path %> -
+
+
+

🚀 Time tracking wizard

+
+

Get started with tracking your coding time in just a few minutes.

+ <%= link_to "Set up time tracking", my_wakatime_setup_path, role: "button" %> +
-
-

Timezone

- <%= form_with model: @user, - url: @is_own_settings ? my_settings_path : settings_user_path(@user), - method: :patch do |f| %> -
- <%= f.label :timezone, "Your timezone" %> - <%= f.select :timezone, - TZInfo::Timezone.all.map(&:identifier).sort, - include_blank: @user.timezone.blank?, class: "form-select" %> -
- This affects how your activity graph and other time-based features are displayed. - <%= f.submit "Save Settings" %> - <% end %> -
- -
- -
-

Slack status

-

When you're hacking on a project, Hackatime can update your Slack status so you can show it off!

- <% unless @can_enable_slack_status %> - <%= link_to "Re-authorize with Slack to give permission to update your status", slack_auth_path %> - <% end %> - <%= form_with model: @user, - url: @is_own_settings ? my_settings_path : settings_user_path(@user), - method: :patch do |f| %> -
- -
- <%= f.submit "Save Settings" %> - <% end %> -
- -
-

Slack notifications

- <% if @enabled_sailors_logs.any? %> -

You have notifications enabled for the following channels:

-
    - <% @enabled_sailors_logs.each do |sl| %> -
  • - <%= render "shared/slack_channel_mention", channel_id: sl.slack_channel_id %> -
  • - <% end %> -
- <% else %> -

You have no notifications enabled.

- <% end %> -

- You can enable notifications for specific channels by running /sailorslog on in the Slack channel you want to enable notifications for. -

-
- -
- -
-

GitHub Account

-

- This is used to show your active projects on the leaderboard & current hacking activity on the dashboard. -

- <% if @user.github_uid.present? %> -

Your GitHub account is linked. <%= link_to "@#{@user.github_username}", "https://github.com/#{@user.github_username}", target: "_blank" %>

- <% else %> - <%= link_to "Link GitHub Account", github_auth_path, data: { turbo: "false" } %> - <% end %> -
- -
-

Email Addresses

-

These are the email addresses associated with your account.

- <% if @user.email_addresses.any? %> -
    - <% @user.email_addresses.each do |email_address| %> -
  • - <%= email_address.email %> - <% if email_address.source.present? %> - - (from <%= email_address.source.humanize %>) - - <% end %> -
  • - <% end %> -
- <% else %> -

No email addresses found.

- <% end %> - -
- <%= form_tag add_email_auth_path, data: { turbo: false } do %> -
- <%= email_field_tag :email, nil, placeholder: "Add another email address", required: true %> +
+
+

🌍 Timezone

+
+ <%= form_with model: @user, + url: @is_own_settings ? my_settings_path : settings_user_path(@user), + method: :patch do |f| %> +
+ <%= f.label :timezone, "Your timezone" %> + <%= f.select :timezone, + TZInfo::Timezone.all.map(&:identifier).sort, + include_blank: @user.timezone.blank?, class: "form-select" %>
- <%= submit_tag "Add Email" %> + This affects how your activity graph and other time-based features are displayed. + <%= f.submit "Save Settings", role: "button" %> <% end %> -
-
+ -
-

Hackatime extension

- <%= form_with model: @user, - url: @is_own_settings ? my_settings_path : settings_user_path(@user), - method: :patch do |f| %> -
- <%= f.label "Simple text" %> - <%= f.select :hackatime_extension_text_type, - User.hackatime_extension_text_types.keys.map { |type| [type.humanize, type] }, - selected: @user.hackatime_extension_text_type, class: "form-select" %> -
- <%= f.submit "Save Settings" %> - <% end %> -
- -
-

Stats badges

-

This badge shows your stats on your GitHub profile.

- - <% gh_badge = GithubReadmeStats.new(current_user.id, "darcula") %> - -
<%= gh_badge.generate_badge_url %>
- - -
- - <% if @projects.any? && @user.slack_uid.present? %> -
-

This badge shows individual project stats.

-

see the documentation for more customization options!

- - -
<%= @work_time_stats_url %>
+ <%= form_with model: @user, + url: @is_own_settings ? my_settings_path : settings_user_path(@user), + method: :patch do |f| %> +
+ +
+ <%= f.submit "Save Settings", role: "button" %> + <% end %> +
+ +
+

Channel Notifications

+ <% if @enabled_sailors_logs.any? %> +

You have notifications enabled for the following channels:

+
    + <% @enabled_sailors_logs.each do |sl| %> +
  • + <%= render "shared/slack_channel_mention", channel_id: sl.slack_channel_id %> +
  • + <% end %> +
+ <% else %> +

You have no notifications enabled.

+ <% end %> +

+ You can enable notifications for specific channels by running /sailorslog on in the Slack channel you want to enable notifications for. +

+
+ + +
+
+

🔗 Connected Accounts

+
+ +
+

GitHub Account

+

This is used to show your active projects on the leaderboard & current hacking activity on the dashboard.

+ <% if @user.github_uid.present? %> +

✅ Your GitHub account is linked: <%= link_to "@#{@user.github_username}", "https://github.com/#{@user.github_username}", target: "_blank" %>

+ <% else %> + <%= link_to "Link GitHub Account", github_auth_path, data: { turbo: "false" }, role: "button" %> + <% end %> +
+ +
+

Email Addresses

+

These are the email addresses associated with your account.

+ <% if @user.email_addresses.any? %> +
    + <% @user.email_addresses.each do |email_address| %> +
  • + <%= email_address.email %> + <% if email_address.source.present? %> + + (from <%= email_address.source.humanize %>) + + <% end %> +
  • + <% end %> +
+ <% else %> +

No email addresses found.

+ <% end %> + + +
+
+ +
+
+

⚙️ Extension Settings

+
+ <%= form_with model: @user, + url: @is_own_settings ? my_settings_path : settings_user_path(@user), + method: :patch do |f| %> +
+ <%= f.label "Simple text" %> + <%= f.select :hackatime_extension_text_type, + User.hackatime_extension_text_types.keys.map { |type| [type.humanize, type] }, + selected: @user.hackatime_extension_text_type, class: "form-select" %> +
+ <%= f.submit "Save Settings", role: "button" %> + <% end %> +
+ +
+
+

📊 Stats Badges

+
+
+

Show your coding stats on your GitHub profile with beautiful badges.

+

General Stats Badge

+

This badge shows your overall coding statistics.

+ + <% gh_badge = GithubReadmeStats.new(current_user.id, "darcula") %> + +
<%= gh_badge.generate_badge_url %>
+
+ + <% if @projects.any? && @user.slack_uid.present? %> +
+

Project Stats Badge

+

This badge shows individual project statistics.

+

See the documentation for more customization options!

+ + +
<%= @work_time_stats_url %>
+
+ <% end %> + - - <% end %> +
-
-

Markscribe Templates

-

Use markscribe to create beautiful GitHub profile READMEs with your coding stats.

-
-
{{ wakatimeDoubleCategoryBar "💾 Languages:" wakatimeData.Languages "💼 Projects:" wakatimeData.Projects 5 }}
-
-

Add this to your GitHub profile README template to display your top languages and projects.

-

See the markscribe documentation for more template options.

- Example of markscribe output showing coding language and project statistics -
+
+
+

📝 Markscribe Templates

+

Use markscribe to create beautiful GitHub profile READMEs with your coding stats.

+
+ +
+
{{ wakatimeDoubleCategoryBar "💾 Languages:" wakatimeData.Languages "💼 Projects:" wakatimeData.Projects 5 }}
+
+

Add this to your GitHub profile README template to display your top languages and projects.

+

See the markscribe documentation for more template options.

+ Example of markscribe output showing coding language and project statistics +
-
- -
-

Config file

-

- <% if current_user.most_recent_direct_entry_heartbeat %> - Your last heartbeat was <%= time_ago_in_words current_user.most_recent_direct_entry_heartbeat.created_at %> ago. - <% else %> - You haven't sent any heartbeats yet directly to this platform. - <% end %> -

- <%= render "wakatime_config_display" %> -

- - This file is located in ~/.wakatime.cfg on your computer. - You can configure it with other settings as well. - -

-
- -
-

Privacy

- <%= form_with model: @user, - url: @is_own_settings ? my_settings_path : settings_user_path(@user), - method: :patch do |f| %> -
- -
- <%= f.submit "Save Settings" %> - <% end %> -
- - <% admin_tool do %> -
-

WakaTime Mirror

-

Mirror your coding activity to WakaTime.

- - <% if current_user.wakatime_mirrors.any? %> -
- <% current_user.wakatime_mirrors.each do |mirror| %> -
-

- Endpoint: <%= mirror.endpoint_url %>
- Last synced: <%= mirror.last_synced_at ? time_ago_in_words(mirror.last_synced_at) + " ago" : "Never" %> -

- <%= button_to "Delete", user_wakatime_mirror_path(current_user, mirror), method: :delete, class: "button", data: { confirm: "Are you sure?" } %> -
+
+
+

📄 Config File

+

+ <% if current_user.most_recent_direct_entry_heartbeat %> + Your last heartbeat was <%= time_ago_in_words current_user.most_recent_direct_entry_heartbeat.created_at %> ago. + <% else %> + You haven't sent any heartbeats yet directly to this platform. <% end %> -

+

+
+ + <%= render "wakatime_config_display" %> +

+ + This file is located in ~/.wakatime.cfg on your computer. + You can configure it with other settings as well. + +

+ + +
+
+

🔒 Privacy Settings

+
+ + <%= form_with model: @user, + url: @is_own_settings ? my_settings_path : settings_user_path(@user), + method: :patch do |f| %> +
+ +
+ <%= f.submit "Save Settings", role: "button" %> <% end %> +
- <%= form_with(model: [current_user, WakatimeMirror.new], local: true) do |f| %> -
- <%= f.label :endpoint_url, "WakaTime API Endpoint" %> - <%= f.text_field :endpoint_url, value: "https://wakatime.com/api/v1", placeholder: "https://wakatime.com/api/v1" %> -
+ <% admin_tool do %> +
+
+

🔄 WakaTime Mirror

+

Mirror your coding activity to WakaTime.

+
-
- <%= f.label :encrypted_api_key, "WakaTime API Key" %> - <%= f.text_field :encrypted_api_key, placeholder: "Enter your WakaTime API key" %> -
- - <%= f.submit "Add Mirror", class: "button" %> - <% end %> - - <% end %> - -
-

Migration assistant

-

This will migrate your heartbeats from waka.hackclub.com to this platform.

- <%= button_to "Migrate heartbeats", my_settings_migrate_heartbeats_path, method: :post %> - <% if @heartbeats_migration_jobs.any? %> -
    - <% @heartbeats_migration_jobs.each do |job| %> -
  • - <% if job.finished_at && !job.error %> - ✅ - <% elsif job.finished_at && job.error %> - ❌ - <% else %> - ⏳ + <% if current_user.wakatime_mirrors.any? %> +
    + <% current_user.wakatime_mirrors.each do |mirror| %> +
    +

    + Endpoint: <%= mirror.endpoint_url %>
    + Last synced: <%= mirror.last_synced_at ? time_ago_in_words(mirror.last_synced_at) + " ago" : "Never" %> +

    + <%= button_to "Delete", user_wakatime_mirror_path(current_user, mirror), method: :delete, role: "button", class: "secondary", data: { confirm: "Are you sure?" } %> +
    <% end %> - Job started at <%= job.created_at.strftime("%Y-%m-%d %H:%M:%S") %> - <% if job.finished_at %> - (and finished after <%= distance_of_time_in_words(job.finished_at - job.created_at) %>) - <% end %> - <% admin_tool('', 'span') do %> - <%= link_to "View job", GoodJob::Engine.routes.url_helpers.job_path(job.id) %> - <% end %> -
  • + <% end %> -
+ + <%= form_with(model: [current_user, WakatimeMirror.new], local: true) do |f| %> +
+ <%= f.label :endpoint_url, "WakaTime API Endpoint" %> + <%= f.text_field :endpoint_url, value: "https://wakatime.com/api/v1", placeholder: "https://wakatime.com/api/v1", class: "form-control" %> +
+ +
+ <%= f.label :encrypted_api_key, "WakaTime API Key" %> + <%= f.text_field :encrypted_api_key, placeholder: "Enter your WakaTime API key", class: "form-control" %> +
+ <%= f.submit "Add Mirror", role: "button" %> + <% end %> +
<% end %> - + +
+
+

🚚 Migration Assistant

+

This will migrate your heartbeats from waka.hackclub.com to this platform.

+
+ + <%= button_to "Migrate heartbeats", my_settings_migrate_heartbeats_path, method: :post, role: "button" %> + + <% if @heartbeats_migration_jobs.any? %> +
+

Migration Jobs

+
    + <% @heartbeats_migration_jobs.each do |job| %> +
  • + <% if job.finished_at && !job.error %> + ✅ + <% elsif job.finished_at && job.error %> + ❌ + <% else %> + ⏳ + <% end %> + Job started at <%= job.created_at.strftime("%Y-%m-%d %H:%M:%S") %> + <% if job.finished_at %> + (and finished after <%= distance_of_time_in_words(job.finished_at - job.created_at) %>) + <% end %> + <% admin_tool('', 'span') do %> + <%= link_to "View job", GoodJob::Engine.routes.url_helpers.job_path(job.id) %> + <% end %> +
  • + <% end %> +
+
+ <% end %> +
+