Compare commits

...

7 Commits

20 changed files with 304 additions and 108 deletions

View File

@ -130,6 +130,7 @@ GEM
tzinfo tzinfo
ffi (1.17.2-aarch64-linux-gnu) ffi (1.17.2-aarch64-linux-gnu)
ffi (1.17.2-arm64-darwin) ffi (1.17.2-arm64-darwin)
ffi (1.17.2-x86_64-linux-gnu)
foreman (0.88.1) foreman (0.88.1)
fugit (1.11.1) fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11) et-orbi (~> 1, >= 1.2.11)
@ -195,6 +196,8 @@ GEM
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.7-arm64-darwin) nokogiri (1.18.7-arm64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.7-x86_64-linux-gnu)
racc (~> 1.4)
ostruct (0.6.1) ostruct (0.6.1)
parallel (1.27.0) parallel (1.27.0)
parser (3.3.8.0) parser (3.3.8.0)
@ -322,6 +325,7 @@ GEM
thor (~> 1.3.1) thor (~> 1.3.1)
sqlite3 (2.6.0-aarch64-linux-gnu) sqlite3 (2.6.0-aarch64-linux-gnu)
sqlite3 (2.6.0-arm64-darwin) sqlite3 (2.6.0-arm64-darwin)
sqlite3 (2.6.0-x86_64-linux-gnu)
sshkit (1.24.0) sshkit (1.24.0)
base64 base64
logger logger
@ -336,6 +340,7 @@ GEM
thruster (0.1.12) thruster (0.1.12)
thruster (0.1.12-aarch64-linux) thruster (0.1.12-aarch64-linux)
thruster (0.1.12-arm64-darwin) thruster (0.1.12-arm64-darwin)
thruster (0.1.12-x86_64-linux)
timeout (0.4.3) timeout (0.4.3)
turbo-rails (2.0.13) turbo-rails (2.0.13)
actionpack (>= 7.1.0) actionpack (>= 7.1.0)
@ -365,6 +370,7 @@ PLATFORMS
aarch64-linux aarch64-linux
aarch64-linux-gnu aarch64-linux-gnu
arm64-darwin-24 arm64-darwin-24
x86_64-linux
DEPENDENCIES DEPENDENCIES
amazing_print amazing_print

View File

@ -9,7 +9,13 @@
--color-warning: rgb(255, 202, 40); --color-warning: rgb(255, 202, 40);
--color-accept: rgb(121, 134, 203); --color-accept: rgb(121, 134, 203);
--color-danger: rgb(239, 83, 80); --color-danger: rgb(239, 83, 80);
--color-table-border: rgb(203, 213, 225); --color-table-border: rgb(130, 144, 158);
/* theme */
--color-base-background: rgb(39, 44, 56);
--color-base-secondary: rgb(55, 61, 71);
--color-base-text: rgb(152, 158, 172);
--color-base-border: rgb(77, 84, 102);
--base-font-size: 0.85rem; --base-font-size: 0.85rem;
--text-xs: calc(var(--base-font-size) * 0.75); --text-xs: calc(var(--base-font-size) * 0.75);
@ -90,7 +96,11 @@
} }
.side-bar { .side-bar {
@apply w-64 px-4 text-lg font-bold divide-y divide-default-slate-dark; @apply w-[16rem] px-4 text-lg font-bold divide-y divide-base-border;
}
.content {
@apply rounded-lg bg-base-secondary;
} }
.page-title { .page-title {
@ -119,7 +129,7 @@
} }
.menu-group-icon { .menu-group-icon {
@apply py-1 text-sm text-default-slate-dark font-medium justify-center @apply py-1 text-sm font-medium justify-center
} }
.menu-group-name { .menu-group-name {
@ -169,15 +179,15 @@
/*Base Table*/ /*Base Table*/
.base-table { .base-table {
@apply min-w-full divide-y divide-table-border whitespace-nowrap border border-table-border @apply min-w-full whitespace-nowrap border border-table-border
} }
.base-table th { .base-table th {
@apply bg-default px-2 py-2 text-left font-semibold text-default-slate-dark lg:table-cell @apply bg-base-text px-2 py-2 text-left font-bold lg:table-cell
} }
.base-table td { .base-table td {
@apply border-t border-table-border px-2 py-1 text-default-slate lg:table-cell whitespace-nowrap @apply border-t border-table-border px-2 py-1 lg:table-cell whitespace-nowrap
} }
} }
@ -190,3 +200,24 @@
@apply text-lg font-bold; @apply text-lg font-bold;
} }
} }
/* 기본 스크롤바 스타일 */
::-webkit-scrollbar {
width: 6px;
height: 6px;
padding: 4px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: rgba(21, 21, 21, 0.4);
border-radius: 4px;
transition: background-color 0.2s;
}
::-webkit-scrollbar-thumb:hover {
background-color: rgba(100, 100, 100, 0.6);
}

