Procházet zdrojové kódy

소스 최신화 및 안정화

KIM-JINO5 před 4 měsíci
rodič
revize
50b5cd99aa
100 změnil soubory, kde provedl 1360 přidání a 1839 odebrání
  1. 1 2
      .env
  2. 2 1
      app/Helpers/common.php
  3. 0 429
      app/Helpers/common.php~
  4. 2 2
      app/Http/Controllers/Account/EmailController.php
  5. 14 2
      app/Http/Controllers/Admin/Page/MenuController.php
  6. 6 1
      app/Http/Controllers/ApiController.php
  7. 1 1
      app/Http/Controllers/DocumentController.php
  8. 0 82
      app/Http/Middleware/Board/PostAccess.php~
  9. 2 2
      app/Http/Middleware/Prepare/Admin.php
  10. 9 8
      app/Http/Middleware/Prepare/Front.php
  11. 1 1
      app/Http/Middleware/VerifyCsrfToken.php
  12. 1 0
      app/Models/Comment.php
  13. 4 2
      app/Models/Menu.php
  14. 0 247
      app/Policies/PostPolicy.php~
  15. 1 1
      app/Providers/AppServiceProvider.php
  16. 1 1
      app/Rules/IsPhone.php
  17. 0 37
      config/visitor.php~
  18. 139 0
      lang/ko/validation-inline.php
  19. 3 3
      package-lock.json
  20. 48 1
      public/css/auth/verify.css
  21. 1 54
      public/css/common/auth/login.css
  22. 55 1
      public/css/common/auth/passwords.css
  23. 0 32
      public/css/common/font.css
  24. 17 1
      public/css/desktop/account/certify.css
  25. 1 35
      public/css/desktop/account/comment.css
  26. 1 20
      public/css/desktop/account/leave.css
  27. 29 1
      public/css/desktop/account/modify.css
  28. 36 1
      public/css/desktop/account/passwords.css
  29. 1 26
      public/css/desktop/account/profile.css
  30. 0 0
      public/css/desktop/board/index.css
  31. 0 0
      public/css/desktop/board/latest.css
  32. 47 1
      public/css/desktop/board/tag.css
  33. 23 1
      public/css/mobile/account/loginLog.css
  34. 36 1
      public/css/mobile/account/modify.css
  35. 31 1
      public/css/mobile/account/passwords.css
  36. 1 78
      public/css/mobile/account/post.css
  37. 0 107
      public/css/mobile/board/comment.css
  38. 0 0
      public/css/mobile/board/index.css
  39. 66 14
      public/css/mobile/board/latest.css
  40. 30 1
      public/css/mobile/board/write.css
  41. 1 8
      public/css/mobile/document.css
  42. 0 0
      public/css/mobile/layout.css
  43. 0 113
      public/css/mobile/main.css
  44. 1 1
      resources/css/app.css
  45. 19 0
      resources/sass/_variables.scss
  46. 0 2
      resources/sass/app.scss
  47. 0 0
      resources/sass/bootstrap/scss/bootstrap
  48. 3 0
      resources/sass/common/font.scss
  49. 170 119
      resources/sass/desktop/board/latest.scss
  50. 3 1
      resources/sass/mobile/account/loginLog.scss
  51. 104 45
      resources/sass/mobile/board/index.scss
  52. 104 45
      resources/sass/mobile/board/latest.scss
  53. 1 0
      resources/views/admin/layouts/app.blade.php
  54. 25 4
      resources/views/admin/page/menu/index.blade.php
  55. 0 0
      resources/views/auth/layout.blade.php
  56. 1 1
      resources/views/auth/login.blade.php
  57. 1 1
      resources/views/auth/passwords/confirm.blade.php
  58. 1 1
      resources/views/auth/passwords/email.blade.php
  59. 1 1
      resources/views/auth/passwords/reset.blade.php
  60. 1 1
      resources/views/auth/register.blade.php
  61. 1 1
      resources/views/auth/verify.blade.php
  62. 0 51
      resources/views/board/comment/pagination.blade.php
  63. 0 108
      resources/views/board/component/media.blade.php
  64. 1 1
      resources/views/component/pagination.blade.php
  65. 3 1
      resources/views/component/uploader.blade.php
  66. 2 2
      resources/views/desktop/account/certify.blade.php
  67. 2 2
      resources/views/desktop/account/comment.blade.php
  68. 0 0
      resources/views/desktop/account/email.blade.php
  69. 2 3
      resources/views/desktop/account/leave.blade.php
  70. 2 2
      resources/views/desktop/account/loginLog.blade.php
  71. 2 3
      resources/views/desktop/account/modify.blade.php
  72. 0 0
      resources/views/desktop/account/navTabs.blade.php
  73. 2 2
      resources/views/desktop/account/passwordCampaign.blade.php
  74. 2 2
      resources/views/desktop/account/passwordChange.blade.php
  75. 2 2
      resources/views/desktop/account/post.blade.php
  76. 4 12
      resources/views/desktop/account/profile.blade.php
  77. 0 0
      resources/views/desktop/board/comment/error.blade.php
  78. 1 1
      resources/views/desktop/board/comment/index.blade.php
  79. 0 0
      resources/views/desktop/board/comment/write.blade.php
  80. 1 1
      resources/views/desktop/board/component/inquiry.blade.php
  81. 70 82
      resources/views/desktop/board/component/latest.blade.php
  82. 106 0
      resources/views/desktop/board/component/media.blade.php
  83. 0 0
      resources/views/desktop/board/component/notice.blade.php
  84. 0 0
      resources/views/desktop/board/component/pagination.blade.php
  85. 3 3
      resources/views/desktop/board/component/post.blade.php
  86. 0 0
      resources/views/desktop/board/component/search.blade.php
  87. 0 0
      resources/views/desktop/board/component/tab.blade.php
  88. 1 1
      resources/views/desktop/board/edit.blade.php
  89. 5 5
      resources/views/desktop/board/index.blade.php
  90. 1 1
      resources/views/desktop/board/tag.blade.php
  91. 3 3
      resources/views/desktop/board/view.blade.php
  92. 1 1
      resources/views/desktop/board/write.blade.php
  93. 1 1
      resources/views/desktop/document/index.blade.php
  94. 4 4
      resources/views/desktop/layouts/app.blade.php
  95. 89 0
      resources/views/desktop/layouts/sub.blade.php
  96. 1 1
      resources/views/desktop/main.blade.php
  97. 2 2
      resources/views/desktop/recently.blade.php
  98. 0 0
      resources/views/desktop/service/anniversary/index.blade.php
  99. 0 0
      resources/views/desktop/service/fifa/index.blade.php
  100. 0 0
      resources/views/desktop/service/financial/exchange.blade.php

+ 1 - 2
.env

@@ -60,5 +60,4 @@ VITE_PUSHER_PORT="${PUSHER_PORT}"
 VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
 VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
 
-ENCRYPT_KEY="@@20120726KKh";
-ENCRYPT_IV="@@20120726KKh"
+MOVIE_API="http://192.168.0.10:1050"

+ 2 - 1
app/Helpers/common.php

@@ -257,6 +257,7 @@ function alert(string $msg, string|null $url = "", bool $redirect = true): Illum
     $msg = preg_replace('/(\r\n|\r|\n)/', '\n', addslashes($msg)); // 줄바꿈 되도록 출력
     $msg = strip_tags(trim($msg), '<br/>'); // 태그 제거, 공백 제거
     $msg = preg_replace('/<br[^>]*>/i', '\n\n', $msg); // br 태그를 \n로 개행 alert 에서 다음줄로 하기 위함.
