diff --git a/Gemfile b/Gemfile index 7a8b81bcc..2cc15bb77 100644 --- a/Gemfile +++ b/Gemfile @@ -118,6 +118,7 @@ gem "mission_control-jobs" gem "view_component" gem "phlex-rails" gem "aws-sdk-s3" +gem "rubyzip", "~> 3.0" gem "faraday" gem "faraday-retry" diff --git a/Gemfile.lock b/Gemfile.lock index d34f2b12e..14341891b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -865,6 +865,7 @@ DEPENDENCIES rspec-rails rubocop rubocop-rails-omakase + rubyzip (~> 3.0) selenium-webdriver sentry-rails (~> 6.6) sentry-ruby (~> 6.6) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 97b83118c..a0d4b2b9b 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -98,5 +98,6 @@ @use "pages/raffle"; @use "pages/notifications" as notifications_page; @use "pages/notification_settings" as notification_settings_page; +@use "pages/data_exports" as data_exports_page; @use "pages/rng"; @use "landing/landing_footer"; diff --git a/app/assets/stylesheets/components/_settings-form.scss b/app/assets/stylesheets/components/_settings-form.scss index cd5a32445..966549933 100644 --- a/app/assets/stylesheets/components/_settings-form.scss +++ b/app/assets/stylesheets/components/_settings-form.scss @@ -138,6 +138,7 @@ border-radius: 999px; padding: var(--space-xxs) var(--space-m); cursor: pointer; + text-decoration: none; transition: border-color 160ms ease, background-color 160ms ease; @@ -146,4 +147,11 @@ border-color: var(--color-border-input-focus); } } + + &__export-btn { + display: block; + width: 100%; + text-align: center; + text-decoration: none; + } } diff --git a/app/assets/stylesheets/pages/_data_exports.scss b/app/assets/stylesheets/pages/_data_exports.scss new file mode 100644 index 000000000..4f0625ba0 --- /dev/null +++ b/app/assets/stylesheets/pages/_data_exports.scss @@ -0,0 +1,92 @@ +.data-exports-page { + max-width: 720px; + width: 100%; + margin: 0 auto; + color: var(--color-space-text); + + &__header { + margin-bottom: var(--space-m); + } + + &__title { + font-family: var(--font-family-subtitle); + font-size: var(--font-size-xxl); + margin: 0 0 var(--space-xxs); + } + + &__description { + margin: 0; + color: var(--color-space-text-muted); + font-size: var(--font-size-s); + } + + &__actions { + margin-bottom: var(--space-l); + } + + &__list { + display: flex; + flex-direction: column; + gap: var(--space-xs); + } + + &__empty { + padding: var(--space-xl) var(--space-l); + text-align: center; + margin-top: var(--space-m); + } + + &__empty-title { + font-family: var(--font-family-subtitle); + font-size: var(--font-size-l); + margin: 0 0 var(--space-xxs); + color: var(--color-space-text); + } + + &__empty-hint { + margin: 0; + color: var(--color-space-text-muted); + font-size: var(--font-size-s); + } +} + +.data-export-item { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-s); + padding: var(--space-s) var(--space-m); + color: var(--color-space-text); + background: rgba(5, 4, 24, 0.35); + border: 2px solid var(--color-space-border); + border-radius: var(--profile-radius, var(--border-radius)); + + &__info { + display: flex; + align-items: center; + gap: var(--space-s); + min-width: 0; + } + + &__date { + opacity: 0.5; + font-weight: 400; + font-family: var(--font-family-text); + font-size: var(--font-size-s); + } + + &__error { + color: var(--color-brand-salmon); + font-size: var(--font-size-xs); + } + + &__actions { + flex: 0 0 auto; + } + + &__processing { + opacity: 0.5; + font-size: var(--font-size-s); + font-style: italic; + } +} diff --git a/app/components/sidebar_component.html.erb b/app/components/sidebar_component.html.erb index 059cd7aae..b0ce09be9 100644 --- a/app/components/sidebar_component.html.erb +++ b/app/components/sidebar_component.html.erb @@ -163,6 +163,12 @@ Links your coding time from Hackatime to your projects +
+ + <%= link_to "Export Data", my_data_exports_path, class: "settings-form__hackatime-btn settings-form__export-btn" %> + Download a ZIP of your projects, devlogs, and images +
+