diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index f296340..305c4b0 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -82,3 +82,34 @@ table { margin: 0; } } + +a[target=_blank]::after { + content: url("mingcute/external_link_line.svg"); + display: inline-block; + scale: 0.7; + transform-origin: 0 50%; +} + +.row { + display: flex; + flex-flow: row nowrap; + align-items: baseline; + gap: 1em; + + > * { + margin: 0; + } + + > .right { + margin-left: auto; + } +} + +.mask-icon { + display: inline-block; + height: 1lh; + width: 1lh; + background-color: var(--icon-color, black); + mask-image: var(--icon, url("mingcute/task_line.svg")); + mask-size: 100%; +} diff --git a/app/assets/stylesheets/tabs.css b/app/assets/stylesheets/tabs.css new file mode 100644 index 0000000..0cb98ad --- /dev/null +++ b/app/assets/stylesheets/tabs.css @@ -0,0 +1,28 @@ +.tabs { + padding-inline: 0; + + li { + list-style: none; + margin: 0; + } + + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; + gap: 0.25em; + + a { + text-decoration: none; + display: inline-block; + padding: 0.25em 0.5em; + border: 1px solid gray; + border-radius: 0.5em; + + transition: background-color 0.2s, color 0.2s; + + &.active, &:hover, &:focus { + background-color: var(--pico-primary); + color: white; + } + } +} diff --git a/app/assets/stylesheets/workflows.css b/app/assets/stylesheets/workflows.css index 7bc05a3..7018909 100644 --- a/app/assets/stylesheets/workflows.css +++ b/app/assets/stylesheets/workflows.css @@ -1,26 +1,25 @@ .workflow { - --bg-color: #D1D5DB; /* Pico zinc 150 */ - --text-color: oklch(from var(--bg-color) calc(0.55 * l) calc(0.55 * c) h); + --color: #424751; /* Pico zinc 700 */ border-radius: 1em; - background-color: var(--bg-color); - color: var(--text-color); + outline: 2px solid var(--color); - display: flex; - flex-flow: row nowrap; - justify-content: center; + display: inline-flex; + gap: 0.25em; min-width: 2em; padding: 0.1em 0.5em; - gap: 0.5em; - text-align: center; + + > .mask-icon { + --icon-color: var(--color); + } > img { max-width: unset; width: 1lh; - opacity: 0.6; + opacity: 0.75; } &.red { - --bg-color: #F06048; /* Pico red 400 */ + --color: #BD3C13; /* Pico orange 550 */ } } diff --git a/app/controllers/project_admin/application_controller.rb b/app/controllers/project_admin/application_controller.rb new file mode 100644 index 0000000..bc023f8 --- /dev/null +++ b/app/controllers/project_admin/application_controller.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module ProjectAdmin + class ApplicationController < ::ApplicationController + before_action :fetch_project + + private + + def fetch_project + @project = Project.find_by!(code: params[:project_id]) + end + end +end diff --git a/app/controllers/project_admin/workflows_controller.rb b/app/controllers/project_admin/workflows_controller.rb new file mode 100644 index 0000000..a69b762 --- /dev/null +++ b/app/controllers/project_admin/workflows_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module ProjectAdmin + class WorkflowsController < ApplicationController + def index + @workflows = @project.workflows + end + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 84f8109..eef67dc 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -6,4 +6,14 @@ module ApplicationHelper url_for(controller: controller_name, action: :index, project:) end + + def mask_icon(icon, **options) + # Renders a span as a masked icon + case options[:class] + when String then options[:class] += ' mask-icon' + when nil then options[:class] = 'mask-icon' + else options[:class] = Array(options[:class]) + ['mask-icon'] + end + content_tag(:span, '', style: "--icon: url(#{image_path(icon)})", **options) + end end diff --git a/app/helpers/project_admin/workflows_helper.rb b/app/helpers/project_admin/workflows_helper.rb new file mode 100644 index 0000000..a0e9f36 --- /dev/null +++ b/app/helpers/project_admin/workflows_helper.rb @@ -0,0 +1,2 @@ +module ProjectAdmin::WorkflowsHelper +end diff --git a/app/helpers/project_admin_helper.rb b/app/helpers/project_admin_helper.rb new file mode 100644 index 0000000..9e46b92 --- /dev/null +++ b/app/helpers/project_admin_helper.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module ProjectAdminHelper + def project_admin_frame(project, &) + tabs_id = 'project_admin_tabs' + tabs = ProjectAdmin::TabsViewModel.new(project, frame: :project_admin, id: tabs_id) + content = capture(&) if block_given? + + render partial: 'project_admin/frame', locals: { id: :project_admin, tabs:, tabs_id:, content: } + end +end diff --git a/app/view_models/project_admin/tabs_view_model.rb b/app/view_models/project_admin/tabs_view_model.rb new file mode 100644 index 0000000..7756f42 --- /dev/null +++ b/app/view_models/project_admin/tabs_view_model.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module ProjectAdmin + class TabsViewModel + include Rails.application.routes.url_helpers + + def initialize(project, id:, frame:) + @project = project + @id = id + @frame = frame + end + + def render_in(view_context) + view_context.render( + partial: 'project_admin/tabs', + locals: { project: @project, links:, id: @id, frame: @frame } + ) + end + + private + + def links + { + 'Data' => edit_project_path(@project), + 'Workflows' => project_workflows_path(@project) + } + end + end +end diff --git a/app/views/project_admin/_frame.html.slim b/app/views/project_admin/_frame.html.slim new file mode 100644 index 0000000..1087df0 --- /dev/null +++ b/app/views/project_admin/_frame.html.slim @@ -0,0 +1,11 @@ +h1 + span> Project + span= @project.name + += link_to '← Back', project_path(@project) + += render tabs + += turbo_frame_tag(id) do + = content + = turbo_stream.replace(tabs_id, tabs) diff --git a/app/views/project_admin/_tabs.html.slim b/app/views/project_admin/_tabs.html.slim new file mode 100644 index 0000000..5652181 --- /dev/null +++ b/app/views/project_admin/_tabs.html.slim @@ -0,0 +1,3 @@ +nav.tabs id=id + - links.each do |text, path| + li= link_to text, path, class: {'active': request.path == path}, data: {'turbo-frame': frame, 'turbo-action': 'advance'} diff --git a/app/views/project_admin/workflows/index.html.slim b/app/views/project_admin/workflows/index.html.slim new file mode 100644 index 0000000..80c82b9 --- /dev/null +++ b/app/views/project_admin/workflows/index.html.slim @@ -0,0 +1,9 @@ += project_admin_frame(@project) do + h2 + span Workflows + + - @workflows.each do |workflow| + article.row + = workflow_display(workflow, full: true) + ul.links.right + li= link_to 'Edit', edit_project_workflow_path(@project, workflow), target: '_blank' diff --git a/app/views/projects/edit.html.slim b/app/views/projects/edit.html.slim index 386dbee..dc7c7e0 100644 --- a/app/views/projects/edit.html.slim +++ b/app/views/projects/edit.html.slim @@ -1,5 +1,5 @@ -h1 - span Editing project - span= @project.name += project_admin_frame(@project) do + h2 + span Editing project -= render 'form' + = render 'form' diff --git a/app/views/workflows/_display.html.slim b/app/views/workflows/_display.html.slim index 5be1e6f..6e72610 100644 --- a/app/views/workflows/_display.html.slim +++ b/app/views/workflows/_display.html.slim @@ -1,4 +1,4 @@ div.workflow class=color title=name - = image_tag(icon) + = mask_icon(icon) - if full - span= name + span<= name diff --git a/config/routes.rb b/config/routes.rb index 86a6e85..da6724a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,7 +16,12 @@ Rails.application.routes.draw do # Defines the root path route ("/") # root "posts#index" - resources :projects + resources :projects do + scope module: :project_admin do + resources :workflows, only: %i[index new create edit update destroy] + end + end + resources :tasks do patch :change_status, on: :member end diff --git a/vendor/assets/images/mingcute/external_link_line.svg b/vendor/assets/images/mingcute/external_link_line.svg new file mode 100644 index 0000000..63a2fc0 --- /dev/null +++ b/vendor/assets/images/mingcute/external_link_line.svg @@ -0,0 +1 @@ + \ No newline at end of file