+
     if ($redirect) {
         if ($url) {
             return redirect($url)->withErrors($msg)->withInput();
@@ -425,7 +426,7 @@ function listNum(int $total, int $page, int $perPage): int
  */
 function layout(string $viewPath): string
 {
-    return (DEVICE_TYPE != DEVICE_TYPE_1 ? ('mobile.' . $viewPath) : $viewPath);
+    return (DEVICE_TYPE != DEVICE_TYPE_1 ? 'mobile.' : 'desktop.') . $viewPath;
 }
 
 /*

+ 0 - 429
app/Helpers/common.php~

@@ -1,429 +0,0 @@
-<?php
-
-// 전체 배열의 키를 대문자, 소문자로 변경해서 반환한다.
-function arrayChangeKeyCaseRecursive($arr = [], $case = CASE_LOWER): string
-{
-    return array_map(function ($item) use ($case) {
-        if (is_array($item)){
-            $item = arrayChangeKeyCaseRecursive($item, $case);
-        }
-        return $item;
-    }, array_change_key_case($arr, $case));
-}
-
-// Request Url
-function currentURL(): string
-{
-    $protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http");
-    $host = (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost');
-    $query = (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '');
-    return sprintf("%s://%s%s", $protocol, $host, $query);
-}
-
-// 데이터 단위 변환
-function byteFormat($num, $precision = 1): string
-{
-    if ($num >= 1000000000000) {
-        $num = round($num / 1099511627776, $precision);
-        $unit = 'TB';
-    } elseif ($num >= 1000000000) {
-        $num = round($num / 1073741824, $precision);
-        $unit = 'GB';
-    } elseif ($num >= 1000000) {
-        $num = round($num / 1048576, $precision);
-        $unit = 'MB';
-    } elseif ($num >= 1000) {
-        $num = round($num / 1024, $precision);
-        $unit = 'KB';
-    } else {
-        $unit = 'Bytes';
-        return number_format($num) . ' ' . $unit;
-    }
-    return number_format($num, $precision) . ' ' . $unit;
-}
-
-// 데이터 단위 지정 변환
-function byteToFormat($bytes = 0, $unit = "", $decimals = 0): string
-{
-    $units = ['B' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4, 'PB' => 5, 'EB' => 6, 'ZB' => 7, 'YB' => 8];
-    $value = 0;
-    if ($bytes > 0) {
-        if (!array_key_exists($unit, $units)) {
-            $pow = floor(log($bytes) / log(1024));
-            $unit = array_search($pow, $units);
-        }
-        $value = ($bytes / pow(1024, floor($units[$unit])));
-    }
-    if (!is_numeric($decimals) || $decimals < 0) {
-        $decimals = 2;
-    }
-    return sprintf('%.' . $decimals . 'f ' . $unit, $value);
-}
-
-// 상태 보기
-function show($varName): string
-{
-    switch ($result = get_cfg_var($varName)) {
-        case 0:
-            return '<span class="text-danger">Off</span>';
-        case 1:
-            return '<span class="text-success">On</span>';
-        default:
-            return $result;
-    }
-}
-
-// 리눅스 시스템 보기 - 파일권한
-function isFun($funName = ""): string
-{
-    if (!$funName || trim($funName) == '' || preg_match('~[^a-z0-9\_]+~i', $funName, $tmp)) {
-        return '알수없음';
-    } else {
-        return (false !== function_exists($funName)) ? '<span class="text-success">사용가능</span>' : '<span class="text-danger">Г—</span>';
-    }
-}
-
-// 리눅스 시스템 보기 - CPU 모델
-function GetCoreInformation(): array
-{
-    $data = @file('/proc/stat');
-    $cores = [];
-
-    if($data) {
-        foreach ($data as $line) {
-            if (preg_match('/^cpu[0-9]/', $line)) {
-                $info = explode(' ', $line);
-                $cores[] = ['user' => $info[1], 'nice' => $info[2], 'sys' => $info[3], 'idle' => $info[4], 'iowait' => $info[5], 'irq' => $info[6], 'softirq' => $info[7]];
-            }
-        }
-    }
-
-    return $cores;
-}
-
-// 리눅스 시스템 보기 CPU 속도
-function GetCpuPercentages($stat1 = [], $stat2 = []): array
-{
-    $cpus = [];
-    if (count($stat1) !== count($stat2)) {
-        return $cpus;
-    }
-
-    for ($i = 0, $l = count($stat1); $i < $l; $i++) {
-        $dif = [];
-        $dif['user'] = ($stat2[$i]['user'] - $stat1[$i]['user']);
-        $dif['nice'] = ($stat2[$i]['nice'] - $stat1[$i]['nice']);
-        $dif['sys'] = ($stat2[$i]['sys'] - $stat1[$i]['sys']);
-        $dif['idle'] = ($stat2[$i]['idle'] - $stat1[$i]['idle']);
-        $dif['iowait'] = ($stat2[$i]['iowait'] - $stat1[$i]['iowait']);
-        $dif['irq'] = ($stat2[$i]['irq'] - $stat1[$i]['irq']);
-        $dif['softirq'] = ($stat2[$i]['softirq'] - $stat1[$i]['softirq']);
-        $total = array_sum($dif);
-        $cpu = [];
-
-        foreach ($dif as $x => $y) {
-            $cpu[$x] = round($y / $total * 100, 2);
-        }
-        $cpus['cpu' . $i] = $cpu;
-    }
-    return $cpus;
-}
-
-// 현재 URL 이 대상 URL 과 같다면 active 상태
-function activeUrl($segment = ''): string
-{
-    return (request()->is($segment) ? 'active' : '');
-}
-
-// 관리자 설정값 조회
-function configs($item = '', $default = ''): string|int|null
-{
-    $config = cache('config-meta');
-
-    if($item) {
-        $ret = (property_exists($config, $item) ? $config->{$item} : $default);
-    }else{
-        $ret = $config;
-    }
-
-    return $ret;
-}
-
-// 게시판 에디터 출력
-function htmlEditor($name = '', $content = '', $className = '', $isDhtmlEditor = true, $emoticonYN = true, $placeholder = "", $rows = 0, $id = ''): string
-{
-    // TINYMCE 에디터 추가
-    $html = "";
-
-    if ($isDhtmlEditor && !defined('LOAD_DHTML_EDITOR_JS'))
-    {
-        // tinymce iframe 허용
-        $whiteIframe = configs('white_iframe');
-        $whiteIframe = preg_replace("/[\r|\n|\r\n]+/", ",", $whiteIframe);
-        $whiteIframe = preg_replace("/\s+/", "", $whiteIframe);
-
-        $html .= PHP_EOL . '<script type="module">';
-
-        // 아이프레임 주소 허용여부 결정
-        $html .= sprintf('var whiteIframe = "%s";', $whiteIframe);
-
-        // 이모티콘 사용여부
-        $html .= sprintf('var useEmoticon = "%s";', ($emoticonYN ? 'Y' : 'N'));
-
-        $html .= '</script>';
-
-        define('LOAD_DHTML_EDITOR_JS', true);
-    }
-
-    $html .= '<textarea';
-    $html .= sprintf(' class="tinymce-editor %s"', $className);
-
-    if($name) {
-        $html .= sprintf(' name="%s"', $name);
-    }
-
-    if($id) {
-        $html .= sprintf(' id="%s"', $id);
-    }
-
-    if($placeholder) {
-        $html .= sprintf(' placeholder="%s"', $placeholder);
-    }
-
-    if ($rows) {
-        $html .= sprintf(' rows="%s"', $rows);
-    }
-
-    $html .= ('>' . htmlspecialchars($content) . '</textarea>');
-
-    return $html;
-}
-
-// 관리자 Form Submit 정보 attributes 와 맵핑
-function mapAdminAttr(array $rules, array $posts): array
-{
-    foreach(array_keys($rules) as $field) {
-        if(array_key_exists($field, $posts)) {
-            continue;
-        }
-        $posts[$field] = 0;
-    }
-    return $posts;
-}
-
-// FreeBSD 값 조회
-function getKey($keyName): bool
-{
-    return doCommand('sysctl', "-n $keyName");
-}
-
-// FreeBSD 시스템 명령 실행
-function doCommand($commandName, $args): bool
-{
-    $buffer = "";
-    if (false === ($command = findCommand($commandName))) {
-        return false;
-    }
-    if ($fp = @popen("$command $args", 'r')) {
-        while (!@feof($fp)) {
-            $buffer .= @fgets($fp, 4096);
-        }
-        return trim($buffer);
-    }
-    return false;
-}
-
-// FreeBSD 명령어 지정 조회
-function findCommand($commandName)
-{
-    $path = ['/bin', '/sbin', '/usr/bin', '/usr/sbin', '/usr/local/bin', '/usr/local/sbin'];
-    foreach ($path as $p) {
-        if (@is_executable("$p/$commandName")) {
-            return "$p/$commandName";
-        }
-    }
-    return false;
-}
-
-// 날짜와 시간에 <br/>, \n 추가
-function dateBr($date = null, $default = ''): string
-{
-    return ($date ? date('Y-m-d <\b\r /> H:i:s', strtotime($date)) : $default);
-}
-
-// Alert 띄우기
-function alert(string $msg, string|null $url = "", bool $redirect = true): Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse|Illuminate\Http\Response|\Illuminate\Contracts\Routing\ResponseFactory
-{
-    $msg = preg_replace('/(\r\n|\r|\n)/', '\n', addslashes($msg)); // 줄바꿈 되도록 출력
-    $msg = strip_tags(trim($msg), '<br/>'); // 태그 제거, 공백 제거
-    $msg = preg_replace('/<br[^>]*>/i', '\n\n', $msg); // br 태그를 \n로 개행 alert 에서 다음줄로 하기 위함.
-    if ($redirect) {
-        if ($url) {
-            return redirect($url)->withErrors($msg)->withInput();
-        } else {
-            return back()->withErrors($msg)->withInput();
-        }
-    }else{
-        return response(
-            sprintf('<script>alert("%s");</script>', $msg)
-        , 200, ['Content-Type', 'text/javascript']);
-    }
-}
-
-// 로그인 확인
-function loginCheck(string $callback = null): Illuminate\Http\Response|\Illuminate\Contracts\Routing\ResponseFactory
-{
-    $s = "<script>";
-    $s .= "if (confirm(\"로그인 후 이용하실 수 있습니다.\\n로그인 화면으로 이동하시겠습니까?\")) {";
-    $s .= "location.href = \"" . route('login') . "?callback=" . urlencode(url($_SERVER['REQUEST_URI']) ?? $callback) . "\";";
-    $s .= '} else if(document.referrer) { history.go(-1); console.log(2); ';
-    $s .= '} else { window.close(); console.log(1); }';
-    $s .= '</script>';
-    return response($s, 200, ['Content-Type', 'text/javascript']);
-}
-
-// Alert 후 창 닫음
-function alertClose(string $msg): Illuminate\Http\Response|\Illuminate\Contracts\Routing\ResponseFactory
-{
-    $s = "<script>";
-    $s .= "alert(\"$msg\");";
-    $s .= "self.close();";
-    $s .= "window.close();";
-    $s .= "</script>";
-    return response($s, 200, ['Content-Type', 'text/javascript']);
-}
-
-// 성인인증 알림
-function confirmToAdult(string $callback = null): Illuminate\Http\Response|\Illuminate\Contracts\Routing\ResponseFactory
-{
-    $s = "<script>";
-    $s .= "if (confirm(\"해당 상품은 성인인증이 필요합니다.\\n로그인 화면으로 이동하시겠습니까?\")) {";
-    $s .= "location.href = \"" . route('login') . "?callback=" . urlencode(url($_SERVER['REQUEST_URI']) ?? $callback) . "\";";
-    if(DEVICE_TYPE != DEVICE_TYPE_1) { // 모바일
-        $s .= '} else { history.back(); }';
-    }else{ // PC
-        $s .= '} else { window.close(); }';
-    }
-    $s .= "</script>";
-    return response($s, 200, ['Content-Type', 'text/javascript']);
-}
-
-
-// Send socket
-function getSock(string $url): string
-{
-    // host 와 uri 를 분리
-    $host = "";
-    $get = "";
-
-    if (preg_match("/http:\/\/([a-zA-Z0-9_\-\.]+)([^<]*)/", $url, $res)) {
-        $host = $res[1];
-        $get = $res[2];
-    }
-
-    // 80번 포트로 소캣접속 시도
-    $fp = fsockopen($host, 80, $n, $s, 30);
-    if (empty($fp)) {
-        die($s . ' (' . $n . ")\n");
-    } else {
-        fputs($fp, "GET $get HTTP/1.0\r\n");
-        fputs($fp, "Host: $host\r\n");
-        fputs($fp, "\r\n");
-
-        $header = '';
-        // header 와 content 를 분리한다.
-        while (trim($buffer = fgets($fp, 1024)) !== '') {
-            $header .= $buffer;
-        }
-        while (!feof($fp)) {
-            $buffer .= fgets($fp, 1024);
-        }
-    }
-    fclose($fp);
-
-    // content 만 return 한다.
-    return $buffer;
-}
-
-// 휴대폰 번호 조회
-function getTelNumber($phone, $hyphen = 1): string
-{
-    if ($hyphen) {
-        $preg = "$1-$2-$3";
-    } else {
-        $preg = "$1$2$3";
-    }
-
-    $phone = str_replace('-', '', trim($phone));
-    return preg_replace(
-        "/^(01[016789])([0-9]{3,4})([0-9]{4})$/",
-        $preg,
-        $phone
-    );
-}
-
-// 수행 측정시간
-function getTime(): float
-{
-    $t = explode(' ', microtime());
-    return (float)$t[0] + (float)$t[1];
-}
-
-/**
- * iframe tag 조회
- */
-function getIframeTag($string = '', $onlySrc = false)
-{
-    preg_match('/<iframe.*src=\"(.*)\".*><\/iframe>/isU', $string, $matches);
-    if ($onlySrc) {
-        return (isset($matches[1])) ? $matches[1] : ""; // the src part. (http://www.youtube.com/embed/IIYeKGNNNf4?rel=0)
-    } else {
-        return (isset($matches[0])) ? $matches[0] : ""; // only the <iframe ...></iframe> part
-    }
-}
-
-/*
- * 이미지 인지 여부
- */
-function isImage($path = ''): int
-{
-    return intval(in_array(getimagesize($path)[2], [IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP]));
-}
-
-/*
- * 문자 검색 후 강조
- */
-function highlight($search, $str): string
-{
-    return (!is_null($search)) ? preg_replace( '#' . preg_quote($search,'#') . '#iu', '<span style="background: #ff9632;color: #000;">$0</span>', $str) : $str;
-}
-
-/*
- * 모든 공백 제거
- */
-function aTrim($str): string
-{
-    return preg_replace('/\s+/', '', $str);
-}
-
-/*
- * 목록 시작 번호
- * currentItems: same as limit
- * currentPage: floor(start / limit)
- * totalPages: ceil(totalItems / limit)
- * last: totalPages * limit
- * previous: (currentPage-1) * limit
- * next: (currentPage+1) * limit
- */
-function listNum(int $total, int $page, int $perPage): int
-{
-    return (($listNum = ($total - ($page - 1) * $perPage)) > 0 ? $listNum : $total);
-}
-
-/*
- * 단말기 구분으로 레이아웃 처리
- */
-function layout(string $viewPath): string
-{
-    return (DEVICE_TYPE != DEVICE_TYPE_1 ? ('mobile.' . $viewPath) : $viewPath);
-}

+ 2 - 2
app/Http/Controllers/Account/EmailController.php

@@ -50,7 +50,7 @@ class EmailController extends Controller
 
             $posts = $this->validate($request, $rules, $messages, $attributes);
 
-            if($this->userEmailLogModel->isUpdateAble(UID)) {
+            if(!$this->userEmailLogModel->isUpdateAble(UID)) {
                 throw new Exception(
                     sprintf('이메일 변경은 %d일 지난 후 가능합니다.', $this->userEmailLogModel->getDayLeft(UID))
                 );
@@ -67,7 +67,7 @@ class EmailController extends Controller
                 'name' => $name,
                 'email' => $posts['email'],
             ];
-            Mail::to($sender)->send(new VerifyCode($verifyCode, $posts['email']));
+            Mail::to($sender)->send(new VerifyCode($verifyCode, $verifyExpiresAt, UID));
 
             // 쿠키 생성
             $sender->verifyCode = $verifyCode;

+ 14 - 2
app/Http/Controllers/Admin/Page/MenuController.php

@@ -5,6 +5,7 @@
  */
 namespace App\Http\Controllers\Admin\Page;
 
+use App\Models\Board;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Validator;
 use App\Http\Controllers\Controller;
@@ -13,10 +14,12 @@ use App\Models\Menu;
 class MenuController extends Controller
 {
     private Menu $menuModel;
+    private Board $boardModel;
 
-    public function __construct(Menu $menu)
+    public function __construct(Menu $menu, Board $board)
     {
         $this->menuModel = $menu;
+        $this->boardModel = $board;
     }
 
     /**
@@ -37,9 +40,13 @@ class MenuController extends Controller
             }
         }
 
+        // 게시판 목록 조회
+        $boardList = $this->boardModel->all();
+
         return view('admin.page.menu.index', [
             'actionURL' => route('admin.page.menu.store'),
-            'menuData' => $menuData
+            'menuData' => $menuData,
+            'boardList' => $boardList
         ]);
     }
 
@@ -52,6 +59,7 @@ class MenuController extends Controller
     {
         $rules = [
             'menu_id' => 'nullable|numeric',
+            'board_id' => 'nullable|numeric|exists:tb_board,id',
             'name' => 'string',
             'link' => 'string',
             'target' => 'string|nullable',
@@ -64,6 +72,7 @@ class MenuController extends Controller
 
         $attributes = [
             'menu_id' => '메뉴 PK',
+            'board_id' => '게시판 PK',
             'name' => '메뉴명',
             'link' => 'URL',
             'target' => '새창 여부',
@@ -96,6 +105,7 @@ class MenuController extends Controller
                 $updateData = [
                     'menu_id' => $menuID,
                     'parent_id' => ($posts['parent_id'][$menuID] ?? ''),
+                    'board_id' => ($posts['board_id'][$menuID] ?? ''),
                     'name' => ($posts['name'][$menuID] ?? ''),
                     'link' => ($posts['link'][$menuID] ?? ''),
                     'target' => ($posts['target'][$menuID] ?? ''),
@@ -109,6 +119,7 @@ class MenuController extends Controller
                 $rules = [
                     'menu_id' => 'required|numeric|exists:tb_menu,id',
                     'parent_id' => 'required|numeric|exists:tb_menu,parent_id',
+                    'board_id' => 'required|numeric|exists:tb_board,id',
                     'name' => 'string',
                     'link' => 'string',
                     'target' => 'numeric|in:1,0',
@@ -122,6 +133,7 @@ class MenuController extends Controller
                 $attributes = [
                     'menu_id' => '메뉴 PK',
                     'parent_id' => '부모 메뉴 PK',
+                    'board_id' => '게시판 PK',
                     'name' => '메뉴명',
                     'link' => 'URL',
                     'target' => '새창 여부',

+ 6 - 1
app/Http/Controllers/ApiController.php

@@ -140,7 +140,12 @@ class ApiController extends Controller
             }
 
             // 중복 여부
-            if ((new User)->where('nickname', $nickname)->exists()) {
+            if (
+                (new User)->where([
+                    ['nickname', $nickname],
+                    ['user_id', UID]
+                ])->exists()
+            ) {
                 throw new Exception;
             }
 

+ 1 - 1
app/Http/Controllers/DocumentController.php

@@ -24,7 +24,7 @@ class DocumentController extends Controller
             abort(404);
         }
 
-        return view(layout('document'), [
+        return view(layout('document.index'), [
             'title' => $document->subject,
             'content' => $document->content,
             'writeURL' => route('admin.page.document.edit', $document->id)

+ 0 - 82
app/Http/Middleware/Board/PostAccess.php~

@@ -1,82 +0,0 @@
-<?php
-
-namespace App\Http\Middleware\Board;
-
-use Closure;
-use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Gate;
-use App\Services\BoardService;
-use App\Services\PostService;
-
-class PostAccess
-{
-    public function handle(Request $request, Closure $next)
-    {
-        $code = $request->route('code');
-        $postID = $request->route('postID');
-
-        // 게시판 코드 확인
-        if (!$code || !$postID) {
-            abort(404);
-        }
-
-        $boardService = new BoardService();
-
-        // 게시판 정보 조회
-        $board = $boardService->find($code);
-
-        // 게시판 존재 유무
-        if (!$board->exists) {
-            return alert('존재하지 않는 게시판입니다.', DIRECTORY_SEPARATOR);
-        }
-
-        // 게시판 사용 여부
-        if ($board->is_display == 0) {
-            return alert('더 이상 사용하지 않는 게시판입니다.', DIRECTORY_SEPARATOR);
-        }
-
-        $postService = new PostService();
-
-        // 게시글 조회
-        $post = $postService->find($postID);
-        $boardIndexURL = route('board.list', $code);
-
-        // 게시글 존재 유무
-        if (!$post->exists) {
-            return alert('존재하지 않는 게시글입니다.', $boardIndexURL);
-        }
-
-        // 게시판 정보 조회
-        $boardMeta = $boardService->meta($board->id);
-
-        // 보기 권한 확인
-        $response = Gate::inspect('view', [$post, $boardMeta]);
-        echo '<pre>';var_dump($response->denied());echo '</pre>';exit;
-        if($response->denied()) {
-            if($response->code() == 401) {
-                return loginCheck($boardIndexURL);
-            }else{
-                return alert($response->message(), $boardIndexURL);
-            }
-        }
-
-        // 신고 시 숨김
-        if (
-            $boardMeta->item('use_blame', 0)
-            && $post->blame >= $boardMeta->item('blame_blind_count', 0)
-        ) {
-            return alert('신고 누적으로 비공개 처리되었습니다. 해당 게시글은 관리자 확인 후 이용규칙에 따라 처리됩니다.', $boardIndexURL);
-        }
-
-        // 게시글 조회 수 증가
-        $postService->addHit($post);
-
-        $request->merge([
-            'board' => $board,
-            'boardMeta' => $boardMeta,
-            'post' => $post
-        ]);
-
-        return $next($request);
-    }
-}

+ 2 - 2
app/Http/Middleware/Prepare/Admin.php

@@ -43,13 +43,13 @@ class Admin
         foreach ($menus as $controller => $row) {
             $info = (key($row) == '/' ? current($row) : $row);
 
-            if($parent) {
+            if ($parent) {
                 $segment = [
                     ADMIN_PATH,
                     $parent,
                     $controller
                 ];
-            }else{
+            } else {
                 $segment = [
                     ADMIN_PATH,
                     $controller

+ 9 - 8
app/Http/Middleware/Prepare/Front.php

@@ -40,15 +40,16 @@ class Front
                             continue;
                         }
                     }
-                    $row = $menuModel->findCategory($row->id);
-                    $row->hasChildren = $row->children->count();
-                    $row->isRoot = $row->isRoot();
-                    $row->isLeaf = $row->isLeaf();
-                    $row->url = url($row->link);
-                    $row->target = ($row->target ? '_blank' : '_self');
+                    $mn = $menuModel->findCategory($row->id);
+                    $mn->hasChildren = $mn->children->count();
+                    $mn->isRoot = $mn->isRoot();
+                    $mn->isLeaf = $mn->isLeaf();
+                    $mn->url = url($mn->link);
+                    $mn->target = ($mn->target ? '_blank' : '_self');
+                    $mn->postCount = $row->postCount;
 
-                    $ret['topMenu'][$row->parent_id][] = $row;
-                    $ret['subMenu'][$row->id] = $row;
+                    $ret['topMenu'][$mn->parent_id][] = $mn;
+                    $ret['subMenu'][$mn->id] = $mn;
                 }
             }
             Cache::put($menuModel->cacheName_2, $ret, $menuModel->cacheTime);

+ 1 - 1
app/Http/Middleware/VerifyCsrfToken.php

@@ -12,6 +12,6 @@ class VerifyCsrfToken extends Middleware
      * @var array<int, string>
      */
     protected $except = [
-        // 토스 웹훅은 CSRF 검증에서 제외
+        //
     ];
 }

+ 1 - 0
app/Models/Comment.php

@@ -92,6 +92,7 @@ class Comment extends Model
             'tb_board.name AS boardName',
             'tb_board.code',
             'tb_post.subject',
+            'users.id',
             'users.sid',
             'users.name',
             'users.email'

+ 4 - 2
app/Models/Menu.php

@@ -71,6 +71,7 @@ class Menu extends Model
     {
         $insertData = [
             $insertData['menu_id'],
+            $insertData['board_id'],
             $insertData['name'],
             $insertData['link'],
             $insertData['target'],
@@ -81,7 +82,7 @@ class Menu extends Model
             $insertData['depth']
         ];
 
-        $menuID = DB::selectOne("CALL SP_MENU_SAVE(?, ?, ?, ?, ?, ?, ?, ?, ?);", $insertData)->id;
+        $menuID = DB::selectOne("CALL SP_MENU_SAVE(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", $insertData)->id;
 
         $this->reload();
         return $menuID;
@@ -92,9 +93,10 @@ class Menu extends Model
      */
     public function updater(array $updateData): void
     {
-        DB::select("CALL SP_MENU_UPDATE(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", [
+        DB::select("CALL SP_MENU_UPDATE(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", [
             $updateData['menu_id'],
             $updateData['parent_id'],
+            $updateData['board_id'],
             $updateData['name'],
             $updateData['link'],
             $updateData['target'],

+ 0 - 247
app/Policies/PostPolicy.php~

@@ -1,247 +0,0 @@
-<?php
-
-namespace App\Policies;
-
-use Illuminate\Auth\Access\HandlesAuthorization;
-use App\Models\Board;
-use App\Models\BoardMeta;
-use App\Models\Post;
-use App\Models\User;
-use App\Services\PostService;
-use App\Services\CommentService;
-
-class PostPolicy
-{
-    use HandlesAuthorization;
-
-    public PostService $postService;
-
-    /**
-     * Create a new policy instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        $this->postService = new PostService();
-        $this->commentService = new CommentService();
-    }
-
-    /**
-     * Determine whether the user can view any models.
-     *
-     * @param  \App\Models\User  $user
-     * @return \Illuminate\Auth\Access\Response|bool
-     */
-    public function viewAny(User $user)
-    {
-        //
-    }
-
-    /**
-     * Determine whether the user can view the model.
-     *
-     * @param  \App\Models\User  $user
-     * @param  \App\Models\Post  $post
-     * @param  \App\Models\BoardMeta  $boardMeta
-     * @return \Illuminate\Auth\Access\Response|bool
-     */
-    public function view(?User $user, Post $post, BoardMeta $boardMeta)
-    {
-        // 게시글 보기 권한 확인
-        $permitValue = $boardMeta->item(BOARD_PERMIT_TYPE_2);
-        if ($permitValue == 1 && !$user) {
-            return $this->deny('로그인 후 이용 해주세요.', 401);
-        } else if ($permitValue == 100 && !$user?->isAdministrator()) {
-            return $this->deny(MAP_BOARD_PERMIT_ALERT_TYPE[BOARD_PERMIT_TYPE_2]);
-        }
-echo '<pre>';print_r($permitValue);echo '</pre>';exit;
-        // 1:1 문의 게시판은 로그인 필수
-        if ($post->is_secret) {
-            if (!$user) {
-                return $this->deny('로그인 후 이용 해주세요.', 401);
-            }
-            if($user->id != $post->user_id) {
-                return $this->deny(MAP_BOARD_PERMIT_ALERT_TYPE[BOARD_PERMIT_TYPE_2]);
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Determine whether the user can create models.
-     *
-     * @param  \App\Models\User  $user
-     * @param  \App\Models\Board  $board
-     * @param  \App\Models\BoardMeta  $boardMeta
-     * @return \Illuminate\Auth\Access\Response|bool
-     */
-    public function create(?User $user, Board $board, BoardMeta $boardMeta)
-    {
-        // 게시글 쓰기 권한 확인
-        $permitValue = $boardMeta->item(BOARD_PERMIT_TYPE_3, 0);
-        if ($permitValue == 1 && !$user) {
-            return $this->deny('로그인 후 이용 해주세요.', 401);
-        } else if ($permitValue == 100 && !$user?->isAdministrator()) {
-            return $this->deny(MAP_BOARD_PERMIT_ALERT_TYPE[BOARD_PERMIT_TYPE_3]);
-        }
-
-        // 1:1 문의 게시판은 로그인 필수
-        if($boardMeta->item('use_personal', 0)) {
-            if(!$user) {
-                return $this->deny('로그인 후 이용 해주세요.', 401);
-            }
-        }
-
-        // 글 한개만 작성 가능
-        if ($boardMeta->item('use_only_one_post', 0)) {
-            if ($this->postService->userPostRows($board, $user) >= 1) {
-                return $this->deny('이 게시판은 하루에 한 글만 작성 가능합니다.');
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Determine whether the user can update the model.
-     *
-     * @param  \App\Models\User  $user
-     * @param  \App\Models\Post  $post
-     * @param  \App\Models\BoardMeta  $boardMeta
-     * @return \Illuminate\Auth\Access\Response|bool
-     */
-    public function update(?User $user, Post $post, BoardMeta $boardMeta)
-    {
-        if(!$user && $post->user_id) {
-            return $this->deny('로그인 후 이용 해주세요.', 401);
-        }else if(!$post->user_id) {
-            return true;
-        }
-
-        // 게시글 수정 금지 기간 확인
-        if(($protectPostDay = $boardMeta->item('protect_post_day', 0)) > 0) {
-            if((time() - strtotime($post->created_at)) >= ($protectPostDay * 86400)) {
-                return $this->deny(sprintf('%d일 이상된 게시글은 수정이 불가합니다.', $protectPostDay));
-            }
-        }
-
-        // 게시글 수정 보호
-        if($boardMeta->item('protect_update_post', 0) > 0) {
-            if($post->comment_rows > 0) {
-                return $this->deny('댓글이 달린 게시글은 수정이 불가합니다.');
-            }
-        }
-
-        return ($user->id == $post->user_id ? true : $this->deny("권한이 없습니다."));
-    }
-
-    /**
-     * Determine whether the user can delete the model.
-     *
-     * @param  \App\Models\User  $user
-     * @param  \App\Models\Post  $post
-     * @param  \App\Models\BoardMeta  $boardMeta
-     * @return \Illuminate\Auth\Access\Response|bool
-     */
-    public function delete(?User $user, Post $post, BoardMeta $boardMeta)
-    {
-        if(!$user && $post->user_id) {
-            return $this->deny('로그인 후 이용 해주세요.', 401);
-        }else if(!$post->user_id) {
-            return true;
-        }
-
-        // 게시글 삭제 금지 기간 확인
-        if(($protectPostDay = $boardMeta->item('protect_post_day', 0)) > 0) {
-            if((time() - strtotime($post->created_at)) >= ($protectPostDay * 86400)) {
-                return $this->deny(sprintf('%d일 이상된 게시글은 삭제가 불가합니다.', $protectPostDay));
-            }
-        }
-
-        // 게시글 삭제 보호
-        if($boardMeta->item('protect_delete_post', 0) > 0) {
-            if($post->comment_rows > 0) {
-                return $this->deny('댓글이 달린 게시글은 삭제가 불가 합니다.');
-            }
-        }
-
-        return ($user->id == $post->user_id ? true : $this->deny("권한이 없습니다."));
-    }
-
-    /**
-     * Determine whether the user can restore the model.
-     *
-     * @param  \App\Models\User  $user
-     * @param  \App\Models\Post  $post
-     * @return \Illuminate\Auth\Access\Response|bool
-     */
-    public function restore(User $user, Post $post)
-    {
-        //
-    }
-
-    /**
-     * Determine whether the user can permanently delete the model.
-     *
-     * @param  \App\Models\User  $user
-     * @param  \App\Models\Post  $post
-     * @param  \App\Models\BoardMeta  $boardMeta
-     * @return \Illuminate\Auth\Access\Response|bool
-     */
-    public function forceDelete(?User $user, Post $post, BoardMeta $boardMeta)
-    {
-        if($boardMeta->item('block_delete', 0)) {
-            if(!$user?->is_admin) {
-                return $this->deny('이 게시글은 관리자만 삭제 가능합니다.');
-            }
-        }
-
-        return ($user?->id == $post->user_id ? true : $this->deny("권한이 없습니다."));
-    }
-
-    /**
-     * 이미지 첨부권한 확인
-     */
-    public function uploader(?User $user, BoardMeta $boardMeta)
-    {
-        $permitValue = $boardMeta->item(BOARD_PERMIT_TYPE_6, 0);
-
-        if ($permitValue == 1 && !$user) {
-            return $this->deny('로그인 후 이용 해주세요.', 401);
-        } else if ($permitValue == 100 && !$user?->isAdministrator()) {
-            return $this->deny(MAP_BOARD_PERMIT_ALERT_TYPE[BOARD_PERMIT_TYPE_6]);
-        }
-
-        return true;
-    }
-
-    /**
-     * 파일 다운로드 권한 확인
-     */
-    public function download(?User $user, Post $post, BoardMeta $boardMeta)
-    {
-        $permitValue = $boardMeta->item(BOARD_PERMIT_TYPE_7, 0);
-        if ($permitValue == 1 && !$user || (!$user && $post->user_id)) {
-            return $this->deny('로그인 후 이용 해주세요.', 401);
-        } else if ($permitValue == 100 && !$user?->isAdministrator()) {
-            return $this->deny(MAP_BOARD_PERMIT_ALERT_TYPE[BOARD_PERMIT_TYPE_7]);
-        }
-
-        // 다운로드 제한 - 댓글 필수
-        if ($boardMeta->item('need_comment_for_download', 0)) {
-            if ($this->commentService->userCommentRows($post, $user) <= 0) {
-                return $this->deny('다운로드를 하려면 댓글이 필요합니다.');
-            }
-        }
-
-        // 다운로드 제한 - 추천 필수
-        if ($boardMeta->item('use_post_like', 0)
-            && $boardMeta->item('need_like_for_download', 0)) {
-            if (!$this->postService->userPostIsLike($post, $user)) {
-                return $this->deny('다운로드를 하려면 추천이 필요합니다.');
-            }
-        }
-
-        return true;
-    }
-}

+ 1 - 1
app/Providers/AppServiceProvider.php

@@ -65,7 +65,7 @@ class AppServiceProvider extends ServiceProvider
         defined('DEVICE_TYPE') OR define('DEVICE_TYPE', $deviceType);
         defined('PLATFORM') OR define('PLATFORM', $platform);
         defined('BROWSER') OR define('BROWSER', $browser);
-        defined('UID') OR define('UID', null);
+        defined('UID') OR define('UID', 0);
         defined('IS_USER') OR define('IS_USER', 0);
         defined('IS_ADMIN') OR define('IS_ADMIN', 0);
 

+ 1 - 1
app/Rules/IsPhone.php

@@ -43,6 +43,6 @@ class IsPhone implements Rule
      */
     public function message()
     {
-        return ':attribute 은(는) 사용하실 수 없는 휴대전화번호입니다.';
+        return ':attribute 은(는) 사용하실 수 없는 연락처입니다.';
     }
 }

+ 0 - 37
config/visitor.php~

@@ -1,37 +0,0 @@
-<?php
-return [
-    /*
-    |--------------------------------------------------------------------------
-    | Default Driver
-    |--------------------------------------------------------------------------
-    |
-    | This value determines which of the following driver to use.
-    | You can switch to a different driver at runtime.
-    |
-    */
-    'default' => 'jenssegers',
-
-    //except save request or route names
-    'except' =>  ['login', 'register'],
-
-
-    //name of the table which visit records should save in
-    'table_name' =>  'visits',
-
-    /*
-    |--------------------------------------------------------------------------
-    | List of Drivers
-    |--------------------------------------------------------------------------
-    |
-    | This is the array of Classes that maps to Drivers above.
-    | You can create your own driver if you like and add the
-    | config in the drivers array and the class to use for
-    | here with the same name. You will have to implement
-    | Shetabit\Visitor\Contracts\UserAgentParser in your driver.
-    |
-    */
-    'drivers' => [
-        'jenssegers' => \Shetabit\Visitor\Drivers\JenssegersAgent::class,
-        'UAParser' => \Shetabit\Visitor\Drivers\UAParser::class,
-    ]
-];

+ 139 - 0
lang/ko/validation-inline.php

@@ -0,0 +1,139 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Validation Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines contain the default error messages used by
+    | the validator class. Some of these rules have multiple versions such
+    | as the size rules. Feel free to tweak each of these messages here.
+    |
+    */
+
+    'accepted'             => '이 필드를 동의해야 합니다.',
+    'active_url'           => '이 URL은 유효한 URL이 아닙니다.',
+    'after'                => ':date 이후 날짜여야 합니다.',
+    'after_or_equal'       => ':date 이후 날짜이거나 같은 날짜여야 합니다.',
+    'alpha'                => '이 필드는 문자만 포함할 수 있습니다.',
+    'alpha_dash'           => '이 필드는 문자, 숫자, 대쉬(-), 밑줄(_)만 포함할 수 있습니다.',
+    'alpha_num'            => '이 필드는 문자와 숫자만 포함할 수 있습니다.',
+    'array'                => '이 필드는 배열이어야 합니다.',
+    'before'               => ':date 이전 날짜여야 합니다.',
+    'before_or_equal'      => ':date 이전 날짜이거나 같은 날짜여야 합니다.',
+    'between'              => [
+        'numeric' => '이 값은 :min에서 :max 사이여야 합니다.',
+        'file'    => '이 파일의 용량은 :min에서 :max 킬로바이트 사이여야 합니다.',
+        'string'  => '이 문자열의 길이는 :min에서 :max 문자 사이여야 합니다.',
+        'array'   => '이 배열의 항목 수는 :min에서 :max 개의 항목이 있어야 합니다.',
+    ],
+    'boolean'              => '이 필드는 true 또는 false 이어야 합니다.',
+    'confirmed'            => '확인 항목이 일치하지 않습니다.',
+    'date'                 => '유효한 날짜가 아닙니다.',
+    'date_equals'          => ':date과(와) 같은날짜여야합니다.',
+    'date_format'          => ':format 형식과 일치하지 않습니다.',
+    'different'            => '이 값과 :other은(는) 서로 달라야 합니다.',
+    'digits'               => ':digits 자리 숫자여야 합니다.',
+    'digits_between'       => ':min에서 :max 자리 사이여야 합니다.',
+    'dimensions'           => '올바르지 않는 이미지 크기입니다.',
+    'distinct'             => '이 필드에 중복된 값이 있습니다.',
+    'email'                => '유효한 이메일 주소여야 합니다.',
+    'ends_with'            => '다음 중 하나로 끝나야 합니다: :values.',
+    'exists'               => '선택된 값은 올바르지 않습니다.',
+    'file'                 => '파일이어야 합니다.',
+    'filled'               => '이 필드는 값이 있어야 합니다.',
+    'gt'                   => [
+        'numeric' => '이 값은 :value보다 커야 합니다.',
+        'file'    => '이 파일의 용량은 :value킬로바이트보다 커야 합니다.',
+        'string'  => '이 문자열의 길이는 :value보다 길어야 합니다.',
+        'array'   => '이 배열의 항목 수는 :value개 보다 많아야 합니다.',
+    ],
+    'gte'                  => [
+        'numeric' => '이 값은 :value보다 같거나 커야 합니다.',
+        'file'    => '이 파일의 용량은 :value킬로바이트보다 같거나 커야 합니다.',
+        'string'  => '이 문자열의 길이는 :value보다 같거나 길어야 합니다.',
+        'array'   => '이 배열의 항목 수는 :value개 보다 같거나 많아야 합니다.',
+    ],
+    'image'                => '이미지여야 합니다.',
+    'in'                   => '선택된 값은 올바르지 않습니다.',
+    'in_array'             => '이 값은 :other에 존재하지 않습니다.',
+    'integer'              => '정수여야 합니다.',
+    'ip'                   => '유효한 IP 주소여야 합니다.',
+    'ipv4'                 => '유효한 IPv4 주소여야 합니다.',
+    'ipv6'                 => '유효한 IPv6 주소여야 합니다.',
+    'json'                 => 'JSON 문자열이어야 합니다.',
+    'lt'                   => [
+        'numeric' => '이 값은 :value보다 작아야 합니다.',
+        'file'    => '이 파일의 용량은 :value킬로바이트보다 작아야 합니다.',
+        'string'  => '이 문자열의 길이는 :value보다 짧아야 합니다.',
+        'array'   => '이 배열의 항목 수는 :value개 보다 작아야 합니다.',
+    ],
+    'lte'                  => [
+        'numeric' => '이 값은 :value보다 같거나 작아야 합니다.',
+        'file'    => '이 파일의 용량은 :value킬로바이트보다 같거나 작아야 합니다.',
+        'string'  => '이 문자열의 길이는 :value보다 같거나 짧아야 합니다.',
+        'array'   => '이 배열의 항목 수는 :value개 보다 같거나 작아야 합니다.',
+    ],
+    'max'                  => [
+        'numeric' => '이 값은 :max보다 클 수 없습니다.',
+        'file'    => '이 파일의 용량은 :max킬로바이트보다 클 수 없습니다.',
+        'string'  => '이 문자열의 길이는 :max자보다 클 수 없습니다.',
+        'array'   => '이 배열의 항목 수는 :max개보다 많을 수 없습니다.',
+    ],
+    'mimes'                => '다음의 파일 형식이어야 합니다: :values.',
+    'mimetypes'            => '다음의 파일 형식이어야 합니다: :values.',
+    'min'                  => [
+        'numeric' => '이 값은 최소한 :min이어야 합니다.',
+        'file'    => '이 파일의 용량은 최소한 :min킬로바이트이어야 합니다.',
+        'string'  => '이 문자열의 길이는 최소한 :min자이어야 합니다.',
+        'array'   => '이 배열의 항목 수는 최소한 :min개의 항목이 있어야 합니다.',
+    ],
+    'multiple_of'          => '이 값은 :value 의 배수여야 합니다.',
+    'not_in'               => '선택된 값은 올바르지 않습니다.',
+    'not_regex'            => '형식이 올바르지 않습니다.',
+    'numeric'              => '숫자여야 합니다.',
+    'password'             => '비밀번호가 잘못되었습니다.',
+    'present'              => '이 필드가 있어야 합니다.',
+    'regex'                => '형식이 올바르지 않습니다.',
+    'required'             => '이 필드는 필수입니다.',
+    'required_if'          => ':other이(가) :value 일 때 이 필드는 필수입니다.',
+    'required_unless'      => ':other이(가) :values에 없다면 이 필드는 필수입니다.',
+    'required_with'        => ':values이(가) 있는 경우이 필드는 필수입니다.',
+    'required_with_all'    => ':values이(가) 모두 있는 경우 이 필드는 필수입니다.',
+    'required_without'     => ':values이(가) 없는 경우 이 필드는 필수입니다.',
+    'required_without_all' => ':values이(가) 모두 없는 경우 이 필드는 필수입니다.',
+    'same'                 => '이 필드의 값과 :other은(는) 일치해야 합니다.',
+    'size'                 => [
+        'numeric' => '이 값은 :size (이)여야 합니다.',
+        'file'    => '이 파일의 용량은 :size킬로바이트여야 합니다.',
+        'string'  => '이 문자열의 길이는 :size자여야 합니다.',
+        'array'   => '이 배열은 :size개의 항목을 포함해야 합니다.',
+    ],
+    'starts_with'          => ':values 중 하나로 시작해야 합니다.',
+    'string'               => '문자열이어야 합니다.',
+    'timezone'             => '올바른 시간대 이어야 합니다.',
+    'unique'               => '이미 사용 중입니다.',
+    'uploaded'             => '업로드하지 못했습니다.',
+    'url'                  => '형식이 올바르지 않습니다.',
+    'uuid'                 => '유효한UUID여야합니다.',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Custom Validation Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | Here you may specify custom validation messages for attributes using the
+    | convention "attribute.rule" to name the lines. This makes it quick to
+    | specify a specific custom language line for a given attribute rule.
+    |
+    */
+
+    'custom' => [
+        'attribute-name' => [
+            'rule-name' => 'custom-message',
+        ],
+    ],
+
+];

+ 3 - 3
package-lock.json

@@ -1584,9 +1584,9 @@
             }
         },
         "node_modules/sass": {
-            "version": "1.97.1",
-            "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.1.tgz",
-            "integrity": "sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==",
+            "version": "1.97.2",
+            "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.2.tgz",
+            "integrity": "sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==",
             "dev": true,
             "license": "MIT",
             "dependencies": {

+ 48 - 1
public/css/auth/verify.css

@@ -1,4 +1,51 @@
-#verifyForm{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;height:100vh;background:#f1f1f1}#verifyForm a{text-decoration:none}#verifyForm header{font-family:"Open-Sans-Extrabold";font-size:37px;font-weight:bolder;margin:1.6rem 0}#verifyForm header a{color:#d3d629}#verifyForm header a:hover,#verifyForm header a:focus{color:#a8aa2f}#verifyForm main{max-width:800px;padding:10px}#verifyForm main h5{font-weight:bold;margin-bottom:.8rem}#verifyForm main hr{margin:.9rem 0;border-color:#888}#verifyForm main form div:last-child a{color:#0066c0}#verifyForm main form div:last-child a:hover,#verifyForm main form div:last-child a:focus{color:#00558c;text-decoration:underline}#verifyForm main footer{text-align:center;font-size:11px;color:#6c6c6c}m main form div:last-child a:hover, #verifyForm main form div:last-child a:focus {
+#verifyForm {
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-orient: vertical;
+  -webkit-box-direction: normal;
+      -ms-flex-direction: column;
+          flex-direction: column;
+  -webkit-box-align: center;
+      -ms-flex-align: center;
+          align-items: center;
+  -webkit-box-pack: center;
+      -ms-flex-pack: center;
+          justify-content: center;
+  height: 100vh;
+  background: #f1f1f1;
+}
+#verifyForm a {
+  text-decoration: none;
+}
+#verifyForm header {
+  font-family: "Open-Sans-Extrabold";
+  font-size: 37px;
+  font-weight: bolder;
+  margin: 1.6rem 0;
+}
+#verifyForm header a {
+  color: #d3d629;
+}
+#verifyForm header a:hover, #verifyForm header a:focus {
+  color: #a8aa2f;
+}
+#verifyForm main {
+  max-width: 800px;
+  padding: 10px;
+}
+#verifyForm main h5 {
+  font-weight: bold;
+  margin-bottom: 0.8rem;
+}
+#verifyForm main hr {
+  margin: 0.9rem 0;
+  border-color: #888;
+}
+#verifyForm main form div:last-child a {
+  color: #0066c0;
+}
+#verifyForm main form div:last-child a:hover, #verifyForm main form div:last-child a:focus {
   color: #00558c;
   text-decoration: underline;
 }

+ 1 - 54
public/css/common/auth/login.css

@@ -1,57 +1,4 @@
-#loginForm {
-  display: -webkit-box;
-  display: -ms-flexbox;
-  display: flex;
-  -webkit-box-orient: vertical;
-  -webkit-box-direction: normal;
-      -ms-flex-direction: column;
-          flex-direction: column;
-  -webkit-box-align: center;
-      -ms-flex-align: center;
-          align-items: center;
-  -webkit-box-pack: center;
-      -ms-flex-pack: center;
-          justify-content: center;
-  height: 100vh;
-}
-#loginForm a {
-  text-decoration: none;
-}
-#loginForm header {
-  font-family: "Open-Sans-Extrabold";
-  font-size: 37px;
-  font-weight: bolder;
-  margin-bottom: 0.7rem;
-}
-#loginForm header a {
-  color: #333;
-}
-#loginForm header a:hover, #loginForm header a:focus {
-  color: #18306c;
-}
-#loginForm main {
-  border-radius: 4px;
-  padding: 20px;
-  border: 1px solid #b5b5b5;
-  background: #fff;
-}
-#loginForm main h5 {
-  font-weight: bold;
-  margin-bottom: 0.9rem;
-}
-#loginForm main div:last-child ul {
-  margin-bottom: 0;
-}
-#loginForm main div:last-child ul li span {
-  display: inline-block;
-  margin: 0;
-  padding: 0;
-  width: 1px;
-  height: 11px;
-  background: #2c2c2c;
-  vertical-align: middle;
-}
-#loginForm main div:last-child a:hover, #loginForm main div:last-child a:focus {
+#loginForm{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;height:100vh}#loginForm a{text-decoration:none}#loginForm header{font-family:"Open-Sans-Extrabold";font-size:37px;font-weight:bolder;margin-bottom:.7rem}#loginForm header a{color:#333}#loginForm header a:hover,#loginForm header a:focus{color:#18306c}#loginForm main{border-radius:4px;padding:20px;border:1px solid #b5b5b5;background:#fff}#loginForm main h5{font-weight:bold;margin-bottom:.9rem}#loginForm main div:last-child ul{margin-bottom:0}#loginForm main div:last-child ul li span{display:inline-block;margin:0;padding:0;width:1px;height:11px;background:#2c2c2c;vertical-align:middle}#loginForm main div:last-child a:hover,#loginForm main div:last-child a:focus{text-decoration:underline}#loginForm main hr{margin:.5rem 0;border-color:#888}#loginForm main footer{text-align:center;font-size:11px;padding-top:12px;color:#6c6c6c}ld a:hover, #loginForm main div:last-child a:focus {
   text-decoration: underline;
 }
 #loginForm main hr {