View File

@ -1,4 +1,11 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has. # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
allow_browser versions: :modern allow_browser versions: :modern
before_action :set_controllers
private
def set_controllers
@controllers = Controller.all
end
end end

View File

@ -0,0 +1,2 @@
class DeviceController < ApplicationController
end

View File

@ -0,0 +1,2 @@
class WebController < ApplicationController
end

View File

@ -0,0 +1,2 @@
module DeviceHelper
end

View File

@ -0,0 +1,2 @@
module WebHelper
end

View File

@ -0,0 +1 @@
<div class="p-4">DEVICE</div>

View File

@ -23,22 +23,25 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
</head> </head>
<body> <body class="h-screen overflow-hidden bg-base-background text-base-text min-w-[400px] overflow-x-auto">
<%= turbo_frame_tag :modals %> <%= turbo_frame_tag :modals %>
<main class="flex flex-col h-full divide-y divide-border-table-border"> <main class="flex flex-col h-full">
<%= render "partials/header" %> <%= render "partials/header" %>
<div class="flex flex-row flex-1 w-full divide-x divide-border-table-border"> <div class="flex flex-row flex-1 w-full overflow-hidden">
<div class="w-full h-full"> <%= render "partials/sidebar" %>
<% if flash[:notice] %> <div class="flex-1 h-full pb-4 pr-4">
<div class="m-4 rounded px-4 py-2 bg-accept text-white"> <div class="flex-1 h-full content">
<%= raw flash[:notice] %> <% if flash[:notice] %>
</div> <div class="m-4 rounded px-4 py-2 bg-accept text-white">
<% elsif flash[:alert] %> <%= raw flash[:notice] %>
<div class="m-4 rounded px-4 py-2 bg-danger text-white"> </div>
<%= raw flash[:alert] %> <% elsif flash[:alert] %>
</div> <div class="m-4 rounded px-4 py-2 bg-danger text-white">
<% end %> <%= raw flash[:alert] %>
<%= yield %> </div>
<% end %>
<%= yield %>
</div>
</div> </div>
</div> </div>
</main> </main>

View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || "Farmitry Hvac" %></title>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= yield :head %>
<%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
<%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>
<link rel="icon" href="/icon.png" type="image/png">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/icon.png">
<%# Includes all stylesheet files in app/assets/stylesheets %>
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
<%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
</head>
<body class="h-screen overflow-hidden bg-base-background text-base-text min-w-[400px] overflow-x-auto">
<%= turbo_frame_tag :modals %>
<main class="flex flex-col h-full">
<%= render "partials/header" %>
<div class="flex flex-row flex-1 w-full overflow-hidden">
<%= render "partials/sidebar" %>
<div class="flex-1 h-full pb-4 pr-4">
<div class="flex-1 h-full content">
<% if flash[:notice] %>
<div class="m-4 rounded px-4 py-2 bg-accept text-white">
<%= raw flash[:notice] %>
</div>
<% elsif flash[:alert] %>
<div class="m-4 rounded px-4 py-2 bg-danger text-white">
<%= raw flash[:alert] %>
</div>
<% end %>
<%= yield %>
</div>
</div>
</div>
</main>
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || "Farmitry Hvac" %></title>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= yield :head %>
<%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
<%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>
<link rel="icon" href="/icon.png" type="image/png">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/icon.png">
<%# Includes all stylesheet files in app/assets/stylesheets %>
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
<%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
</head>
<body>
<%= turbo_frame_tag :modals %>
<main class="flex flex-col h-full divide-y divide-border-table-border">
<%= render "partials/header" %>
<div class="flex flex-row flex-1 w-full divide-x divide-border-table-border">
<div class="w-full h-full">
<% if flash[:notice] %>
<div class="m-4 rounded px-4 py-2 bg-accept text-white">
<%= raw flash[:notice] %>
</div>
<% elsif flash[:alert] %>
<div class="m-4 rounded px-4 py-2 bg-danger text-white">
<%= raw flash[:alert] %>
</div>
<% end %>
<%= yield %>
</div>
</div>
</main>
</body>
</html>

