feat: Relay 브랜드 로고·favicon 전면 적용

사이드바·인증 화면 'R' 텍스트 로고를 브랜드 더블 셰브론 마크(RelayMark)로 교체.
favicon을 SVG+PNG+ICO 세트와 웹 매니페스트로 정비(create-vue 기본 아이콘 대체), 가운데 셰브론을 키워 작은 크기 가독성 개선.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 12:06:31 +09:00
parent 6767316cdb
commit 433901312d
25 changed files with 105 additions and 18 deletions
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="ko">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<!-- 파비콘/앱 아이콘 (Relay 브랜드) — .ico(레거시) + svg(모던) 조합 -->
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180.png" />
<link rel="manifest" href="/manifest.webmanifest" />
<meta name="theme-color" content="#4f46e5" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Relay — 사내 업무 지시 플랫폼" />
<!-- Pretendard 웹폰트 (디자인 시안 기준 서체) -->
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="Relay app icon">
<defs>
<linearGradient id="relayGrad" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5b54f0"/>
<stop offset="1" stop-color="#4338ca"/>
</linearGradient>
</defs>
<rect width="512" height="512" rx="120" fill="url(#relayGrad)"/>
<g fill="none" stroke="#ffffff" stroke-width="52" stroke-linecap="round" stroke-linejoin="round">
<path d="M128 130 L256 256 L128 382"/>
<path d="M256 130 L384 256 L256 382"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 591 B