+ 55 - 1
public/css/common/auth/passwords.css

@@ -1,4 +1,58 @@
-#passwordEmail,#passwordReset{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;height:100vh}#passwordEmail a,#passwordReset a{text-decoration:none}#passwordEmail header,#passwordReset header{font-family:"Open-Sans-Extrabold";font-size:37px;font-weight:bolder;margin-bottom:.7rem}#passwordEmail header a,#passwordReset header a{color:#333}#passwordEmail header a:hover,#passwordEmail header a:focus,#passwordReset header a:hover,#passwordReset header a:focus{color:#18306c}#passwordEmail main,#passwordReset main{border-radius:4px;padding:20px;border:1px solid #b5b5b5;background:#fff}#passwordEmail main h5,#passwordReset main h5{font-weight:bold;margin-bottom:.9rem}#passwordEmail main div:last-child a:hover,#passwordEmail main div:last-child a:focus,#passwordReset main div:last-child a:hover,#passwordReset main div:last-child a:focus{text-decoration:underline}#passwordEmail main hr,#passwordReset main hr{margin:.5rem 0;border-color:#888}#passwordEmail main footer,#passwordReset main footer{text-align:center;font-size:11px;padding-top:12px;color:#6c6c6c}sswordEmail main hr,
+#passwordEmail,
+#passwordReset {
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-orient: vertical;
+  -webkit-box-direction: normal;
+      -ms-flex-direction: column;
+          flex-direction: column;
+  -webkit-box-align: center;
+      -ms-flex-align: center;
+          align-items: center;
+  -webkit-box-pack: center;
+      -ms-flex-pack: center;
+          justify-content: center;
+  height: 100vh;
+}
+#passwordEmail a,
+#passwordReset a {
+  text-decoration: none;
+}
+#passwordEmail header,
+#passwordReset header {
+  font-family: "Open-Sans-Extrabold";
+  font-size: 37px;
+  font-weight: bolder;
+  margin-bottom: 0.7rem;
+}
+#passwordEmail header a,
+#passwordReset header a {
+  color: #333;
+}
+#passwordEmail header a:hover, #passwordEmail header a:focus,
+#passwordReset header a:hover,
+#passwordReset header a:focus {
+  color: #18306c;
+}
+#passwordEmail main,
+#passwordReset main {
+  border-radius: 4px;
+  padding: 20px;
+  border: 1px solid #b5b5b5;
+  background: #fff;
+}
+#passwordEmail main h5,
+#passwordReset main h5 {
+  font-weight: bold;
+  margin-bottom: 0.9rem;
+}
+#passwordEmail main div:last-child a:hover, #passwordEmail main div:last-child a:focus,
+#passwordReset main div:last-child a:hover,
+#passwordReset main div:last-child a:focus {
+  text-decoration: underline;
+}
+#passwordEmail main hr,
 #passwordReset main hr {
   margin: 0.5rem 0;
   border-color: #888;

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 32
public/css/common/font.css