View File

@ -1,9 +1,9 @@
<header class="flex header" data-controller="timer"> <header class="flex header" data-controller="timer">
<div class="flex flex-row h-full"> <div class="flex flex-row h-full">
<%= image_tag "svg/svg_logo.svg", class: "w-16 h-auto" %> <%= image_tag "svg/svg_logo.svg", class: "w-fit h-auto mr-4" %>
<%= link_to root_path do %> <%= link_to root_path do %>
<div class="flex h-full items-center tracking-[0.5rem]">FARMITRY</div> <div class="flex h-full items-center tracking-[0.5rem]">FARMITRY</div>
<% end %> <% end %>
</div> </div>
<div data-timer-target="output" class="text-gray-600"></div> <div data-timer-target="output"></div>
</header> </header>

View File

@ -0,0 +1,28 @@
<nav class="side-bar overflow-y-auto">
<div class="menu-group">
<div class="menu-group-icon">
<i class="fa-solid fa-house text-base-text/30 text-4xl"></i>
</div>
<div class="menu-group-name">
HOME
</div>
</div>
<% @controllers.each do |c| %>
<%= link_to view_schedule_path(c.id), class: "menu-group" do %>
<div class="menu-group-icon">
<i class="fa-solid fa-temperature-high text-base-text/30 text-4xl"></i>
</div>
<div class="menu-group-name">
<%= c.name %>
</div>
<% end %>
<% end %>
<div class="menu-group">
<div class="menu-group-icon">
<i class="fa-solid fa-gear text-base-text/30 text-4xl"></i>
</div>
<div class="menu-group-name">
설청
</div>
</div>
</nav>

View File

@ -1,7 +1 @@
<div class="p-4"> <div>MAIN</div>
<div class="flex flex-wrap gap-2 justify-center">
<% @controllers.each do |c| %>
<%= link_to c.name, view_schedule_path(c.id), class: "btn bg-primary" %>
<% end %>
</div>
</div>

View File