+28
View File
@@ -0,0 +1,28 @@
{
"name": "Relay — 사내 업무 지시 플랫폼",
"short_name": "Relay",
"description": "프로젝트 단위로 업무를 정리하고 담당자에게 지시하는 사내 업무 플랫폼",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4f46e5",
"icons": [
{
"src": "/favicon.svg",
"type": "image/svg+xml",
"sizes": "any"
},
{
"src": "/relay-icon-256.png",
"type": "image/png",
"sizes": "256x256",
"purpose": "any maskable"
},
{
"src": "/relay-icon-512.png",
"type": "image/png",
"sizes": "512x512",
"purpose": "any maskable"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 B

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 46 KiB

@@ -1,13 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="Relay app icon">
<defs>
<linearGradient id="relayGrad" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5b54f0"></stop>
<stop offset="1" stop-color="#4338ca"></stop>
<stop offset="0" stop-color="#5b54f0"/>
<stop offset="1" stop-color="#4338ca"/>
</linearGradient>
</defs>
<rect width="512" height="512" rx="143" fill="url(#relayGrad)"></rect>
<svg x="160" y="160" width="192" height="192" viewBox="0 0 32 32">
<path d="M8 8 L16 16 L8 24" fill="none" stroke="#ffffff" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M16 8 L24 16 L16 24" fill="none" stroke="#ffffff" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</svg>
<rect width="512" height="512" rx="120" fill="url(#relayGrad)"/>
<g fill="none" stroke="#ffffff" stroke-width="52" stroke-linecap="round" stroke-linejoin="round">
<path d="M128 130 L256 256 L128 382"/>
<path d="M256 130 L384 256 L256 382"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 765 B

After

Width:  |  Height:  |  Size: 591 B

+35
View File
@@ -0,0 +1,35 @@
<script setup lang="ts">
// Relay 브랜드 마크(더블 셰브론) — 색상 로고 타일 안에 들어가는 심볼.
// 색상/그라데이션 배경 타일에는 white, 흰/투명 배경에는 기본(인디고)을 사용한다.
import markWhite from '@/assets/images/logo/svg/relay-mark-white.svg'
import mark from '@/assets/images/logo/svg/relay-mark.svg'
withDefaults(defineProps<{ white?: boolean }>(), { white: false })
</script>
<template>
<!-- 부모 타일이 어떤 정렬을 쓰든 중앙에 오도록 자체 중앙 정렬 -->
<span class="relay-mark">
<img
:src="white ? markWhite : mark"
alt=""
aria-hidden="true"
draggable="false"
>
</span>
</template>
<style scoped>
.relay-mark {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.relay-mark img {
width: 66%;
height: 66%;
object-fit: contain;
}
</style>
+2 -1
View File
@@ -7,6 +7,7 @@ import { useRoute, useRouter, RouterLink } from 'vue-router'
import { useAuthStore } from '@/stores/auth.store'
import { useNotificationStore } from '@/stores/notification.store'
import UserAvatar from '@/components/UserAvatar.vue'
import RelayMark from '@/components/RelayMark.vue'
import AgentChatPanel from '@/components/AgentChatPanel.vue'
import type { NotificationView } from '@/types/notification'
@@ -96,7 +97,7 @@ async function onLogout() {
title="Relay"
>
<div class="logo">
R
<RelayMark white />
</div>
<span class="brand-name">Relay</span>
</RouterLink>
@@ -3,6 +3,7 @@
// 브라우저가 스크립트의 창 닫기를 차단할 수 있으므로(사용자가 직접 연 탭),
// 안내 문구를 함께 보여 사용자가 직접 닫고 기존 화면에서 로그인하도록 한다.
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import RelayMark from '@/components/RelayMark.vue'
import { useRoute, RouterLink } from 'vue-router'
const route = useRoute()
@@ -30,7 +31,7 @@ onBeforeUnmount(() => {
<div class="verified-wrap">
<div class="card">
<div class="brand">
<span class="logo">R</span> Relay
<span class="logo"><RelayMark white /></span> Relay
</div>
<!-- 인증 성공 -->
@@ -3,6 +3,7 @@
// 이메일 입력(1단계) → 전송 완료 안내(2단계). 존재 여부는 노출하지 않는다.
import { onBeforeUnmount, ref } from 'vue'
import { RouterLink } from 'vue-router'
import RelayMark from '@/components/RelayMark.vue'
import { useAuth } from '@/composables/useAuth'
const { forgotPassword } = useAuth()
@@ -66,7 +67,7 @@ onBeforeUnmount(() => {
<div class="blob b2" />
<div class="ring" />
<div class="bp-logo">
<span class="logo">R</span> Relay
<span class="logo"><RelayMark white /></span> Relay
</div>
<div class="bp-body">
<div class="bp-head">
@@ -106,7 +107,7 @@ onBeforeUnmount(() => {
<main class="form-panel">
<div class="auth-card">
<div class="ac-logo">
<span class="logo">R</span> Relay
<span class="logo"><RelayMark white /></span> Relay
</div>
<!-- 1단계: 이메일 입력 -->
+3 -2
View File
@@ -2,6 +2,7 @@
// 로그인 — 좌측 브랜드 패널 + 우측 로그인 폼
import { computed, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import RelayMark from '@/components/RelayMark.vue'
import { useAuthStore } from '@/stores/auth.store'
const route = useRoute()
@@ -69,7 +70,7 @@ const points = [
<div class="blob b2" />
<div class="ring" />
<div class="bp-logo">
<span class="logo">R</span> Relay
<span class="logo"><RelayMark white /></span> Relay
</div>
<div class="bp-body">
<div class="bp-head">
@@ -110,7 +111,7 @@ const points = [
<main class="form-panel">
<div class="auth-card">
<div class="ac-logo">
<span class="logo">R</span> Relay
<span class="logo"><RelayMark white /></span> Relay
</div>
<h1 class="ac-title">
로그인
@@ -2,6 +2,7 @@
// 비밀번호 재설정 — 메일 링크의 token(쿼리)으로 새 비밀번호를 설정
import { computed, ref } from 'vue'
import { useRoute, useRouter, RouterLink } from 'vue-router'
import RelayMark from '@/components/RelayMark.vue'
import { useAuth } from '@/composables/useAuth'
const route = useRoute()
@@ -45,7 +46,7 @@ async function onSubmit() {
<div class="auth-simple">
<div class="card">
<div class="bp-logo">
<span class="logo">R</span> Relay
<span class="logo"><RelayMark white /></span> Relay
</div>
<!-- 토큰 없음 -->
+3 -2
View File
@@ -2,6 +2,7 @@
// 회원가입 — 가입 폼 → 인증 메일 발송 안내. 인증 메일의 링크를 눌러야 가입이 완료된다.
import { computed, ref } from 'vue'
import { RouterLink } from 'vue-router'
import RelayMark from '@/components/RelayMark.vue'
import { useAuthStore } from '@/stores/auth.store'
import { useDialog } from '@/composables/useDialog'
@@ -98,7 +99,7 @@ const points = [
<div class="blob b2" />
<div class="ring" />
<div class="bp-logo">
<span class="logo">R</span> Relay
<span class="logo"><RelayMark white /></span> Relay
</div>
<div class="bp-body">
<div class="bp-head">
@@ -138,7 +139,7 @@ const points = [
<main class="form-panel">
<div class="auth-card">
<div class="ac-logo">
<span class="logo">R</span> Relay
<span class="logo"><RelayMark white /></span> Relay
</div>
<!-- 상태 1: 가입 -->