+ 17 - 1
public/css/desktop/account/certify.css

@@ -1,4 +1,20 @@
-#accountCertify{position:relative}#accountCertify>dl{margin-bottom:1.5rem}#accountCertify>dl dt{font-size:17px;margin-bottom:10px}#accountCertify>dl dd{font-size:13px}#accountCertify form{min-width:250px;max-width:420px;margin:0 auto}#accountCertify form table{border:none} margin: 0 auto;
+#accountCertify {
+  position: relative;
+}
+#accountCertify > dl {
+  margin-bottom: 1.5rem;
+}
+#accountCertify > dl dt {
+  font-size: 17px;
+  margin-bottom: 10px;
+}
+#accountCertify > dl dd {
+  font-size: 13px;
+}
+#accountCertify form {
+  min-width: 250px;
+  max-width: 420px;
+  margin: 0 auto;
 }
 #accountCertify form table {
   border: none;

+ 1 - 35
public/css/desktop/account/comment.css

@@ -1,38 +1,4 @@
-@charset "UTF-8";
-/* 작성 댓글 */
-#accountComment {
-  -webkit-box-sizing: border-box;
-          box-sizing: border-box;
-}
-#accountComment table caption {
-  caption-side: top;
-  color: #bbbbbb;
-}
-#accountComment table tr th, #accountComment table tr td {
-  text-align: center;
-}
-#accountComment table thead tr th {
-  background: #133a46;
-}
-#accountComment table tbody tr:hover, #accountComment table tbody tr:focus {
-  background-color: #1a1e21;
-}
-#accountComment table tbody tr th, #accountComment table tbody tr td {
-  text-align: center;
-  vertical-align: middle;
-}
-#accountComment table tbody tr td p {
-  font-size: 13px;
-}
-#accountComment table tbody tr td p a {
-  color: #b3b3b3;
-}
-#accountComment table tbody tr td p var {
-  color: #aa0000;
-  font-style: normal;
-  margin-left: 3px;
-  letter-spacing: -1px;
-  vertical-align: middle;
+#accountComment{-webkit-box-sizing:border-box;box-sizing:border-box}#accountComment table caption{caption-side:top;color:#bbb}#accountComment table tr th,#accountComment table tr td{text-align:center}#accountComment table thead tr th{background:#133a46}#accountComment table tbody tr:hover,#accountComment table tbody tr:focus{background-color:#1a1e21}#accountComment table tbody tr th,#accountComment table tbody tr td{text-align:center;vertical-align:middle}#accountComment table tbody tr td p{font-size:13px}#accountComment table tbody tr td p a{color:#b3b3b3}#accountComment table tbody tr td p var{color:#a00;font-style:normal;margin-left:3px;letter-spacing:-1px;vertical-align:middle}#accountComment table tbody tr td p i{color:#cbd5e0;margin-left:3px;vertical-align:-1px}#accountComment table tbody tr td p:last-child{margin-bottom:0};
 }
 #accountComment table tbody tr td p i {
   color: #cbd5e0;

+ 1 - 20
public/css/desktop/account/leave.css

@@ -1,23 +1,4 @@
-#accountLeave {
-  position: relative;
-}
-#accountLeave > dl {
-  margin-bottom: 1.5rem;
-}
-#accountLeave > dl dt {
-  font-size: 17px;
-  margin-bottom: 10px;
-}
-#accountLeave > dl dd {
-  font-size: 13px;
-}
-#accountLeave form {
-  min-width: 350px;
-  max-width: 550px;
-  margin: 0 auto;
-}
-#accountLeave form table {
-  border: none;
+#accountLeave{position:relative}#accountLeave>dl{margin-bottom:1.5rem}#accountLeave>dl dt{font-size:17px;margin-bottom:10px}#accountLeave>dl dd{font-size:13px}#accountLeave form{min-width:350px;max-width:550px;margin:0 auto}#accountLeave form table{border:none}#accountLeave form table tbody tr td{text-align:left}der: none;
 }
 #accountLeave form table tbody tr td {
   text-align: left;

+ 29 - 1
public/css/desktop/account/modify.css

@@ -1,4 +1,32 @@
-#accountModify{position:relative}#accountModify>dl{margin-bottom:1.5rem}#accountModify>dl dt{font-size:17px;margin-bottom:10px}#accountModify>dl dd{font-size:13px}#accountModify form{margin-bottom:0}#accountModify form table{border:none}#accountModify form table tbody tr th hr{margin:.6rem 0}#accountModify form table tbody tr td{text-align:left}#accountModify form table tbody tr td #btnChangeEmail{text-decoration:none}#accountModify form table tbody tr td #btnChangeEmail:hover,#accountModify form table tbody tr td #btnChangeEmail:focus{text-decoration:underline}#accountModify form table tbody tr td hr{margin:.3rem 0}s {
+#accountModify {
+  position: relative;
+}
+#accountModify > dl {
+  margin-bottom: 1.5rem;
+}
+#accountModify > dl dt {
+  font-size: 17px;
+  margin-bottom: 10px;
+}
+#accountModify > dl dd {
+  font-size: 13px;
+}
+#accountModify form {
+  margin-bottom: 0;
+}
+#accountModify form table {
+  border: none;
+}
+#accountModify form table tbody tr th hr {
+  margin: 0.6rem 0;
+}
+#accountModify form table tbody tr td {
+  text-align: left;
+}
+#accountModify form table tbody tr td #btnChangeEmail {
+  text-decoration: none;
+}
+#accountModify form table tbody tr td #btnChangeEmail:hover, #accountModify form table tbody tr td #btnChangeEmail:focus {
   text-decoration: underline;
 }
 #accountModify form table tbody tr td hr {

+ 36 - 1
public/css/desktop/account/passwords.css

@@ -1,4 +1,39 @@
-#accountPassword,#accountPasswordCampaign{position:relative}#accountPassword>dl,#accountPasswordCampaign>dl{margin-bottom:1.5rem}#accountPassword>dl dt,#accountPasswordCampaign>dl dt{font-size:15px;margin-bottom:10px}#accountPassword>dl dd,#accountPasswordCampaign>dl dd{font-size:13px}#accountPassword form,#accountPasswordCampaign form{min-width:350px;max-width:450px;margin:0 auto}#accountPassword form table,#accountPasswordCampaign form table{border:none}#accountPassword form table tbody tr th hr,#accountPasswordCampaign form table tbody tr th hr{margin:.6rem 0}#accountPassword form table tbody tr td,#accountPasswordCampaign form table tbody tr td{text-align:left}#accountPassword form table tbody tr td hr,#accountPasswordCampaign form table tbody tr td hr{margin:.3rem 0}word form table tbody tr td hr,
+#accountPassword,
+#accountPasswordCampaign {
+  position: relative;
+}
+#accountPassword > dl,
+#accountPasswordCampaign > dl {
+  margin-bottom: 1.5rem;
+}
+#accountPassword > dl dt,
+#accountPasswordCampaign > dl dt {
+  font-size: 15px;
+  margin-bottom: 10px;
+}
+#accountPassword > dl dd,
+#accountPasswordCampaign > dl dd {
+  font-size: 13px;
+}
+#accountPassword form,
+#accountPasswordCampaign form {
+  min-width: 350px;
+  max-width: 450px;
+  margin: 0 auto;
+}
+#accountPassword form table,
+#accountPasswordCampaign form table {
+  border: none;
+}
+#accountPassword form table tbody tr th hr,
+#accountPasswordCampaign form table tbody tr th hr {
+  margin: 0.6rem 0;
+}
+#accountPassword form table tbody tr td,
+#accountPasswordCampaign form table tbody tr td {
+  text-align: left;
+}
+#accountPassword form table tbody tr td hr,
 #accountPasswordCampaign form table tbody tr td hr {
   margin: 0.3rem 0;
 }

+ 1 - 26
public/css/desktop/account/profile.css

@@ -1,29 +1,4 @@
-#accountProfile {
-  position: relative;
-}
-#accountProfile > dl {
-  margin-bottom: 1.5rem;
-}
-#accountProfile > dl dt {
-  font-size: 17px;
-  margin-bottom: 10px;
-}
-#accountProfile > dl dd {
-  font-size: 13px;
-}
-#accountProfile article table {
-  border: none;
-}
-#accountProfile article table tbody tr th {
-  color: #b3b3b3;
-}
-#accountProfile article table tbody tr th hr {
-  color: #ccc;
-  margin: 0.6rem 0;
-}
-#accountProfile article table tbody tr td {
-  text-align: left;
-  color: #bbb;
+#accountProfile{position:relative}#accountProfile>dl{margin-bottom:1.5rem}#accountProfile>dl dt{font-size:17px;margin-bottom:10px}#accountProfile>dl dd{font-size:13px}#accountProfile article table{border:none}#accountProfile article table tbody tr th{color:#b3b3b3}#accountProfile article table tbody tr th hr{color:#ccc;margin:.6rem 0}#accountProfile article table tbody tr td{text-align:left;color:#bbb}#accountProfile article table tbody tr td hr{color:#ccc;margin:.3rem 0}or: #bbb;
 }
 #accountProfile article table tbody tr td hr {
   color: #ccc;

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
public/css/desktop/board/index.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
public/css/desktop/board/latest.css