@ -1,57 +1,58 @@
<%= form_with url: schedule_edit_update_schedules_path, method: :post, class: 'flex flex-col h-full divide-y divide-border-table-border' do %> <div class="flex flex-col h-full text-white overflow-y-auto ">
<%= hidden_field_tag :controller_id, params[:id] %> <div class="flex flex-col flex-1 divide-y divide-base-border">
<div class="flex-1 p-4"> <%= form_with url: schedule_edit_update_schedules_path, method: :post, class: 'flex flex-col h-full divide-y divide-border-base-border p-4' do %>
<span class="text-2xl font-bold"><%= @controller.name %> 컨트롤러</span> <%= hidden_field_tag :controller_id, params[:id] %>
<table class="base-table"> <div class="space-y-4">
<thead> <div class="flex justify-between">
<tr> <div class="text-2xl font-bold"><%= @controller.name %> 컨트롤러</div>
<th>시간</th> <%= submit_tag "업데이트", class: "btn bg-primary" %>
<th>분</th> </div>
<th>사용여부</th> <table class="base-table">
<th>온도</th> <thead>
<th>삭제</th> <tr>
</tr> <th>시간</th>
</thead> <th>분</th>
<tbody> <th>사용여부</th>
<% @schedule.each do |s| %> <th>온도</th>
<tr> <th>삭제</th>
<td> </tr>
<%= select_tag "schedule[#{s.id}][hour]", </thead>
options_for_select((0..23).map { |h| [h.to_s.rjust(2, '0'), h] }, s.hour), <tbody>
class: "input-style" %> <% @schedule.each do |s| %>
</td> <tr>
<td><%= number_field_tag "schedule[#{s.id}][minute]", s.minute, min: 0, max: 59, step: 1, inputmode: "decimal", class: "input-style" %></td> <td>
<td><%= check_box_tag "schedule[#{s.id}][is_active]", "1", s.is_active == true || s.is_active == 1 %></td> <%= select_tag "schedule[#{s.id}][hour]",
<td><%= number_field_tag "schedule[#{s.id}][temperature]", s.temperature, step: "0.1", inputmode: "decimal", class: "input-style" %></td> options_for_select((0..23).map { |h| [h.to_s.rjust(2, '0'), h] }, s.hour),
<td> class: "input-style" %>
<%= link_to "삭제", schedule_path(s), </td>
data: { <td><%= number_field_tag "schedule[#{s.id}][minute]", s.minute, min: 0, max: 59, step: 1, inputmode: "decimal", class: "input-style" %></td>
turbo_method: :delete, <td><%= check_box_tag "schedule[#{s.id}][is_active]", "1", s.is_active == true || s.is_active == 1 %></td>
turbo_confirm: "정말 삭제하시겠습니까?" <td><%= number_field_tag "schedule[#{s.id}][temperature]", s.temperature, step: "0.1", inputmode: "decimal", class: "input-style" %></td>
}, <td>
class: "btn bg-danger text-sm" %> <%= link_to "삭제", schedule_path(s),
</td> data: {
</tr> turbo_method: :delete,
<% end %> turbo_confirm: "정말 삭제하시겠습니까?"
</tbody> },
</table> class: "btn bg-danger text-sm" %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
<div class="flex p-4 space-x-4">
<%= button_to "초기화", reset_schedule_path(params[:id]),
method: :post,
data: { turbo_confirm: "정말 초기화하시겠습니까? 모든 스케줄 데이터가 삭제됩니다." },
class: "btn bg-danger" %>
<%= button_to "추가하기", open_modals_path(type: "add_schedule", id: params[:id]),
class: "btn bg-default-slate",
data: {
turbo_method: :post,
turbo_frame: "modals"
} %>
</div>
</div> </div>
<div class="flex p-4">
<%= submit_tag "업데이트", class: "btn bg-primary" %>
</div>
<% end %>
<div class="flex p-4">
<%= button_to "초기화", reset_schedule_path(params[:id]),
method: :post,
data: { turbo_confirm: "정말 초기화하시겠습니까? 모든 스케줄 데이터가 삭제됩니다." },
class: "btn bg-danger" %>
</div>
<div class="flex p-4">
<%= button_to "추가하기", open_modals_path(type: "add_schedule", id: params[:id]),
class: "btn bg-default-slate",
data: {
turbo_method: :post,
turbo_frame: "modals"
} %>
</div> </div>

View File

@ -1,28 +1,30 @@
<div class="flex flex-col h-full divide-y divide-border-table-border"> <div class="flex flex-col h-full divide-y divide-base-border text-white">
<div class="flex flex-col flex-1 p-4 space-y-4"> <div class="flex flex-col flex-1 p-4 space-y-4 overflow-y-hidden">
<span class="text-2xl font-bold"><%= @controller.name %> 컨트롤러</span> <div class="overflow-y-auto space-y-4">
<table class="base-table"> <div class="flex justify-between">
<thead> <div class="text-2xl font-bold"><%= @controller.name %> 컨트롤러</div>
<tr> <%= link_to "수정", schedule_edit_schedule_path(@controller.id), class: "btn bg-default-slate" %>
<th>시간</th> </div>
<th>분</th> <table class="base-table">
<th>사용여부</th> <thead>
<th>온도</th>
</tr>
</thead>
<tbody>
<% @schedule.each do |s| %>
<tr> <tr>
<td><%= s.hour %>시</td> <th>시간</th>
<td><%= s.minute %>분</td> <th>분</th>
<td><%= s.is_active %></td> <th>사용여부</th>
<td><%= s.temperature %> °C</td> <th>온도</th>
</tr> </tr>
<% end %> </thead>
</tbody> <tbody>
</table> <% @schedule.each do |s| %>
</div> <tr>
<div class="flex p-4"> <td><%= s.hour %>시</td>
<%= link_to "수정", schedule_edit_schedule_path(@controller.id), class: "btn bg-default-slate" %> <td><%= s.minute %>분</td>
<td><%= s.is_active %></td>
<td><%= s.temperature %> °C</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div> </div>
</div> </div>

View File

@ -0,0 +1 @@
<div>WEB</div>

View File

@ -29,4 +29,7 @@ Rails.application.routes.draw do
post :open post :open
end end
end end
resources :device
resources :web
end end

View File

@ -0,0 +1,7 @@
require "test_helper"
class DeviceControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end

View File

@ -0,0 +1,7 @@
require "test_helper"
class WebControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end