+ 47 - 1
public/css/desktop/board/tag.css

@@ -1,4 +1,50 @@
-#tags{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;gap:10px}#tags button.tag-nav-link{font-size:.813rem;padding:9px 11px;border:1px solid hsla(0,0%,100%,.1019607843);border-radius:4px;outline:none;background-color:rgba(0,0,0,0);color:hsla(0,0%,100%,.5019607843);font-weight:600;line-height:1;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#tags button.tag-nav-link:hover,#tags button.tag-nav-link.active{background-color:hsla(0,0%,100%,.1019607843)}#tags button.tag-nav-link.active{color:#ffffe0}#posts .list-group-item{padding:15px 20px}#posts .list-group-item h4 a{font-weight:bold;color:#fff}#posts .list-group-item blockquote{margin-bottom:24px}#posts .list-group-item span.tag-sub-link{margin:0;cursor:pointer}#posts .list-group-item span.tag-sub-link:hover{color:#ffffe0;text-decoration:underline}#posts .list-group-item a:hover,#posts .list-group-item button:hover{text-decoration:underline;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}ion: underline;
+#tags {
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -ms-flex-wrap: wrap;
+      flex-wrap: wrap;
+  gap: 10px;
+}
+#tags button.tag-nav-link {
+  font-size: 0.813rem;
+  padding: 9px 11px;
+  border: 1px solid rgba(255, 255, 255, 0.1019607843);
+  border-radius: 4px;
+  outline: none;
+  background-color: transparent;
+  color: rgba(255, 255, 255, 0.5019607843);
+  font-weight: 600;
+  line-height: 1;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+   -ms-user-select: none;
+       user-select: none;
+}
+#tags button.tag-nav-link:hover, #tags button.tag-nav-link.active {
+  background-color: rgba(255, 255, 255, 0.1019607843);
+}
+#tags button.tag-nav-link.active {
+  color: #ffffe0;
+}
+
+#posts .list-group-item {
+  padding: 15px 20px;
+}
+#posts .list-group-item h4 a {
+  font-weight: bold;
+  color: #fff;
+}
+#posts .list-group-item blockquote {
+  margin-bottom: 24px;
+}
+#posts .list-group-item span.tag-sub-link {
+  margin: 0;
+  cursor: pointer;
+}
+#posts .list-group-item span.tag-sub-link:hover {
+  color: #ffffe0;
+  text-decoration: underline;
 }
 #posts .list-group-item a:hover,
 #posts .list-group-item button:hover {

+ 23 - 1
public/css/mobile/account/loginLog.css

@@ -1,4 +1,26 @@
-#accountLoginLog{-webkit-box-sizing:border-box;box-sizing:border-box}#accountLoginLog table{margin-bottom:0;min-width:580px}#accountLoginLog table caption{caption-side:top;color:#bbb}#accountLoginLog table tr th,#accountLoginLog table tr td{text-align:center}#accountLoginLog table thead tr th{background:#133a46}#accountLoginLog table tbody tr td{text-align:center;vertical-align:middle;border:none;font-size:13px} text-align: center;
+#accountLoginLog {
+  -webkit-box-sizing: border-box;
+          box-sizing: border-box;
+}
+#accountLoginLog table {
+  margin-bottom: 0;
+  min-width: 580px;
+}
+#accountLoginLog table caption {
+  caption-side: top;
+  color: #bbbbbb;
+}
+#accountLoginLog table tr {
+  border-bottom: 1px solid #212121;
+}
+#accountLoginLog table tr th, #accountLoginLog table tr td {
+  text-align: center;
+}
+#accountLoginLog table thead tr th {
+  background: #133a46;
+}
+#accountLoginLog table tbody tr td {
+  text-align: center;
   vertical-align: middle;
   border: none;
   font-size: 13px;

+ 36 - 1
public/css/mobile/account/modify.css

@@ -1,4 +1,39 @@
-#accountModify{position:relative}#accountModify>dl{margin-bottom:1.5rem}#accountModify>dl dt{font-size:17px;margin-bottom:10px}#accountModify>dl dd{font-size:13px}#accountModify form{margin-bottom:0}#accountModify form table{border:none}#accountModify form table tbody tr th{color:#b3b3b3}#accountModify form table tbody tr th hr{color:#ccc;margin:.6rem 0}#accountModify form table tbody tr td{text-align:left}@media(max-width: 576px){#accountModify form table tbody tr td #btnConfirmEmail,#accountModify form table tbody tr td #btnCancelEmail{margin-bottom:5px}}#accountModify form table tbody tr td input[type=file]{width:inherit}#accountModify form table tbody tr td hr{margin:.3rem 0}rm table tbody tr td input[type=file] {
+#accountModify {
+  position: relative;
+}
+#accountModify > dl {
+  margin-bottom: 1.5rem;
+}
+#accountModify > dl dt {
+  font-size: 17px;
+  margin-bottom: 10px;
+}
+#accountModify > dl dd {
+  font-size: 13px;
+}
+#accountModify form {
+  margin-bottom: 0;
+}
+#accountModify form table {
+  border: none;
+}
+#accountModify form table tbody tr th {
+  color: #b3b3b3;
+}
+#accountModify form table tbody tr th hr {
+  color: #ccc;
+  margin: 0.6rem 0;
+}
+#accountModify form table tbody tr td {
+  text-align: left;
+}
+@media (max-width: 576px) {
+  #accountModify form table tbody tr td #btnConfirmEmail,
+  #accountModify form table tbody tr td #btnCancelEmail {
+    margin-bottom: 5px;
+  }
+}
+#accountModify form table tbody tr td input[type=file] {
   width: inherit;
 }
 #accountModify form table tbody tr td hr {

+ 31 - 1
public/css/mobile/account/passwords.css

@@ -1,4 +1,34 @@
-#accountPassword,#accountPasswordCampaign{position:relative}#accountPassword>dl,#accountPasswordCampaign>dl{margin-bottom:1.5rem}#accountPassword>dl dt,#accountPasswordCampaign>dl dt{font-size:15px;margin-bottom:10px}#accountPassword>dl dd,#accountPasswordCampaign>dl dd{font-size:13px}#accountPassword form,#accountPasswordCampaign form{max-width:450px;margin:0 auto}#accountPassword form table,#accountPasswordCampaign form table{border:none}#accountPassword form table tbody tr td,#accountPasswordCampaign form table tbody tr td{text-align:left}#accountPassword form table tbody tr td hr,#accountPasswordCampaign form table tbody tr td hr{margin:.3rem 0}e tbody tr td hr,
+#accountPassword,
+#accountPasswordCampaign {
+  position: relative;
+}
+#accountPassword > dl,
+#accountPasswordCampaign > dl {
+  margin-bottom: 1.5rem;
+}
+#accountPassword > dl dt,
+#accountPasswordCampaign > dl dt {
+  font-size: 15px;
+  margin-bottom: 10px;
+}
+#accountPassword > dl dd,
+#accountPasswordCampaign > dl dd {
+  font-size: 13px;
+}
+#accountPassword form,
+#accountPasswordCampaign form {
+  max-width: 450px;
+  margin: 0 auto;
+}
+#accountPassword form table,
+#accountPasswordCampaign form table {
+  border: none;
+}
+#accountPassword form table tbody tr td,
+#accountPasswordCampaign form table tbody tr td {
+  text-align: left;
+}
+#accountPassword form table tbody tr td hr,
 #accountPasswordCampaign form table tbody tr td hr {
   margin: 0.3rem 0;
 }

+ 1 - 78
public/css/mobile/account/post.css

@@ -1,81 +1,4 @@
-@charset "UTF-8";
-/* 작성 게시글 */
-#accountPost {
-  -webkit-box-sizing: border-box;
-          box-sizing: border-box;
-}
-#accountPost table {
-  margin-bottom: 0;
-}
-#accountPost table caption {
-  caption-side: top;
-  color: #bbbbbb;
-}
-#accountPost table tr th, #accountPost table tr td {
-  text-align: center;
-}
-#accountPost table thead tr th {
-  background: #133a46;
-}
-#accountPost table tbody tr:hover, #accountPost table tbody tr:focus {
-  background-color: #1a1e21;
-}
-#accountPost table tbody tr th, #accountPost table tbody tr td {
-  text-align: center;
-  vertical-align: middle;
-}
-#accountPost table tbody tr td p {
-  margin-bottom: 5px;
-}
-#accountPost table tbody tr td p label {
-  font-size: 0.8rem;
-  margin-right: 3px;
-}
-#accountPost table tbody tr td p del, #accountPost table tbody tr td p a {
-  font-size: 0.8rem;
-  font-weight: normal;
-  text-decoration: none;
-}
-#accountPost table tbody tr td p var {
-  color: #aa0000;
-  font-style: initial;
-  font-size: 0.813rem;
-  vertical-align: bottom;
-  letter-spacing: -1px;
-}
-#accountPost table tbody tr td p i {
-  color: #cbd5e0;
-  margin-left: 5px;
-  vertical-align: -2px;
-}
-#accountPost table tbody tr td p span {
-  font-size: 0.625rem;
-  vertical-align: text-top;
-  margin-left: 5px;
-}
-#accountPost table tbody tr td ul {
-  margin: 0;
-  padding: 0;
-}
-#accountPost table tbody tr td ul li {
-  display: inline-block;
-  font-size: 0.75rem;
-}
-#accountPost table tbody tr td ul li:after {
-  content: "·";
-  padding: 0 3px 0 7px;
-}
-#accountPost table tbody tr td ul li:last-child:after {
-  content: "";
-  padding: 0;
-}
-#accountPost table tbody tr td .thumbnail {
-  display: block;
-  position: relative;
-  width: 100%;
-  height: 100%;
-  overflow: hidden;
-  min-height: 50px;
+#accountPost{-webkit-box-sizing:border-box;box-sizing:border-box}#accountPost table{margin-bottom:0}#accountPost table caption{caption-side:top;color:#bbb}#accountPost table tr th,#accountPost table tr td{text-align:center}#accountPost table thead tr th{background:#133a46}#accountPost table tbody tr:hover,#accountPost table tbody tr:focus{background-color:#1a1e21}#accountPost table tbody tr th,#accountPost table tbody tr td{text-align:center;vertical-align:middle}#accountPost table tbody tr td p{margin-bottom:5px}#accountPost table tbody tr td p label{font-size:.8rem;margin-right:3px}#accountPost table tbody tr td p del,#accountPost table tbody tr td p a{font-size:.8rem;font-weight:normal;text-decoration:none}#accountPost table tbody tr td p var{color:#a00;font-style:initial;font-size:.813rem;vertical-align:bottom;letter-spacing:-1px}#accountPost table tbody tr td p i{color:#cbd5e0;margin-left:5px;vertical-align:-2px}#accountPost table tbody tr td p span{font-size:.625rem;vertical-align:text-top;margin-left:5px}#accountPost table tbody tr td ul{margin:0;padding:0}#accountPost table tbody tr td ul li{display:inline-block;font-size:.75rem}#accountPost table tbody tr td ul li:after{content:"·";padding:0 3px 0 7px}#accountPost table tbody tr td ul li:last-child:after{content:"";padding:0}#accountPost table tbody tr td .thumbnail{display:block;position:relative;width:100%;height:100%;overflow:hidden;min-height:50px}#accountPost table tbody tr td .thumbnail>img{position:absolute;width:100%;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}#accountPost table tbody tr td:first-child{text-align:center}#accountPost table tbody tr td:last-child{text-align:left}-height: 50px;
 }
 #accountPost table tbody tr td .thumbnail > img {
   position: absolute;

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 107
public/css/mobile/board/comment.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
public/css/mobile/board/index.css


+ 66 - 14
public/css/mobile/board/latest.css

@@ -77,7 +77,7 @@
   -webkit-transform: translate(-50%, -50%);
           transform: translate(-50%, -50%);
 }
-#latest table tbody tr td > section {
+#latest > section {
   display: -webkit-box;
   display: -ms-flexbox;
   display: flex;
@@ -86,38 +86,90 @@
   -ms-flex-pack: distribute;
       justify-content: space-around;
 }
-#latest table tbody tr td > section figure {
+#latest > section figure {
   -webkit-box-sizing: border-box;
           box-sizing: border-box;
   text-align: center;
   -ms-flex-preferred-size: auto;
       flex-basis: auto;
-  max-width: 50%;
-  padding: 5px;
 }
-#latest table tbody tr td > section figure > a {
-  display: inline-block;
+#latest > section figure > a {
+  position: relative;
+  display: block;
 }
-#latest table tbody tr td > section figure > a img {
+#latest > section figure > a img {
+  position: absolute;
   width: 100%;
-  max-width: 210px;
-  max-height: 215px;
+  top: 0;
+  left: 0;
 }
-#latest table tbody tr td > section figure > a img:focus, #latest table tbody tr td > section figure > a img:hover {
+#latest > section figure > a img:hover {
   -webkit-filter: drop-shadow(2px 2px 4px #969696);
           filter: drop-shadow(2px 2px 4px #969696);
 }
-#latest table tbody tr td > section figure figcaption {
+#latest > section figure figcaption {
   margin: 5px 0;
 }
-#latest table tbody tr td > section figure figcaption a {
+#latest > section figure figcaption p {
+  margin-bottom: 0.125rem;
+}
+#latest > section figure figcaption > a {
   display: initial;
 }
-#latest table tbody tr td > section figure strong {
+#latest > section figure figcaption label {
+  margin-right: 5px;
+}
+#latest > section figure figcaption label a {
+  color: #cbd5e0;
+}
+#latest > section figure figcaption del, #latest > section figure figcaption a {
+  font-size: 14px;
+  font-weight: normal;
+  color: #b3b3b3;
+}
+#latest > section figure figcaption var {
+  color: #aa0000;
+  font-style: normal;
+  margin-left: 3px;
+  letter-spacing: -1px;
+  vertical-align: middle;
+}
+#latest > section figure figcaption i {
+  color: #cbd5e0;
+  margin-left: 3px;
+  vertical-align: -1px;
+}
+#latest > section figure figcaption span {
+  font-size: 10px;
+  margin-left: 3px;
+  vertical-align: middle;
+}
+#latest > section figure strong {
   display: block;
   font-size: 0.813rem;
   margin-bottom: 3px;
 }
-#latest table tbody tr td > section figure small {
+#latest > section figure small {
   font-size: 0.688rem;
+}
+#latest > section figure ul {
+  list-style: none;
+  padding-left: 0;
+  margin: 0;
+}
+#latest > section figure ul li {
+  display: inline-block;
+  font-size: 13px;
+}
+#latest > section figure ul li:first-child::before {
+  display: none;
+}
+#latest > section figure ul li::before {
+  content: "";
+  display: inline-block;
+  width: 2px;
+  height: 2px;
+  margin: 0 5px 4px 2px;
+  border-radius: 2px;
+  background-color: #616670;
 }

+ 30 - 1
public/css/mobile/board/write.css

@@ -1,4 +1,33 @@
-#boardWrite,#boardEdit{-webkit-box-sizing:border-box;box-sizing:border-box;padding:calc(var(--bs-gutter-x)*.5)}#boardWrite>h5,#boardEdit>h5{font-weight:bold;margin-bottom:0}#boardWrite .head,#boardEdit .head{margin-bottom:10px}#boardWrite .body,#boardEdit .body{margin:0 -10px}>#boardWrite .body form table:not(:first-child),>#boardEdit .body form table:not(:first-child){border:none}#boardWrite .body form table tr,#boardEdit .body form table tr{overflow:hidden}#boardWrite .body form table tr td,#boardEdit .body form table tr td{padding:7px;text-align:initial;vertical-align:middle}#boardWrite .foot,#boardEdit .foot{margin-top:10px}r td,
+@charset "UTF-8";
+/* 게시판 작성 / 게시판 수정 */
+#boardWrite,
+#boardEdit {
+  -webkit-box-sizing: border-box;
+          box-sizing: border-box;
+  padding: calc(var(--bs-gutter-x) * 0.5);
+}
+#boardWrite > h5,
+#boardEdit > h5 {
+  font-weight: bold;
+  margin-bottom: 0;
+}
+#boardWrite .head,
+#boardEdit .head {
+  margin-bottom: 10px;
+}
+#boardWrite .body,
+#boardEdit .body {
+  margin: 0 -10px;
+}
+> #boardWrite .body form table:not(:first-child),
+> #boardEdit .body form table:not(:first-child) {
+  border: none;
+}
+#boardWrite .body form table tr,
+#boardEdit .body form table tr {
+  overflow: hidden;
+}
+#boardWrite .body form table tr td,
 #boardEdit .body form table tr td {
   padding: 7px;
   text-align: initial;

+ 1 - 8
public/css/mobile/document.css

@@ -1,10 +1,3 @@
-#document h4 {
-  margin-bottom: 0;
-}
-#document blockquote {
-  text-align: justify;
-  word-break: break-all;
-}
-#document blockquote img {
+#document h4{margin-bottom:0}#document blockquote{text-align:justify;word-break:break-all}#document blockquote img{max-width:100%} img {
   max-width: 100%;
 }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
public/css/mobile/layout.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 113
public/css/mobile/main.css


+ 1 - 1
resources/css/app.css

@@ -13,4 +13,4 @@
 @import 'photoswipe/dist/photoswipe.css';
 
 /* Prism */
-@import 'prismjs/themes/prism-okaidia.css';
+@import 'prismjs/themes/prism-okaidia.css';

+ 19 - 0
resources/sass/_variables.scss

@@ -94,3 +94,22 @@ $dropdown-divider-margin-y: 0;
 
 // Tooltip
 $tooltip-color: #c7c7c7;
+
+$grid-breakpoints: (
+   xs: 0,
+   xxs: 420px,
+   sm: 576px,
+   md: 768px,
+   lg: 992px,
+   xl: 1200px,
+   xxl: 1400px
+);
+
+$container-max-widths: (
+   xxs: 420px,
+   sm: 540px,
+   md: 720px,
+   lg: 960px,
+   xl: 1140px,
+   xxl: 1320px
+);

+ 0 - 2
resources/sass/app.scss

@@ -1,7 +1,5 @@
 @charset "utf-8";
 
-// Fonts
-@import url('https://fonts.bunny.net/css?family=Nunito');
 @import "common/font";
 
 // Variables

+ 0 - 0
resources/sass/bootstrap/scss/bootstrap


+ 3 - 0
resources/sass/common/font.scss

@@ -46,3 +46,6 @@
     url("/public/fonts/NaverNanumSquareNeo/Webfont/woff/NanumSquareNeo-Variable.woff") format("woff"),
     url("/public/fonts/NaverNanumSquareNeo/Webfont/eot/NanumSquareNeo-Variable.eot") format("eot");
 }
+
+// Fonts
+@import url('https://fonts.bunny.net/css?family=Nunito');

+ 170 - 119
resources/sass/desktop/board/latest.scss

@@ -4,157 +4,208 @@
     margin-top: 20px;
 
     table {
-        > &:not(:first-child) {
-            border-top: none;
-        }
-
-        margin-left: auto;
-        margin-right: auto;
-        border: 1px solid #333;
+            margin-left: auto;
+            margin-right: auto;
+            border: 1px solid #333;
 
-        thead {
-            tr {
-                background-color: #133a46;
-                border: 1px solid #333;
+            caption {
+                caption-side: top;
+                color: #bbbbbb;
 
-                th {
-                    text-align: center;
-                    border-bottom: none;
+                span {
+                    font-size: 15px;
                 }
-            }
-        }
-
-        tbody {
-            tr {
 
-                &:hover,
-                &:focus {
-                    background-color: #1a1e21;
-                }
+                select {
+                    width: auto;
+                    display: inline-block;
 
-                th, td {
-                    text-align: center;
-                    vertical-align: middle;
+                    &:last-child {
+                        margin-left: 5px;
+                    }
                 }
+            }
 
-                td {
-                    font-size: 13px;
+            thead {
+                tr {
+                    border: 1px solid #333;
 
-                    label {
-                        a {
-                            color: #cbd5e0;
-                        }
-                    }
-
-                    del, a {
-                        font-size: 14px;
-                        font-weight: normal;
-                        margin-right: 5px;
-                        color: #b3b3b3;
+                    th {
+                        text-align: center;
+                        border-bottom: none;
+                        background-color: #133a46;
                     }
+                }
+            }
 
-                    var {
-                        color: #aa0000;
-                        font-style: initial;
-                        letter-spacing: -1px;
-                        margin-right: 5px;
-                    }
+            tbody {
+                tr {
 
-                    i {
-                        color: #cbd5e0;
-                        margin-right: 3px;
-                        vertical-align: -1px;
+                    &:hover,
+                    &:focus {
+                        td {
+                            background-color: #1a1e21;
+                        }
                     }
 
-                    span {
-                        font-size: 10px;
-                        vertical-align: text-bottom;
+                    th, td {
+                        text-align: center;
+                        vertical-align: middle;
                     }
 
-                    // 사진/동영상
-                    figure {
-                        box-sizing: border-box;
-                        margin: 0;
-                        text-align: center;
+                    td {
+                        font-size: 13px;
 
-                        > a {
-                            position: relative;
-                            display: block;
-                            overflow: hidden;
-                            min-width: 140px;
-                            min-height: 140px;
-                            max-height: 160px;
-                            margin: 0;
-
-                            img {
-                                position: absolute;
-                                width: 100%;
-                                top: 0;
-                                left: 0;
-
-                                &:focus,
-                                &:hover {
-                                    filter: drop-shadow(2px 2px 4px #969696);
-                                }
-                            }
+                        label {
+                            margin-right: 5px;
 
-                            &:hover,
-                            &:focus {
-                                text-decoration: underline;
+                            a {
+                                color: #cbd5e0;
                             }
                         }
 
-                        figcaption {
-                            margin: 5px 0;
-
-                            > a {
-                                display: initial;
+                        del, a {
+                            font-size: 14px;
+                            font-weight: normal;
+                            color: #b3b3b3;
+                        }
 
-                                &:focus,
-                                &:hover {
-                                    text-decoration: underline;
-                                }
-                            }
+                        var {
+                            color: #aa0000;
+                            font-style: normal;
+                            margin-left: 3px;
+                            letter-spacing: -1px;
+                            vertical-align: middle;
                         }
 
-                        strong {
-                            font-weight: 500;
-                            margin-bottom: 3px;
-                            display: block;
+                        i {
+                            color: #cbd5e0;
+                            margin-left: 3px;
+                            vertical-align: -1px;
                         }
 
-                        ul {
-                            list-style: none;
-                            padding-left: 0;
-                            margin: 0;
-
-                            li {
-                                display: inline-block;
-                                font-size: 13px;
-
-                                &:first-child::before {display: none;}
-                                &::before {
-                                    content: '';
-                                    display: inline-block;
-                                    width: 2px;
-                                    height: 2px;
-                                    margin: 0 5px 4px 2px;
-                                    border-radius: 2px;
-                                    background-color: #616670;
-                                }
-                            }
+                        span {
+                            font-size: 10px;
+                            margin-left: 3px;
+                            vertical-align: middle;
                         }
                     }
                 }
             }
+
+            tfoot {
+                tr td {
+                    border-bottom: none;
+
+                    nav ul {
+                        margin-bottom: 0;
+                    }
+                }
+            }
+        }
+
+    // 사진/동영상
+    figure {
+        box-sizing: border-box;
+        margin: 0;
+        text-align: center;
+
+        > a {
+            position: relative;
+            display: block;
+            min-width: 140px;
+            min-height: 140px;
+            max-height: 160px;
+            margin: 0;
+
+            img {
+                position: absolute;
+                width: 100%;
+                top: 0;
+                left: 0;
+
+                &:hover {
+                    filter: drop-shadow(2px 2px 4px #969696);
+                }
+            }
+
+            &:hover,
+            &:focus {
+                text-decoration: underline;
+            }
+        }
+
+        figcaption {
+            margin: 5px 0;
+
+            > a {
+                display: initial;
+
+                &:focus,
+                &:hover {
+                    text-decoration: underline;
+                }
+            }
+
+            label {
+                margin-right: 5px;
+
+                a {
+                    color: #cbd5e0;
+                }
+            }
+
+            del, a {
+                font-size: 14px;
+                font-weight: normal;
+                color: #b3b3b3;
+            }
+
+            var {
+                color: #aa0000;
+                font-style: normal;
+                margin-left: 3px;
+                letter-spacing: -1px;
+                vertical-align: middle;
+            }
+
+            i {
+                color: #cbd5e0;
+                margin-left: 3px;
+                vertical-align: -1px;
+            }
+
+            span {
+                font-size: 10px;
+                margin-left: 3px;
+                vertical-align: middle;
+            }
         }
 
-        tfoot {
-            tr td {
-                border-bottom: none;
+        strong {
+            font-weight: 500;
+            margin-bottom: 3px;
+            display: block;
+        }
 
-                nav ul {
-                    margin-bottom: 0;
+        ul {
+            list-style: none;
+            padding-left: 0;
+            margin: 0;
+
+            li {
+                display: inline-block;
+                font-size: 13px;
+
+                &:first-child::before {display: none;}
+                &::before {
+                    content: '';
+                    display: inline-block;
+                    width: 2px;
+                    height: 2px;
+                    margin: 0 5px 4px 2px;
+                    border-radius: 2px;
+                    background-color: #616670;
                 }
             }
         }

+ 3 - 1
resources/sass/mobile/account/loginLog.scss

@@ -12,7 +12,9 @@
         }
 
         tr {
-            th, td{
+            border-bottom: 1px solid #212121;
+            
+            th, td {
                 text-align: center;
             }
         }

+ 104 - 45
resources/sass/mobile/board/index.scss

@@ -117,56 +117,115 @@
                                     transform: translate(-50%, -50%);
                                 }
                             }
+                        }
+                    }
+                }
+            }
 
-                            // 사진/동영상
-                            > section {
-                                display: flex;
-                                flex-wrap: wrap;
-                                justify-content: space-around;
-
-                                // 사진 영역
-                                figure {
-                                    box-sizing: border-box;
-                                    text-align: center;
-                                    flex-basis: auto;
-                                    max-width: 50%;
-                                    padding: 5px;
-
-                                    > a {
-                                        display: inline-block;
-
-                                        img {
-                                            width: 100%;
-                                            max-width: 210px;
-                                            max-height: 215px;
-
-                                            &:focus,
-                                            &:hover {
-                                                filter: drop-shadow(2px 2px 4px #969696);
-                                            }
-                                        }
-                                    }
+            // 사진/동영상
+            > section {
+                display: flex;
+                flex-wrap: wrap;
+                justify-content: space-around;
+
+                // 사진 영역
+                figure {
+                    box-sizing: border-box;
+                    text-align: center;
+                    flex-basis: auto;
+
+                    > a {
+                        position: relative;
+                        display: block;
+
+                        img {
+                            position: absolute;
+                            width: 100%;
+                            top: 0;
+                            left: 0;
+
+                            &:hover {
+                                filter: drop-shadow(2px 2px 4px #969696);
+                            }
+                        }
+                    }
 
-                                    figcaption {
-                                        margin: 5px 0;
+                    figcaption {
+                        margin: 5px 0;
 
-                                        a {
-                                            display: initial;
-                                        }
-                                    }
+                        p {
+                            margin-bottom: 0.125rem;
+                        }
 
-                                    // 작성자
-                                    strong {
-                                        display: block;
-                                        font-size: 0.813rem;
-                                        margin-bottom: 3px;
-                                    }
+                        > a {
+                            display: initial;
+                        }
+                        
+                        label {
+                            margin-right: 5px;
 
-                                    // 작성일자
-                                    small {
-                                        font-size: 0.688rem;
-                                    }
-                                }
+                            a {
+                                color: #cbd5e0;
+                            }
+                        }
+
+                        del, a {
+                            font-size: 14px;
+                            font-weight: normal;
+                            color: #b3b3b3;
+                        }
+
+                        var {
+                            color: #aa0000;
+                            font-style: normal;
+                            margin-left: 3px;
+                            letter-spacing: -1px;
+                            vertical-align: middle;
+                        }
+
+                        i {
+                            color: #cbd5e0;
+                            margin-left: 3px;
+                            vertical-align: -1px;
+                        }
+
+                        span {
+                            font-size: 10px;
+                            margin-left: 3px;
+                            vertical-align: middle;
+                        }
+                    }
+
+                    // 작성자
+                    strong {
+                        display: block;
+                        font-size: 0.813rem;
+                        margin-bottom: 3px;
+                    }
+
+                    // 작성일자
+                    small {
+                        font-size: 0.688rem;
+                    }
+
+                    ul {
+                        list-style: none;
+                        padding-left: 0;
+                        margin: 0;
+
+                        li {
+                            display: inline-block;
+                            font-size: 13px;
+
+                            &:first-child::before {display: none;}
+                            &::before {
+                                content: '';
+                                display: inline-block;
+                                width: 2px;
+                                height: 2px;
+                                margin: 0 5px 4px 2px;
+                                border-radius: 2px;
+                                background-color: #616670;
                             }
                         }
                     }

+ 104 - 45
resources/sass/mobile/board/latest.scss

@@ -91,56 +91,115 @@
                             transform: translate(-50%, -50%);
                         }
                     }
+                }
+            }
+        }
+    }
 
-                    // 사진/동영상
-                    > section {
-                        display: flex;
-                        flex-wrap: wrap;
-                        justify-content: space-around;
-
-                        // 사진 영역
-                        figure {
-                            box-sizing: border-box;
-                            text-align: center;
-                            flex-basis: auto;
-                            max-width: 50%;
-                            padding: 5px;
-
-                            > a {
-                                display: inline-block;
-
-                                img {
-                                    width: 100%;
-                                    max-width: 210px;
-                                    max-height: 215px;
-
-                                    &:focus,
-                                    &:hover {
-                                        filter: drop-shadow(2px 2px 4px #969696);
-                                    }
-                                }
-                            }
+    // 사진/동영상
+    > section {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-around;
+
+        // 사진 영역
+        figure {
+            box-sizing: border-box;
+            text-align: center;
+            flex-basis: auto;
+
+            > a {
+                position: relative;
+                display: block;
+
+                img {
+                    position: absolute;
+                    width: 100%;
+                    top: 0;
+                    left: 0;
+
+                    &:hover {
+                        filter: drop-shadow(2px 2px 4px #969696);
+                    }
+                }
+            }
 
-                            figcaption {
-                                margin: 5px 0;
+            figcaption {
+                margin: 5px 0;
 
-                                a {
-                                    display: initial;
-                                }
-                            }
+                p {
+                    margin-bottom: 0.125rem;
+                }
 
-                            // 작성자
-                            strong {
-                                display: block;
-                                font-size: 0.813rem;
-                                margin-bottom: 3px;
-                            }
+                > a {
+                    display: initial;
+                }
+                
+                label {
+                    margin-right: 5px;
 
-                            // 작성일자
-                            small {
-                                font-size: 0.688rem;
-                            }
-                        }
+                    a {
+                        color: #cbd5e0;
+                    }
+                }
+
+                del, a {
+                    font-size: 14px;
+                    font-weight: normal;
+                    color: #b3b3b3;
+                }
+
+                var {
+                    color: #aa0000;
+                    font-style: normal;
+                    margin-left: 3px;
+                    letter-spacing: -1px;
+                    vertical-align: middle;
+                }
+
+                i {
+                    color: #cbd5e0;
+                    margin-left: 3px;
+                    vertical-align: -1px;
+                }
+
+                span {
+                    font-size: 10px;
+                    margin-left: 3px;
+                    vertical-align: middle;
+                }
+            }
+
+            // 작성자
+            strong {
+                display: block;
+                font-size: 0.813rem;
+                margin-bottom: 3px;
+            }
+
+            // 작성일자
+            small {
+                font-size: 0.688rem;
+            }
+
+            ul {
+                list-style: none;
+                padding-left: 0;
+                margin: 0;
+
+                li {
+                    display: inline-block;
+                    font-size: 13px;
+
+                    &:first-child::before {display: none;}
+                    &::before {
+                        content: '';
+                        display: inline-block;
+                        width: 2px;
+                        height: 2px;
+                        margin: 0 5px 4px 2px;
+                        border-radius: 2px;
+                        background-color: #616670;
                     }
                 }
             }

+ 1 - 0
resources/views/admin/layouts/app.blade.php

@@ -30,6 +30,7 @@
 
     <script>
         // 자바스크립트에서 사용하는 전역변수 선언
+        var UID = {{ UID }};
         var BASE_URL = "{{ BASE_URL }}";
         var FULL_URL = "{{ FULL_URL }}";
         var ADMIN_URL = "{{ ADMIN_URL }}";

+ 25 - 4
resources/views/admin/page/menu/index.blade.php

@@ -81,14 +81,25 @@
                                                 </td>
                                             </tr>
                                             <tr>
-                                                <th colspan="3">URL</th>
+                                                <th colspan="2">URL</th>
+                                                <th>게시판</th>
                                                 <th>아이콘</th>
                                                 <th>새창 여부</th>
                                             </tr>
                                             <tr>
-                                                <td colspan="3">
+                                                <td colspan="2">
                                                     <input type="text" name="link[{{ $menu->id }}]" class="form-control" value="{{ $menu->link }}"/>
                                                 </td>
+                                                <td>
+                                                    <select name="board_id[{{ $menu->id }}]" class="form-select">
+                                                        <option value="">게시판 선택(연동 필요 시만)</option>
+                                                        @foreach($boardList as $b)
+                                                            <option value="{{ $b->id }}" @if((int)$menu->board_id == (int)$b->id) selected @endif>
+                                                                {{ $b->name }}
+                                                            </option>
+                                                        @endforeach
+                                                    </select>
+                                                </td>
                                                 <td>
                                                     <input type="text" name="icon[{{ $menu->id }}]" class="form-control" value="{{ $menu->icon }}"/>
                                                 </td>
@@ -166,14 +177,24 @@
                         </td>
                     </tr>
                     <tr>
-                        <th colspan="4">URL</th>
+                        <th colspan="3">URL</th>
+                        <th>게시판</th>
                         <th>아이콘</th>
                         <th>새창 여부</th>
                     </tr>
                     <tr>
-                        <td colspan="4">
+                        <td colspan="3">
                             <input type="text" name="link" class="form-control" value=""/>
                         </td>
+                        <td>
+                            <select name="board_id" class="form-select">
+                                <option value="">게시판 선택(연동 필요 시만)</option>
+                                @foreach($boardList as $b)
+                                    <option value="{{ $b->id }}">
+                                        {{ $b->name }}
+                                    </option>
+                                @endforeach
+                            </select>
                         <td>
                             <input type="text" name="icon" class="form-control" value=""/>
                         </td>

+ 0 - 0
resources/views/layouts/sub.blade.php → resources/views/auth/layout.blade.php


+ 1 - 1
resources/views/auth/login.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.sub')
+@extends('auth.layout')
 
 @section('content')
 <div id="loginForm" class="container">

+ 1 - 1
resources/views/auth/passwords/confirm.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.sub')
+@extends('auth.layout')
 
 @section('content')
 <div id="passwordConfirm" class="container">

+ 1 - 1
resources/views/auth/passwords/email.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.sub')
+@extends('auth.layout')
 
 @section('content')
 <div id="passwordEmail" class="container">

+ 1 - 1
resources/views/auth/passwords/reset.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.sub')
+@extends('auth.layout')
 
 @section('content')
 <div id="passwordReset" class="container-fluid">

+ 1 - 1
resources/views/auth/register.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.sub')
+@extends('auth.layout')
 
 @section('content')
 <div id="registerForm" class="container">

+ 1 - 1
resources/views/auth/verify.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.sub')
+@extends('auth.layout')
 
 @section('content')
 <div id="verifyForm" class="container-fluid">

+ 0 - 51
resources/views/board/comment/pagination.blade.php

@@ -1,51 +0,0 @@
-@if($paginator->count() > 0 && $paginator->total() > $paginator->perPage())
-@php
-    $block = ceil($paginator->currentPage() / $paginator->onEachSide);
-    $prevBlockPage = (($block - 1) * $paginator->onEachSide);
-    $nextBlockPage = (($block + 1) * $paginator->onEachSide - ($paginator->onEachSide - 1));
-@endphp
-<ul class="pagination">
-    {{-- Previous Page Link --}}
-    @if ($paginator->onFirstPage())
-        <li class="page-item disabled" aria-disabled="true" aria-label="@lang('pagination.previous')">
-            <span class="page-link" aria-hidden="true">&lsaquo;</span>
-        </li>
-    @else
-        <li class="page-item">
-            <a class="page-link" href="{{ $paginator->previousPageUrl() }}" rel="prev" aria-label="@lang('pagination.previous')">&lsaquo;</a>
-        </li>
-    @endif
-
-    {{-- Pagination Elements --}}
-    @foreach ($elements as $element)
-        {{-- "Three Dots" Separator --}}
-        @if (is_string($element))
-            <li class="page-item disabled" aria-disabled="true"><span class="page-link">{{ $element }}</span></li>
-        @endif
-
-        {{-- Array Of Links --}}
-        @if (is_array($element))
-            @foreach ($element as $page => $url)
-                @if($page > $prevBlockPage && $page < $nextBlockPage)
-                    @if ($page == $paginator->currentPage())
-                        <li class="page-item active" aria-current="page"><span class="page-link">{{ $page }}</span></li>
-                    @else
-                        <li class="page-item"><a class="page-link" href="{{ $url }}">{{ $page }}</a></li>
-                    @endif
-                @endif
-            @endforeach
-        @endif
-    @endforeach
-
-    {{-- Next Page Link --}}
-    @if ($paginator->hasMorePages())
-        <li class="page-item">
-            <a class="page-link" href="{{ $paginator->nextPageUrl() }}" rel="next" aria-label="@lang('pagination.next')">&rsaquo;</a>
-        </li>
-    @else
-        <li class="page-item disabled" aria-disabled="true" aria-label="@lang('pagination.next')">
-            <span class="page-link" aria-hidden="true">&rsaquo;</span>
-        </li>
-    @endif
-</ul>
-@endif

+ 0 - 108
resources/views/board/component/media.blade.php

@@ -1,108 +0,0 @@
-@if($notices && $notices->total > 0)
-<table class="table">
-    <caption>
-        {{-- 분류/정렬/목록 수 --}}
-        @include('board.component.tab')
-    </caption>
-
-    <colgroup>
-        <col width="7%"/>
-        <col width="*"/>
-        <col width="14%"/>
-        <col width="14%"/>
-        <col width="8%"/>
-        <col width="8%"/>
-    </colgroup>
-    <thead>
-        <tr>
-            <th>번호</th>
-            <th>제목</th>
-            <th>작성자</th>
-            <th>작성일</th>
-            <th>조회</th>
-            <th>추천</th>
-        </tr>
-    </thead>
-    <tbody>
-
-        {{-- 공지사항 --}}
-        @include('board.component.notice')
-   
-    </tbody>
-</table>
-@endif
-
-{{-- 사진/동영상 게시글 --}}
-@if($posts->total > 0)
-<div class="row row-cols-sm-4 row-cols-xl-6">
-    @foreach($posts->list as $row)
-        <div class="col">
-            <figure class="figure h-100 d-flex flex-column">
-                <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html" class="ratio ratio-4x3">
-                    @if($row->thumbnail)
-                        <img src="{{ $row->thumbnail }}" class="figure-img img-fluid rounded object-fit-cover" alt="{{ $row->subject }}" onerror="{{ NO_IMAGE_NORMAL_SRC }}'"/>
-                    @else
-                        <img src="{{ NO_IMAGE_NORMAL_SRC }}" class="figure-img img-fluid rounded object-fit-cover" alt="No Image"/>
-                    @endif
-                </a>
-            <figcaption class="figure-caption">
-                @if($boardMeta->use_category && $row->categoryName)
-                    <label>
-                        <a href="{{ $listURL }}?category={{ $row->board_category_id }}" rel="search">
-                            [{{ $row->categoryName }}]
-                        </a>
-                    </label>
-                @endif
-                @if($row->is_secret)
-                    <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">
-                        <i class="fas fa-lock"></i> 비밀글입니다.
-                    </a>
-                @elseif($row->isBlame)
-                    <i class="fas fa-ban"></i> <del>{{ $row->subject }}</del>
-                @else
-                    <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">{{ $row->subject }}</a>
-                @endif
-                @if($row->comment_rows > 0)
-                    <var>[{{ $row->comment_rows }}]</var>
-                @endif
-                @if($row->file_rows > 0)
-                    <i class="fas fa-save"></i>
-                @endif
-                @if($row->link_rows > 0)
-                    <i class="fas fa-external-link-alt"></i>
-                @endif
-                @if($row->image_rows > 0)
-                    <i class="fas fa-image"></i>
-                @endif
-                @if($row->isNew)
-                    <span class="badge bg-warning text-dark">New</span>
-                @endif
-                @if($row->isHot)
-                    <span class="badge bg-danger">Hot</span>
-                @endif
-            </figcaption>
-            <strong>{{ $row->user->name }}</strong>
-            <ul>
-                <li>{{ $row->createdAt }}</li>
-                <li>조회 <small>{{ $row->hit }}</small></li>
-                <li>좋아요 <small>{{ $row->like }}</small></li>
-            </ul>
-            </figure>
-        </div>
-    @endforeach
-</div>
-@else
-<tr>
-    <td colspan="6" class="p-5">
-        게시글이 존재하지 않습니다.
-    </td>
-</tr>
-@endif
-
-<hr/>
-
-@if($posts->total > 0)
-    {{ $posts->list->onEachSide($params->pageCount)->links('board.component.pagination') }}
-@endif
-
-<br/>

+ 1 - 1
resources/views/component/pagination.blade.php

@@ -6,7 +6,7 @@
     $prevBlockPage = (($block - 1) * $paginator->onEachSide);
     $nextBlockPage = (($block + 1) * $paginator->onEachSide - ($paginator->onEachSide - 1));
 @endphp
-<ul class="pagination">
+<ul class="pagination justify-content-start justify-content-sm-center">
     {{-- Previous Page Link --}}
     @if ($paginator->onFirstPage() || $prevBlockPage <= 0)
         <li class="page-item disabled" aria-disabled="true" aria-label="@lang('pagination.previous')">

+ 3 - 1
resources/views/component/uploader.blade.php

@@ -13,7 +13,9 @@
     <![endif]-->
 
     <!-- Scripts -->
-    @vite('resources/js/app.js')
+    @vite(['resources/sass/app.scss', 'resources/js/app.js'])
+    @stack('styles')
+
     <script>
         // 자바스크립트에서 사용하는 전역변수 선언
         var BASE_URL = "{{ BASE_URL }}";

+ 2 - 2
resources/views/account/certify.blade.php → resources/views/desktop/account/certify.blade.php

@@ -1,9 +1,9 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="accountCertify" class="container">
 
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <dl>
         <dt>비밀번호 확인</dt>

+ 2 - 2
resources/views/account/comment.blade.php → resources/views/desktop/account/comment.blade.php

@@ -1,8 +1,8 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="accountComment" class="container">
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <h4>작성 댓글</h4>
     <hr/>

+ 0 - 0
resources/views/account/email.blade.php → resources/views/desktop/account/email.blade.php


+ 2 - 3
resources/views/account/leave.blade.php → resources/views/desktop/account/leave.blade.php

@@ -1,9 +1,8 @@
-@extends('layouts.app')
-
+@extends('desktop.layouts.app')
 @section('content')
 <div id="accountLeave" class="container">
 
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <dl>
         <dt>회원탈퇴</dt>

+ 2 - 2
resources/views/account/loginLog.blade.php → resources/views/desktop/account/loginLog.blade.php

@@ -1,8 +1,8 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="accountLoginLog" class="container">
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <h4>로그인 기록</h4>
     <hr/>

+ 2 - 3
resources/views/account/modify.blade.php → resources/views/desktop/account/modify.blade.php

@@ -1,8 +1,7 @@
-@extends('layouts.app')
-
+@extends('desktop.layouts.app')
 @section('content')
 <div id="accountModify" class="container">
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <dl>
         <dt>회원 정보 수정</dt>

+ 0 - 0
resources/views/account/navTabs.blade.php → resources/views/desktop/account/navTabs.blade.php


+ 2 - 2
resources/views/account/passwordCampaign.blade.php → resources/views/desktop/account/passwordCampaign.blade.php

@@ -1,9 +1,9 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="accountPasswordCampaign" class="container">
 
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <dl>
         <dt>비밀번호 변경 안내</dt>

+ 2 - 2
resources/views/account/passwordChange.blade.php → resources/views/desktop/account/passwordChange.blade.php

@@ -1,9 +1,9 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="accountPassword" class="container">
 
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <dl>
         <dt>비밀번호 변경</dt>

+ 2 - 2
resources/views/account/post.blade.php → resources/views/desktop/account/post.blade.php

@@ -1,8 +1,8 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="accountPost" class="container">
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <h4>작성 게시글</h4>
     <hr/>

+ 4 - 12
resources/views/account/profile.blade.php → resources/views/desktop/account/profile.blade.php

@@ -1,8 +1,8 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="accountProfile" class="container">
-    @include('account.navTabs')
+    @include('desktop.account.navTabs')
 
     <dl>
         <dt>회원 정보</dt>
@@ -19,16 +19,8 @@
             <tr>
                 <th rowspan="5">계정</th>
                 <td>
-                    <div class="row">
-                        <div class="col">
-                            <h6>ID</h6>
-                            <small>{{ $user->sid }}</small>
-                        </div>
-                        <div class="col">
-                            <h6>적립금</h6>
-                            <small>{{ number_format($user->point) }}</small>
-                        </div>
-                    </div>
+                    <h6>ID</h6>
+                    {{ $user->sid }}
                 </td>
             </tr>
             <tr>

+ 0 - 0
resources/views/board/comment/error.blade.php → resources/views/desktop/board/comment/error.blade.php


+ 1 - 1
resources/views/board/comment/index.blade.php → resources/views/desktop/board/comment/index.blade.php

@@ -98,7 +98,7 @@
     <hr/>
     @endforeach
 
-    {{ $comment->list->onEachSide($params->pageCount)->links('board.comment.pagination') }}
+    {{ $comment->list->onEachSide($params->pageCount)->links('desktop.board.component.pagination') }}
 @endif
 
 @if($boardMeta->use_comment_blame)

+ 0 - 0
resources/views/board/comment/write.blade.php → resources/views/desktop/board/comment/write.blade.php


+ 1 - 1
resources/views/board/component/inquiry.blade.php → resources/views/desktop/board/component/inquiry.blade.php

@@ -104,7 +104,7 @@
     <tfoot>
         <tr>
             <td colspan="7">
-                {{ $posts->list->onEachSide($params->pageCount)->links('board.component.pagination') }}
+                {{ $posts->list->onEachSide($params->pageCount)->links('desktop.board.component.pagination') }}
             </td>
         </tr>
     </tfoot>

+ 70 - 82
resources/views/board/component/latest.blade.php → resources/views/desktop/board/component/latest.blade.php

@@ -92,7 +92,7 @@
             <tfoot>
                 <tr>
                     <td colspan="7">
-                        {{ $latest->list->onEachSide($pageCount)->links('board.component.pagination') }}
+                        {{ $latest->list->onEachSide($pageCount)->links('component.pagination') }}
                     </td>
                 </tr>
             </tfoot>
@@ -174,7 +174,7 @@
             <tfoot>
                 <tr>
                     <td colspan="7">
-                        {{ $latest->list->onEachSide($pageCount)->links('board.component.pagination') }}
+                        {{ $latest->list->onEachSide($pageCount)->links('component.pagination') }}
                     </td>
                 </tr>
             </tfoot>
@@ -185,87 +185,75 @@
         @elseif($boardMeta->board_layout_type == BOARD_LAYOUT_MEDIA)
 
         {{-- 사진/동영상 게시글 시작 --}}
-        <table class="table">
-            <tbody>
-            @if($latest->total > 0)
-                <tr>
-                    <td>
-                        <div class="row row-cols-sm-4 row-cols-xl-6">
-                        @foreach($latest->list as $row)
-                            <div class="col">
-                                <figure class="figure">
-                                    @if($row->thumbnail)
-                                        <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">
-                                            <img src="{{ $row->thumbnail }}" class="figure-img img-fluid" alt="{{ $row->subject }}" onerror="this.src='{{ NO_IMAGE_NORMAL_SRC }}'"/>
-                                        </a>
-                                    @endif
-                                    <figcaption class="figure-caption">
-                                        @if($boardMeta->use_category && $row->categoryName)
-                                            <label>
-                                                <a href="{{ $listURL }}?category={{ $row->board_category_id }}" rel="search">
-                                                    [{{ $row->categoryName }}]
-                                                </a>
-                                            </label>
-                                        @endif
-                                        @if($row->is_secret)
-                                            <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">
-                                                <i class="fas fa-lock"></i> 비밀글입니다.
-                                            </a>
-                                        @elseif($row->isBlame)
-                                            <i class="fas fa-ban"></i> <del>{{ $row->subject }}</del>
-                                        @else
-                                            <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">{{ $row->subject }}</a>
-                                        @endif
-                                        @if($row->comment_rows > 0)
-                                            <var>[{{ $row->comment_rows }}]</var>
-                                        @endif
-                                        @if($row->file_rows > 0)
-                                            <i class="fas fa-save"></i>
-                                        @endif
-                                        @if($row->link_rows > 0)
-                                            <i class="fas fa-external-link-alt"></i>
-                                        @endif
-                                        @if($row->image_rows > 0)
-                                            <i class="fas fa-image"></i>
-                                        @endif
-                                        @if($row->isNew)
-                                            <span class="badge bg-warning text-dark">New</span>
-                                        @endif
-                                        @if($row->isHot)
-                                            <span class="badge bg-danger">Hot</span>
-                                        @endif
-                                    </figcaption>
-                                    <strong>{{ $row->user->name }}</strong>
-                                    <ul>
-                                        <li>{{ $row->createdAt }}</li>
-                                        <li>조회 <small>{{ $row->hit }}</small></li>
-                                        <li>좋아요 <small>{{ $row->like }}</small></li>
-                                    </ul>
-                                </figure>
-                            </div>
-                        @endforeach
-                        </div>
-                    </td>
-                </tr>
-            @else
-                <tr>
-                    <td>
-                        게시글이 존재하지 않습니다.
-                    </td>
-                </tr>
-            @endif
-            </tbody>
+        @if($latest->total > 0)
+            <div class="row row-cols-sm-4 row-cols-xl-6 gx-3 gy-4">
+            @foreach($latest->list as $row)
+                <div class="col">
+                    <figure class="figure h-100 d-flex flex-column">
+                        <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html" class="ratio ratio-4x3">
+                            @if($row->thumbnail)
+                                <img src="{{ $row->thumbnail }}" class="figure-img img-fluid rounded object-fit-cover" alt="{{ $row->subject }}" onerror="{{ NO_IMAGE_NORMAL_SRC }}'"/>
+                            @else
+                                <img src="{{ NO_IMAGE_NORMAL_SRC }}" class="figure-img img-fluid rounded object-fit-cover" alt="No Image"/>
+                            @endif
+                        </a>
+                        <figcaption class="figure-caption">
+                            @if($boardMeta->use_category && $row->categoryName)
+                                <label>
+                                    <a href="{{ $listURL }}?category={{ $row->board_category_id }}" rel="search">
+                                        [{{ $row->categoryName }}]
+                                    </a>
+                                </label>
+                            @endif
+                            @if($row->is_secret)
+                                <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">
+                                    <i class="fas fa-lock"></i> 비밀글입니다.
+                                </a>
+                            @elseif($row->isBlame)
+                                <i class="fas fa-ban"></i> <del>{{ $row->subject }}</del>
+                            @else
+                                <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">{{ $row->subject }}</a>
+                            @endif
+                            @if($row->comment_rows > 0)
+                                <var>[{{ $row->comment_rows }}]</var>
+                            @endif
+                            @if($row->file_rows > 0)
+                                <i class="fas fa-save"></i>
+                            @endif
+                            @if($row->link_rows > 0)
+                                <i class="fas fa-external-link-alt"></i>
+                            @endif
+                            @if($row->image_rows > 0)
+                                <i class="fas fa-image"></i>
+                            @endif
+                            @if($row->isNew)
+                                <span class="badge bg-warning text-dark">New</span>
+                            @endif
+                            @if($row->isHot)
+                                <span class="badge bg-danger">Hot</span>
+                            @endif
+                        </figcaption>
+                        <strong>{{ $row->user->name }}</strong>
+                        <ul>
+                            <li>{{ $row->createdAt }}</li>
+                            <li>조회 <small>{{ $row->hit }}</small></li>
+                            <li>좋아요 <small>{{ $row->like }}</small></li>
+                        </ul>
+                    </figure>
+                </div>
+            @endforeach
+            </div>
+        @else
+            <div class="p-5 text-center">
+                게시글이 존재하지 않습니다.
+            </div>
+        @endif
 
-            @if($latest->total > 0)
-            <tfoot>
-                <tr>
-                    <td>
-                        {{ $latest->list->onEachSide($pageCount)->links('board.component.pagination') }}
-                    </td>
-                </tr>
-            </tfoot>
-            @endif
-        </table>
+        <hr/>
+
+        @if($latest->total > 0)
+            {{ $latest->list->onEachSide($pageCount)->links('desktop.board.component.pagination') }}
+        @endif
         {{-- 사진/동영상 게시글 종료 --}}
 
         @endif

+ 106 - 0
resources/views/desktop/board/component/media.blade.php

@@ -0,0 +1,106 @@
+@if($notices && $notices->total > 0)
+<table class="table">
+    <caption>
+        {{-- 분류/정렬/목록 수 --}}
+        @include('board.component.tab')
+    </caption>
+
+    <colgroup>
+        <col width="7%"/>
+        <col width="*"/>
+        <col width="14%"/>
+        <col width="14%"/>
+        <col width="8%"/>
+        <col width="8%"/>
+    </colgroup>
+    <thead>
+        <tr>
+            <th>번호</th>
+            <th>제목</th>
+            <th>작성자</th>
+            <th>작성일</th>
+            <th>조회</th>
+            <th>추천</th>
+        </tr>
+    </thead>
+    <tbody>
+
+        {{-- 공지사항 --}}
+        @include('board.component.notice')
+   
+    </tbody>
+</table>
+@endif
+
+{{-- 사진/동영상 게시글 --}}
+@if($posts->total > 0)
+<div class="row row-cols-sm-4 row-cols-xl-6 gx-3 gy-4">
+    @foreach($posts->list as $row)
+        <div class="col">
+            <figure class="figure h-100 d-flex flex-column">
+                <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html" class="ratio ratio-4x3">
+                    @if($row->thumbnail)
+                        <img src="{{ $row->thumbnail }}" class="figure-img img-fluid rounded object-fit-cover" alt="{{ $row->subject }}" onerror="{{ NO_IMAGE_NORMAL_SRC }}'"/>
+                    @else
+                        <img src="{{ NO_IMAGE_NORMAL_SRC }}" class="figure-img img-fluid rounded object-fit-cover" alt="No Image"/>
+                    @endif
+                </a>
+                <figcaption class="figure-caption">
+                    @if($boardMeta->use_category && $row->categoryName)
+                        <label>
+                            <a href="{{ $listURL }}?category={{ $row->board_category_id }}" rel="search">
+                                [{{ $row->categoryName }}]
+                            </a>
+                        </label>
+                    @endif
+                    @if($row->is_secret)
+                        <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">
+                            <i class="fas fa-lock"></i> 비밀글입니다.
+                        </a>
+                    @elseif($row->isBlame)
+                        <i class="fas fa-ban"></i> <del>{{ $row->subject }}</del>
+                    @else
+                        <a href="{{ $row->viewURL }}" hreflang="ko" referrerpolicy="origin" type="text/html">{{ $row->subject }}</a>
+                    @endif
+                    @if($row->comment_rows > 0)
+                        <var>[{{ $row->comment_rows }}]</var>
+                    @endif
+                    @if($row->file_rows > 0)
+                        <i class="fas fa-save"></i>
+                    @endif
+                    @if($row->link_rows > 0)
+                        <i class="fas fa-external-link-alt"></i>
+                    @endif
+                    @if($row->image_rows > 0)
+                        <i class="fas fa-image"></i>
+                    @endif
+                    @if($row->isNew)
+                        <span class="badge bg-warning text-dark">New</span>
+                    @endif
+                    @if($row->isHot)
+                        <span class="badge bg-danger">Hot</span>
+                    @endif
+                </figcaption>
+                <strong>{{ $row->user->name }}</strong>
+                <ul>
+                    <li>{{ $row->createdAt }}</li>
+                    <li>조회 <small>{{ $row->hit }}</small></li>
+                    <li>좋아요 <small>{{ $row->like }}</small></li>
+                </ul>
+            </figure>
+        </div>
+    @endforeach
+</div>
+@else
+<div class="p-5 text-center">
+    게시글이 존재하지 않습니다.
+</div>
+@endif
+
+<hr/>
+
+@if($posts->total > 0)
+    {{ $posts->list->onEachSide($params->pageCount)->links('desktop.board.component.pagination') }}
+@endif
+
+<br/>

+ 0 - 0
resources/views/board/component/notice.blade.php → resources/views/desktop/board/component/notice.blade.php


+ 0 - 0
resources/views/board/component/pagination.blade.php → resources/views/desktop/board/component/pagination.blade.php


+ 3 - 3
resources/views/board/component/post.blade.php → resources/views/desktop/board/component/post.blade.php

@@ -1,7 +1,7 @@
 <table class="table">
     <caption>
         {{-- 분류/정렬/목록 수 --}}
-        @include('board.component.tab')
+        @include('desktop.board.component.tab')
     </caption>
     <colgroup>
         <col width="6%"/>
@@ -24,7 +24,7 @@
     <tbody>
 
         {{-- 공지사항 --}}
-        @include('board.component.notice')
+        @include('desktop.board.component.notice')
 
         {{-- 일반 게시글 --}}
         @if($posts->total > 0)
@@ -86,7 +86,7 @@
     <tfoot>
         <tr>
             <td colspan="6">
-                {{ $posts->list->onEachSide($params->pageCount)->links('board.component.pagination') }}
+                {{ $posts->list->onEachSide($params->pageCount)->links('desktop.board.component.pagination') }}
             </td>
         </tr>
     </tfoot>

+ 0 - 0
resources/views/board/component/search.blade.php → resources/views/desktop/board/component/search.blade.php


+ 0 - 0
resources/views/board/component/tab.blade.php → resources/views/desktop/board/component/tab.blade.php


+ 1 - 1
resources/views/board/edit.blade.php → resources/views/desktop/board/edit.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="boardEdit" class="container">

+ 5 - 5
resources/views/board/index.blade.php → resources/views/desktop/board/index.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="board" class="container">
@@ -45,17 +45,17 @@
         <div class="body">
             @if($boardMeta->use_personal)
                 {{-- 1:1문의 --}}
-                @include('board.component.inquiry')
+                @include('desktop.board.component.inquiry')
             @elseif($boardMeta->board_layout_type == BOARD_LAYOUT_TYPE_0)
                 {{-- 공지/일반 게시판 --}}
-                @include('board.component.post')
+                @include('desktop.board.component.post')
             @elseif($boardMeta->board_layout_type == BOARD_LAYOUT_TYPE_1)
                 {{-- 사진/동영상 게시판--}}
-                @include('board.component.media')
+                @include('desktop.board.component.media')
             @endif
 
             {{-- 검색 --}}
-            @include('board.component.search')
+            @include('desktop.board.component.search')
         </div>
 
         {{-- 하단 광고 --}}

+ 1 - 1
resources/views/board/tag.blade.php → resources/views/desktop/board/tag.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section(section: 'content')
 <div class="container">

+ 3 - 3
resources/views/board/view.blade.php → resources/views/desktop/board/view.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="boardView" class="container">
@@ -246,7 +246,7 @@
 
                         <!-- 댓글 작성 -->
                         <div id="commentWrite">
-                            @include('board.comment.write')
+                            @include('desktop.board.comment.write')
                         </div>
                     </td>
                 </tr>
@@ -320,7 +320,7 @@
     </form>
 
     {{-- 최근 읽기 목록 --}}
-    @include('board.component.latest')
+    @include('desktop.board.component.latest')
 </div>
 @endsection
 

+ 1 - 1
resources/views/board/write.blade.php → resources/views/desktop/board/write.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="boardWrite" class="container">

+ 1 - 1
resources/views/document.blade.php → resources/views/desktop/document/index.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="document" class="container">

+ 4 - 4
resources/views/layouts/app.blade.php → resources/views/desktop/layouts/app.blade.php

@@ -122,7 +122,7 @@
                     <li class="nav-item">
                         <div class="dropdown">
                             <a href="#" id="account" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-bs-offset="-5,1">
-                                {{ $user->nickname }}님 <span class="caret"></span>
+                                {{ $user->nickname ?: $user->name }}님 <span class="caret"></span>
                             </a>
                             <div class="dropdown-menu dropdown-menu-right">
                                 @admin
@@ -155,7 +155,7 @@
                                 if($meta->hasChildren) {
                                     $hasClass = 'class="has-children"';
                                 }
-                                $html .= sprintf('<li %s><a href="%s" class="dropdown-item" target="%s" %s>%s</a>', $hasClass, $meta->url, $meta->target, $meta->custom, $meta->name);
+                                $html .= sprintf('<li %s><a href="%s" class="dropdown-item" target="%s" %s>%s <small>($d)</small></a>', $hasClass, $meta->url, $meta->target, $meta->custom, $meta->name, $meta->postCount);
                                 $html .= $buildSubMenu($cate->children);
                                 $html .= '</li>';
                             }
@@ -166,14 +166,14 @@
                     @foreach($topMenu[0] as $row)
                         <a href="{{ $row->url }}" target="{{ $row->target }}" {{ $row->custom }} class="nav-link @if(!$row->isLeaf) dropdown-toggle @endif"
                             @if(!$row->isLeaf) data-bs-toggle="dropdown" role="button" aria-expanded="false" data-bs-offset="10,-5" @endif>
-                            {{ $row->name }}
+                            {{ $row->name }} @if($row->board_id) <small>({{ $row->postCount }})</small> @endif
                         </a>
                         @if($row->hasChildren)
                             <ul class="dropdown-menu">
                                 @foreach($row->children as $mn)
                                     @php $meta = $subMenu[$mn->id]; @endphp
                                     <li @if($meta->hasChildren) class="has-children" @endif>
-                                        <a href="{{ $meta->url }}" class="dropdown-item" target="{{ $meta->target }}" {{ $meta->custom }}>{{ $meta->name }}</a>
+                                        <a href="{{ $meta->url }}" class="dropdown-item" target="{{ $meta->target }}" {{ $meta->custom }}>{{ $meta->name }}({{ $meta->postCount }})</a>
                                         @if($meta->hasChildren)
                                         @php echo $buildSubMenu($mn->children) @endphp
                                         @endif

+ 89 - 0
resources/views/desktop/layouts/sub.blade.php

@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
+<head>
+    <meta charset="utf-8"/>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <meta name="apple-mobile-web-app-title" content="{{ config('meta_application_name') }}"/>
+    @if($metaViewport = config('meta_viewport'))
+        <meta name="viewport" content="{{ $metaViewport }}"/>
+    @else
+        <meta name="viewport" content="width=device-width, initial-scale=1"/>
+    @endif
+    @if($metaRobots = config('meta_robots'))
+        <meta name="robots" content="{{ $metaRobots }}"/>
+    @endif
+    @if($metaAuthor = config('meta_author'))
+        <meta name="author" content="{{ $metaAuthor }}"/>
+    @endif
+    @if($metaKeywords = config('meta_keywords'))
+        <meta name="keywords" content="{{ $metaKeywords }}"/>
+    @endif
+    @if($metaDescription = config('meta_description'))
+        <meta name="description" content="{{ $metaDescription }}"/>
+    @endif
+    {!! config('meta_adds_info') !!}
+
+    <!-- CSRF Token -->
+    <meta name="csrf-token" content="{{ csrf_token() }}"/>
+
+    <title>{{ config('site_title', config('app.name')) }}</title>
+
+    @if($siteFavicon = config('site_favicon'))
+        <link rel="icon" type="image/x-icon" href="{{ asset($siteFavicon) }}"/>
+        <link rel="shortcut icon" type="image/x-icon" href="{{ asset($siteFavicon) }}"/>
+    @endif
+
+    @vite(['resources/sass/app.scss', 'resources/js/app.js'])
+    <link rel="stylesheet" href="{{ asset('css/mobile/layout.css') }}"/>
+    @stack('styles')
+
+    <script>
+        // 자바스크립트에서 사용하는 전역변수 선언
+        var BASE_URL = "{{ BASE_URL }}";
+        var FULL_URL = "{{ FULL_URL }}";
+        var ADMIN_URL = "{{ ADMIN_URL }}";
+        var CHARSET = "{{ CHARSET }}";
+        var DATE = "{{ DATE }}";
+        var DATETIME = "{{ DATETIME }}";
+        var IP_ADDRESS = "{{ IP_ADDRESS }}";
+        var REFERER = "{{ REFERER }}";
+        var USER_AGENT = "{{ USER_AGENT }}";
+        var DEVICE = "{{ DEVICE }}";
+        var PLATFORM = "{{ PLATFORM }}";
+        var BROWSER = "{{ BROWSER }}";
+        var IS_USER = {{ IS_USER }};
+        var IS_ADMIN = {{ IS_ADMIN }};
+        var IS_FRONT = 1;
+        var CSRF = "{{ csrf_token() }}";
+    </script>
+
+    <!--[if lt IE 9]>
+    <script src="{{ asset('js/common/html5shiv.min.js') }}" defer></script>
+    <script src="{{ asset('js/common/respond.min.js') }}" defer></script>
+    <script src="{{ asset('js/common/ie8-responsive-file-warning.js') }}" defer></script>
+    <![endif]-->
+
+    <script src="{{ asset('/js/common/common.js') }}" defer></script>
+    <script src="{{ asset('/js/common/jquery.validate.extension.js') }}" defer></script>
+    <script src="{{ asset('/js/front.js') }}" defer></script>
+
+    <!-- Google tag (gtag.js) -->
+    <script async src="https://www.googletagmanager.com/gtag/js?id=G-E4M2FCM7HR"></script>
+    <script>
+        window.dataLayer = window.dataLayer || [];
+        function gtag(){dataLayer.push(arguments);}
+        gtag('js', new Date());
+
+        gtag('config', 'G-E4M2FCM7HR');
+    </script>
+</head>
+<body id="app">
+    @yield('content')
+
+    @stack('scripts')
+
+    @include('component.loading')
+    @include('component.popup')
+    @include('component.alert')
+</body>
+</html>

+ 1 - 1
resources/views/main.blade.php → resources/views/desktop/main.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="index" class="container">

+ 2 - 2
resources/views/recently.blade.php → resources/views/desktop/recently.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app')
+@extends('desktop.layouts.app')
 
 @section('content')
 <div id="board" class="container">
@@ -143,7 +143,7 @@
                 <tfoot>
                     <tr>
                         <td colspan="6">
-                            {{ $recent->list->onEachSide($params->pageCount)->links('board.component.pagination') }}
+                            {{ $recent->list->onEachSide($params->pageCount)->links('desktop.board.component.pagination') }}
                         </td>
                     </tr>
                 </tfoot>

+ 0 - 0
resources/views/service/anniversary/index.blade.php → resources/views/desktop/service/anniversary/index.blade.php


+ 0 - 0
resources/views/service/fifa/index.blade.php → resources/views/desktop/service/fifa/index.blade.php


+ 0 - 0
resources/views/service/financial/exchange.blade.php → resources/views/desktop/service/financial/exchange.blade.php


Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů