공개: alpha.5 기준선 갱신
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
### Changed
|
||||
|
||||
- 데스크톱/웹 스크린샷 캡처를 앱 창·앱 셸 기준으로 정리하고, README·SHOWCASE 이미지를 실제 종횡비에 맞춘 `width/height` 기준으로 재배치
|
||||
- 공개 원격 배포 정책을 `public/* 브랜치 + 버전 태그 + 릴리즈 페이지 + 자산` 기준으로 고정
|
||||
- Gitea/GitHub 릴리즈 게시 스크립트가 지정 원격 기준으로 동작하고 최신 스크린샷 자산도 함께 첨부하도록 확장
|
||||
- 비-`origin` 원격에 대한 로컬 pre-push 가드가 `public/*` 브랜치와 `refs/tags/*`를 함께 허용하도록 조정
|
||||
|
|
|
|||
64
README.md
|
|
@ -1,5 +1,9 @@
|
|||
# KoTalk
|
||||
|
||||
<p align="center">
|
||||
<img src="branding/png/kotalk-transparent-256.png" alt="KoTalk mark" width="96" height="96">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>한국어 중심의 차분한 메시징 경험을 다시 설계하는 오픈소스 프로젝트.</strong>
|
||||
</p>
|
||||
|
|
@ -26,6 +30,7 @@
|
|||
<a href="PROJECT_STATUS.md">Project Status</a> ·
|
||||
<a href="SHOWCASE.md">Showcase</a> ·
|
||||
<a href="BACKGROUND.md">Background</a> ·
|
||||
<a href="branding/BRAND_GUIDE.md">Brand Guide</a> ·
|
||||
<a href="FAQ.md">FAQ</a> ·
|
||||
<a href="RELEASING.md">Releases</a> ·
|
||||
<a href="TRUST_CENTER.md">Trust Center</a> ·
|
||||
|
|
@ -44,7 +49,7 @@
|
|||
</table>
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/assets/latest/hero-shell.png" alt="KoTalk desktop shell" width="920">
|
||||
<img src="docs/assets/latest/hero-shell.png" alt="KoTalk desktop shell" width="920" height="652">
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>플랫한 화이트 톤과 컴팩트한 창 밀도를 기준으로 정리한 현재 데스크톱 셸</em>
|
||||
|
|
@ -88,16 +93,53 @@ KoTalk는 이 배경을 리스크 문구로 숨기지 않고, 왜 이 프로젝
|
|||
|
||||
현재 저장소에서 바로 볼 수 있는 화면과 산출물은 아래와 같습니다.
|
||||
|
||||
| Surface | What to look at | Visual |
|
||||
|---|---|---|
|
||||
| Desktop shell | 레일 + 목록 + 대화 중심의 3단 구조, 플랫한 보더, 멀티 윈도우 전제 | [hero-shell.png](docs/assets/latest/hero-shell.png) |
|
||||
| Desktop onboarding | 첫 실행 시 서버 주소보다 사용자 흐름을 먼저 보여주는 가벼운 진입 | [onboarding.png](docs/assets/latest/onboarding.png) |
|
||||
| Desktop conversation | 메시지 흐름, 읽기 상태, 입력 패널의 조밀한 배치 | [conversation.png](docs/assets/latest/conversation.png) |
|
||||
| Mobile web onboarding | 빠른 진입과 한국어 중심의 간결한 가입 흐름 | [vstalk-web-onboarding.png](docs/assets/latest/vstalk-web-onboarding.png) |
|
||||
| Mobile web inbox | 최근 대화, 필터, 검색 진입의 기본 구조 | [vstalk-web-list.png](docs/assets/latest/vstalk-web-list.png) |
|
||||
| Mobile web search | 대화 재발견과 보관 흐름의 1차 구현 | [vstalk-web-search.png](docs/assets/latest/vstalk-web-search.png) |
|
||||
| Mobile web saved | 나중에 답장, 중요 대화, 다시 열기 허브 | [vstalk-web-saved.png](docs/assets/latest/vstalk-web-saved.png) |
|
||||
| Mobile web chat | 모바일 입력창, 상단 정보 밀도, 복귀 동선 | [vstalk-web-chat.png](docs/assets/latest/vstalk-web-chat.png) |
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/hero-shell.png" alt="Desktop shell" width="420" height="298"><br>
|
||||
<strong>Desktop shell</strong><br>
|
||||
<sub>레일 + 목록 + 대화 중심의 3단 구조</sub>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/onboarding.png" alt="Desktop onboarding" width="420" height="298"><br>
|
||||
<strong>Desktop onboarding</strong><br>
|
||||
<sub>첫 진입을 짧게 정리한 온보딩</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/conversation.png" alt="Desktop conversation" width="390" height="400"><br>
|
||||
<strong>Desktop conversation</strong><br>
|
||||
<sub>대화 흐름과 입력 패널 밀도</sub>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-list.png" alt="Mobile web inbox" width="220" height="513"><br>
|
||||
<strong>Mobile web inbox</strong><br>
|
||||
<sub>최근 대화와 필터 구조</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-onboarding.png" alt="Mobile web onboarding" width="220" height="476"><br>
|
||||
<strong>Mobile web onboarding</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-search.png" alt="Mobile web search" width="220" height="513"><br>
|
||||
<strong>Mobile web search</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-saved.png" alt="Mobile web saved" width="220" height="513"><br>
|
||||
<strong>Mobile web saved</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-chat.png" alt="Mobile web chat" width="220" height="513"><br>
|
||||
<strong>Mobile web chat</strong>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
전체 화면 묶음은 [SHOWCASE.md](SHOWCASE.md)에서 더 자세히 볼 수 있습니다.
|
||||
|
||||
|
|
|
|||
64
SHOWCASE.md
|
|
@ -25,11 +25,26 @@ KoTalk의 현재 공개 표면을 짧게 훑어보는 문서가 아니라, 지
|
|||
|
||||
### Desktop Screens
|
||||
|
||||
| Screen | Why it matters |
|
||||
|---|---|
|
||||
| [hero-shell.png](docs/assets/latest/hero-shell.png) | 현재 데스크톱 전체 셸의 구조와 밀도 |
|
||||
| [onboarding.png](docs/assets/latest/onboarding.png) | 첫 진입에서 어떤 정보를 먼저 보여주는지 |
|
||||
| [conversation.png](docs/assets/latest/conversation.png) | 실제 대화 화면의 읽기 흐름과 입력 밀도 |
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/hero-shell.png" alt="Desktop shell" width="520" height="369"><br>
|
||||
<strong>Desktop shell</strong><br>
|
||||
<sub>현재 데스크톱 전체 셸의 구조와 밀도</sub>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/onboarding.png" alt="Desktop onboarding" width="520" height="369"><br>
|
||||
<strong>Desktop onboarding</strong><br>
|
||||
<sub>첫 진입에서 먼저 보이는 정보</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/assets/latest/conversation.png" alt="Desktop conversation" width="430" height="441"><br>
|
||||
<strong>Desktop conversation</strong><br>
|
||||
<sub>실제 대화 화면의 읽기 흐름과 입력 밀도</sub>
|
||||
</p>
|
||||
|
||||
## Mobile Web Walkthrough
|
||||
|
||||
|
|
@ -44,13 +59,38 @@ KoTalk의 현재 공개 표면을 짧게 훑어보는 문서가 아니라, 지
|
|||
|
||||
### Mobile Web Screens
|
||||
|
||||
| Screen | Why it matters |
|
||||
|---|---|
|
||||
| [vstalk-web-onboarding.png](docs/assets/latest/vstalk-web-onboarding.png) | 초기 진입과 가입 흐름 |
|
||||
| [vstalk-web-list.png](docs/assets/latest/vstalk-web-list.png) | 현재 받은함 구조 |
|
||||
| [vstalk-web-search.png](docs/assets/latest/vstalk-web-search.png) | 검색과 재발견 흐름 |
|
||||
| [vstalk-web-saved.png](docs/assets/latest/vstalk-web-saved.png) | 보관과 후속조치 허브 |
|
||||
| [vstalk-web-chat.png](docs/assets/latest/vstalk-web-chat.png) | 모바일 대화 화면의 현재 밀도 |
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-onboarding.png" alt="Mobile onboarding" width="220" height="476"><br>
|
||||
<strong>Onboarding</strong><br>
|
||||
<sub>초기 진입과 가입 흐름</sub>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-list.png" alt="Mobile inbox" width="220" height="513"><br>
|
||||
<strong>Inbox</strong><br>
|
||||
<sub>현재 받은함 구조</sub>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-search.png" alt="Mobile search" width="220" height="513"><br>
|
||||
<strong>Search</strong><br>
|
||||
<sub>검색과 재발견 흐름</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-saved.png" alt="Mobile saved" width="220" height="513"><br>
|
||||
<strong>Saved</strong><br>
|
||||
<sub>보관과 후속조치 허브</sub>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/assets/latest/vstalk-web-chat.png" alt="Mobile chat" width="220" height="513"><br>
|
||||
<strong>Chat</strong><br>
|
||||
<sub>모바일 대화 화면의 현재 밀도</sub>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Build And Artifact Shelf
|
||||
|
||||
|
|
|
|||
91
branding/BRAND_GUIDE.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# KoTalk Brand Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This package turns the approved raster logo concept into a reusable production asset set for KoTalk.
|
||||
|
||||
- Reference intent: warm, calm, modern messenger mark
|
||||
- Primary use: app icon, favicon, PWA icon, Windows icon, docs, release pages
|
||||
- Master source: `branding/kotalk-logo-master.svg`
|
||||
|
||||
## File Inventory
|
||||
|
||||
### Master vectors
|
||||
|
||||
- `branding/kotalk-logo-master.svg`
|
||||
- `branding/kotalk-logo-master.pdf`
|
||||
- `branding/kotalk-logo-master.eps`
|
||||
|
||||
### PNG exports
|
||||
|
||||
- Transparent: `branding/png/kotalk-transparent-{1024|512|256|192|180|128|64|32|16}.png`
|
||||
- White background: `branding/png/kotalk-white-1024.png`
|
||||
- Mono black: `branding/png/kotalk-mono-black-1024.png`
|
||||
- Mono white: `branding/png/kotalk-mono-white-1024.png`
|
||||
- Inverse for dark surfaces: `branding/png/kotalk-inverse-1024.png`
|
||||
|
||||
### ICO exports
|
||||
|
||||
- Windows app icon: `branding/ico/kotalk.ico`
|
||||
- Favicon bundle: `branding/ico/favicon.ico`
|
||||
|
||||
### Applied runtime assets
|
||||
|
||||
- Web app icons: `src/PhysOn.Web/public/`
|
||||
- Desktop app icons: `src/PhysOn.Desktop/Assets/`
|
||||
|
||||
## Color System
|
||||
|
||||
### Core colors
|
||||
|
||||
- Ink: `#394350`
|
||||
- Warm accent: `#F05B2B`
|
||||
- Separator white: `#FFFFFF`
|
||||
|
||||
### Supporting backgrounds
|
||||
|
||||
- Paper: `#F7F3EE`
|
||||
- Night: `#141922`
|
||||
|
||||
### Recommended backgrounds
|
||||
|
||||
- White: `#FFFFFF`
|
||||
- Warm paper: `#F7F3EE`
|
||||
- Dark surface: `#141922`
|
||||
|
||||
## Safe Area
|
||||
|
||||
- Artboard: `1024 x 1024`
|
||||
- Recommended clear area from the artboard edge: `128px`
|
||||
- Do not scale the visible mark so large that any speech bubble or the center chevron approaches the outer 12% of the square
|
||||
|
||||
## Minimum Use Size
|
||||
|
||||
- Preferred minimum digital size: `24px`
|
||||
- Favicon minimum: `16px`
|
||||
- When rendering below `24px`, use the packaged ICO or PNG exports instead of re-rasterizing from screenshots
|
||||
|
||||
## Usage Rules
|
||||
|
||||
- Keep the mark square, centered, and unrotated
|
||||
- Use the transparent master for docs and UI surfaces when the background is already controlled
|
||||
- Use the white background exports for launcher and touch icons
|
||||
- Use the mono variants only where a single-color system is required
|
||||
|
||||
## Do Not
|
||||
|
||||
- Stretch or rotate the mark
|
||||
- Add shadows, glow, gradients, glass, or texture
|
||||
- Change the orange or dark brand colors arbitrarily
|
||||
- Add pattern backgrounds behind the mark
|
||||
- Recreate the logo from screenshots when the packaged vectors are available
|
||||
|
||||
## Regeneration
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python scripts/branding/generate_kotalk_brand_assets.py
|
||||
```
|
||||
|
||||
This regenerates the committed vector, PNG, ICO, and app-facing icon assets from the scripted master geometry.
|
||||
BIN
branding/ico/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
branding/ico/kotalk.ico
Normal file
|
After Width: | Height: | Size: 12 KiB |
54
branding/kotalk-logo-master.eps
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 0 0 1024 1024
|
||||
%%HiResBoundingBox: 0 0 1024 1024
|
||||
%%LanguageLevel: 2
|
||||
%%Pages: 1
|
||||
%%EndComments
|
||||
/roundrect {
|
||||
/r exch def
|
||||
/y2 exch def
|
||||
/x2 exch def
|
||||
/y exch def
|
||||
/x exch def
|
||||
newpath
|
||||
x r add y moveto
|
||||
x2 r sub y lineto
|
||||
x2 r sub y r add r 270 360 arc
|
||||
x2 y2 r sub lineto
|
||||
x2 r sub y2 r sub r 0 90 arc
|
||||
x r add y2 lineto
|
||||
x r add y2 r sub r 90 180 arc
|
||||
x y r add lineto
|
||||
x r add y r add r 180 270 arc
|
||||
closepath
|
||||
} def
|
||||
gsave
|
||||
0 1024 translate
|
||||
1 -1 scale
|
||||
0.223529 0.262745 0.313725 setrgbcolor
|
||||
218.00 312.00 584.00 602.00 22.00 roundrect fill
|
||||
newpath
|
||||
304.00 602.00 moveto
|
||||
304.00 736.00 lineto
|
||||
438.00 602.00 lineto
|
||||
closepath fill
|
||||
0.941176 0.356863 0.168627 setrgbcolor
|
||||
446.00 312.00 812.00 602.00 22.00 roundrect fill
|
||||
newpath
|
||||
668.00 602.00 moveto
|
||||
742.00 602.00 lineto
|
||||
742.00 694.00 lineto
|
||||
694.00 650.00 lineto
|
||||
closepath fill
|
||||
1.000000 1.000000 1.000000 setrgbcolor
|
||||
newpath
|
||||
490.00 328.00 moveto
|
||||
582.00 328.00 lineto
|
||||
446.00 457.00 lineto
|
||||
582.00 586.00 lineto
|
||||
490.00 586.00 lineto
|
||||
338.00 457.00 lineto
|
||||
closepath fill
|
||||
grestore
|
||||
showpage
|
||||
%%EOF
|
||||
73
branding/kotalk-logo-master.pdf
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
%PDF-1.7
|
||||
%Çì<C387>¢
|
||||
%%Invocation: gs -dBATCH -dNOPAUSE -dSAFER -sDEVICE=pdfwrite -sOutputFile=? ?
|
||||
5 0 obj
|
||||
<</Length 6 0 R/Filter /FlateDecode>>
|
||||
stream
|
||||
xœe’KŽÄ D÷œ‚DÆcŽ1gˆ”Þ$‹™û/šž(B
|
||||
dWÊ%~3l%ƒ®Ø÷+Á†X¹Öy‡Œ<Ú„ZjÇ’ÿ^ ÷‚<C3B7>¯ÔƒÏ;w*[óSš÷€zaÌc
|
||||
ìɘˆ¬þÁµˆÖ»¡ê¨¾ÑîŒÏ;c—O=Y:Ϊ?{•ÍÃùäð:æÿ;T<C5BD>âo—3Šh7UY.Ž™à BÀ\ãQIãeé` ËJ°X©ýgq#vý„3ãHÐ8R{²O:æÌô#Aó~oÜÚJ<C39A>ˆ—޳'h©=8|†ŽùÿΫ –¬KcÐ.lI08dw6ŠGlö<6C>«nQs¤ŸôÏÆˆmendstream
|
||||
endobj
|
||||
6 0 obj
|
||||
260
|
||||
endobj
|
||||
4 0 obj
|
||||
<</Type/Page/MediaBox [0 0 595 842]
|
||||
/Parent 3 0 R
|
||||
/Resources<</ProcSet[/PDF]
|
||||
>>
|
||||
/Contents 5 0 R
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<< /Type /Pages /Kids [
|
||||
4 0 R
|
||||
] /Count 1
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<</Type /Catalog /Pages 3 0 R
|
||||
/Metadata 7 0 R
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<</Type/Metadata
|
||||
/Subtype/XML/Length 1183>>stream
|
||||
<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
|
||||
<?adobe-xap-filters esc="CRLF"?>
|
||||
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='XMP toolkit 2.9.1-13, framework 1.6'>
|
||||
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:iX='http://ns.adobe.com/iX/1.0/'>
|
||||
<rdf:Description rdf:about="" xmlns:pdf='http://ns.adobe.com/pdf/1.3/' pdf:Producer='GPL Ghostscript 10.02.1'/>
|
||||
<rdf:Description rdf:about="" xmlns:xmp='http://ns.adobe.com/xap/1.0/'><xmp:ModifyDate>2026-04-16T11:47:43+09:00</xmp:ModifyDate>
|
||||
<xmp:CreateDate>2026-04-16T11:47:43+09:00</xmp:CreateDate>
|
||||
<xmp:CreatorTool>UnknownApplication</xmp:CreatorTool></rdf:Description>
|
||||
<rdf:Description rdf:about="" xmlns:xapMM='http://ns.adobe.com/xap/1.0/mm/' xapMM:DocumentID='uuid:310abc84-715b-11fc-0000-9524caef6f27'/>
|
||||
<rdf:Description rdf:about="" xmlns:dc='http://purl.org/dc/elements/1.1/' dc:format='application/pdf'><dc:title><rdf:Alt><rdf:li xml:lang='x-default'>Untitled</rdf:li></rdf:Alt></dc:title></rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
|
||||
|
||||
<?xpacket end='w'?>
|
||||
endstream
|
||||
endobj
|
||||
2 0 obj
|
||||
<</Producer(GPL Ghostscript 10.02.1)
|
||||
/CreationDate(D:20260416114743+09'00')
|
||||
/ModDate(D:20260416114743+09'00')>>endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000615 00000 n
|
||||
0000001938 00000 n
|
||||
0000000556 00000 n
|
||||
0000000442 00000 n
|
||||
0000000093 00000 n
|
||||
0000000423 00000 n
|
||||
0000000679 00000 n
|
||||
trailer
|
||||
<< /Size 8 /Root 1 0 R /Info 2 0 R
|
||||
/ID [<C1EC8B35441ABCA0F74E37FC93F2BE37><C1EC8B35441ABCA0F74E37FC93F2BE37>]
|
||||
>>
|
||||
startxref
|
||||
2064
|
||||
%%EOF
|
||||
7
branding/kotalk-logo-master.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="none">
|
||||
<path d="M 240.00 312.00 H 780.00 A 22.00 22.00 0 0 1 802.00 334.00 V 892.00 A 22.00 22.00 0 0 1 780.00 914.00 H 240.00 A 22.00 22.00 0 0 1 218.00 892.00 V 334.00 A 22.00 22.00 0 0 1 240.00 312.00 Z" fill="#394350" />
|
||||
<path d="M 304.00 602.00 L 304.00 736.00 L 438.00 602.00 Z" fill="#394350" />
|
||||
<path d="M 468.00 312.00 H 1236.00 A 22.00 22.00 0 0 1 1258.00 334.00 V 892.00 A 22.00 22.00 0 0 1 1236.00 914.00 H 468.00 A 22.00 22.00 0 0 1 446.00 892.00 V 334.00 A 22.00 22.00 0 0 1 468.00 312.00 Z" fill="#F05B2B" />
|
||||
<path d="M 668.00 602.00 L 742.00 602.00 L 742.00 694.00 L 694.00 650.00 Z" fill="#F05B2B" />
|
||||
<path d="M 490.00 328.00 L 582.00 328.00 L 446.00 457.00 L 582.00 586.00 L 490.00 586.00 L 338.00 457.00 Z" fill="#FFFFFF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 831 B |
BIN
branding/png/kotalk-inverse-1024.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
branding/png/kotalk-mono-black-1024.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
branding/png/kotalk-mono-white-1024.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
branding/png/kotalk-transparent-1024.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
branding/png/kotalk-transparent-128.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
branding/png/kotalk-transparent-16.png
Normal file
|
After Width: | Height: | Size: 492 B |
BIN
branding/png/kotalk-transparent-180.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
branding/png/kotalk-transparent-192.png
Normal file
|
After Width: | Height: | Size: 4 KiB |
BIN
branding/png/kotalk-transparent-256.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
branding/png/kotalk-transparent-32.png
Normal file
|
After Width: | Height: | Size: 922 B |
BIN
branding/png/kotalk-transparent-512.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
branding/png/kotalk-transparent-64.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
branding/png/kotalk-white-1024.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
branding/reference/kotalk-logo-reference.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
|
|
@ -8,6 +8,8 @@
|
|||
- 새 릴리즈나 큰 UI 변경이 있으면 이 폴더의 스크린샷도 함께 갱신합니다.
|
||||
- 릴리즈 번들용 스크린샷과 별개로, 저장소 안의 최신 기준 화면을 유지합니다.
|
||||
- 모바일 웹 스크린샷은 `scripts/ci/capture-vstalk-web-screenshots.cjs`로 다시 생성할 수 있습니다.
|
||||
- 캡처는 불필요한 바깥 여백 없이 앱 창 또는 앱 셸 자체만 정확히 담아야 합니다.
|
||||
- README, SHOWCASE, 릴리즈 페이지에 게시할 때는 실제 이미지 종횡비를 유지하는 `width/height` 기준으로 사용합니다.
|
||||
- 현재 포함:
|
||||
- Windows 데스크톱 셸
|
||||
- Windows 온보딩/대화 화면
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 56 KiB |
|
|
@ -1,4 +1,4 @@
|
|||
# vs-messanger {{VERSION}}
|
||||
# KoTalk {{VERSION}}
|
||||
|
||||
- 채널: `{{CHANNEL}}`
|
||||
- 게시 시각: `{{PUBLISHED_AT}}`
|
||||
|
|
|
|||
353
scripts/branding/generate_kotalk_brand_assets.py
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
BRANDING_DIR = ROOT / "branding"
|
||||
REFERENCE_DIR = BRANDING_DIR / "reference"
|
||||
PNG_DIR = BRANDING_DIR / "png"
|
||||
ICO_DIR = BRANDING_DIR / "ico"
|
||||
WEB_PUBLIC_DIR = ROOT / "src" / "PhysOn.Web" / "public"
|
||||
DESKTOP_ASSETS_DIR = ROOT / "src" / "PhysOn.Desktop" / "Assets"
|
||||
|
||||
ARTBOARD = 1024
|
||||
DARK = "#394350"
|
||||
WARM = "#F05B2B"
|
||||
WHITE = "#FFFFFF"
|
||||
PAPER = "#F7F3EE"
|
||||
NIGHT = "#141922"
|
||||
BLACK = "#111111"
|
||||
|
||||
LEFT_RECT = (218, 312, 584, 602, 22)
|
||||
LEFT_TAIL = [(304, 602), (304, 736), (438, 602)]
|
||||
RIGHT_RECT = (446, 312, 812, 602, 22)
|
||||
RIGHT_TAIL = [(668, 602), (742, 602), (742, 694), (694, 650)]
|
||||
CHEVRON = [(490, 328), (582, 328), (446, 457), (582, 586), (490, 586), (338, 457)]
|
||||
|
||||
|
||||
def ensure_dirs() -> None:
|
||||
for path in (BRANDING_DIR, REFERENCE_DIR, PNG_DIR, ICO_DIR, WEB_PUBLIC_DIR, DESKTOP_ASSETS_DIR):
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def hex_to_rgba(hex_value: str, alpha: int = 255) -> tuple[int, int, int, int]:
|
||||
hex_value = hex_value.lstrip("#")
|
||||
return tuple(int(hex_value[index : index + 2], 16) for index in (0, 2, 4)) + (alpha,)
|
||||
|
||||
|
||||
def rounded_rect_path(x: float, y: float, width: float, height: float, radius: float) -> str:
|
||||
right = x + width
|
||||
bottom = y + height
|
||||
return (
|
||||
f"M {x + radius:.2f} {y:.2f} "
|
||||
f"H {right - radius:.2f} "
|
||||
f"A {radius:.2f} {radius:.2f} 0 0 1 {right:.2f} {y + radius:.2f} "
|
||||
f"V {bottom - radius:.2f} "
|
||||
f"A {radius:.2f} {radius:.2f} 0 0 1 {right - radius:.2f} {bottom:.2f} "
|
||||
f"H {x + radius:.2f} "
|
||||
f"A {radius:.2f} {radius:.2f} 0 0 1 {x:.2f} {bottom - radius:.2f} "
|
||||
f"V {y + radius:.2f} "
|
||||
f"A {radius:.2f} {radius:.2f} 0 0 1 {x + radius:.2f} {y:.2f} Z"
|
||||
)
|
||||
|
||||
|
||||
def polygon_path(points: list[tuple[float, float]]) -> str:
|
||||
start_x, start_y = points[0]
|
||||
segments = [f"M {start_x:.2f} {start_y:.2f}"]
|
||||
for x, y in points[1:]:
|
||||
segments.append(f"L {x:.2f} {y:.2f}")
|
||||
segments.append("Z")
|
||||
return " ".join(segments)
|
||||
|
||||
|
||||
def svg_document(
|
||||
*,
|
||||
background: str | None,
|
||||
left_fill: str,
|
||||
right_fill: str,
|
||||
chevron_fill: str,
|
||||
) -> str:
|
||||
background_markup = (
|
||||
f'<path d="{rounded_rect_path(0, 0, ARTBOARD, ARTBOARD, 0)}" fill="{background}" />\n '
|
||||
if background
|
||||
else ""
|
||||
)
|
||||
return f"""<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {ARTBOARD} {ARTBOARD}" fill="none">
|
||||
{background_markup}<path d="{rounded_rect_path(*LEFT_RECT)}" fill="{left_fill}" />
|
||||
<path d="{polygon_path(LEFT_TAIL)}" fill="{left_fill}" />
|
||||
<path d="{rounded_rect_path(*RIGHT_RECT)}" fill="{right_fill}" />
|
||||
<path d="{polygon_path(RIGHT_TAIL)}" fill="{right_fill}" />
|
||||
<path d="{polygon_path(CHEVRON)}" fill="{chevron_fill}" />
|
||||
</svg>
|
||||
"""
|
||||
|
||||
|
||||
def ps_color(hex_value: str) -> str:
|
||||
r, g, b, _ = hex_to_rgba(hex_value)
|
||||
return f"{r / 255:.6f} {g / 255:.6f} {b / 255:.6f} setrgbcolor"
|
||||
|
||||
|
||||
def ps_polygon(points: list[tuple[float, float]]) -> str:
|
||||
lines = ["newpath"]
|
||||
start_x, start_y = points[0]
|
||||
lines.append(f"{start_x:.2f} {start_y:.2f} moveto")
|
||||
for x, y in points[1:]:
|
||||
lines.append(f"{x:.2f} {y:.2f} lineto")
|
||||
lines.append("closepath fill")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def eps_document() -> str:
|
||||
x1, y1, x2, y2, r = LEFT_RECT
|
||||
x1b, y1b, x2b, y2b, rb = RIGHT_RECT
|
||||
return f"""%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 0 0 {ARTBOARD} {ARTBOARD}
|
||||
%%HiResBoundingBox: 0 0 {ARTBOARD} {ARTBOARD}
|
||||
%%LanguageLevel: 2
|
||||
%%Pages: 1
|
||||
%%EndComments
|
||||
/roundrect {{
|
||||
/r exch def
|
||||
/y2 exch def
|
||||
/x2 exch def
|
||||
/y exch def
|
||||
/x exch def
|
||||
newpath
|
||||
x r add y moveto
|
||||
x2 r sub y lineto
|
||||
x2 r sub y r add r 270 360 arc
|
||||
x2 y2 r sub lineto
|
||||
x2 r sub y2 r sub r 0 90 arc
|
||||
x r add y2 lineto
|
||||
x r add y2 r sub r 90 180 arc
|
||||
x y r add lineto
|
||||
x r add y r add r 180 270 arc
|
||||
closepath
|
||||
}} def
|
||||
gsave
|
||||
0 {ARTBOARD} translate
|
||||
1 -1 scale
|
||||
{ps_color(DARK)}
|
||||
{x1:.2f} {y1:.2f} {x2:.2f} {y2:.2f} {r:.2f} roundrect fill
|
||||
{ps_polygon(LEFT_TAIL)}
|
||||
{ps_color(WARM)}
|
||||
{x1b:.2f} {y1b:.2f} {x2b:.2f} {y2b:.2f} {rb:.2f} roundrect fill
|
||||
{ps_polygon(RIGHT_TAIL)}
|
||||
{ps_color(WHITE)}
|
||||
{ps_polygon(CHEVRON)}
|
||||
grestore
|
||||
showpage
|
||||
%%EOF
|
||||
"""
|
||||
|
||||
|
||||
def draw_variant(
|
||||
size: int,
|
||||
*,
|
||||
background: str | None,
|
||||
left_fill: str,
|
||||
right_fill: str,
|
||||
chevron_fill: str,
|
||||
supersample: int = 4,
|
||||
) -> Image.Image:
|
||||
render_size = size * supersample
|
||||
scale = render_size / ARTBOARD
|
||||
image = Image.new("RGBA", (render_size, render_size), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
if background:
|
||||
draw.rectangle((0, 0, render_size, render_size), fill=hex_to_rgba(background))
|
||||
|
||||
left = [value * scale for value in LEFT_RECT[:4]]
|
||||
right = [value * scale for value in RIGHT_RECT[:4]]
|
||||
radius = LEFT_RECT[4] * scale
|
||||
right_radius = RIGHT_RECT[4] * scale
|
||||
|
||||
draw.rounded_rectangle(left, radius=radius, fill=hex_to_rgba(left_fill))
|
||||
draw.polygon([(x * scale, y * scale) for x, y in LEFT_TAIL], fill=hex_to_rgba(left_fill))
|
||||
|
||||
draw.rounded_rectangle(right, radius=right_radius, fill=hex_to_rgba(right_fill))
|
||||
draw.polygon([(x * scale, y * scale) for x, y in RIGHT_TAIL], fill=hex_to_rgba(right_fill))
|
||||
|
||||
draw.polygon([(x * scale, y * scale) for x, y in CHEVRON], fill=hex_to_rgba(chevron_fill))
|
||||
|
||||
if supersample == 1:
|
||||
return image
|
||||
|
||||
return image.resize((size, size), Image.Resampling.LANCZOS)
|
||||
|
||||
|
||||
def write_text_assets() -> None:
|
||||
(BRANDING_DIR / "kotalk-logo-master.svg").write_text(
|
||||
svg_document(background=None, left_fill=DARK, right_fill=WARM, chevron_fill=WHITE),
|
||||
encoding="utf-8",
|
||||
)
|
||||
(BRANDING_DIR / "kotalk-logo-master.eps").write_text(eps_document(), encoding="utf-8")
|
||||
|
||||
subprocess.run(
|
||||
[
|
||||
"gs",
|
||||
"-dBATCH",
|
||||
"-dNOPAUSE",
|
||||
"-dSAFER",
|
||||
"-sDEVICE=pdfwrite",
|
||||
f"-sOutputFile={BRANDING_DIR / 'kotalk-logo-master.pdf'}",
|
||||
str(BRANDING_DIR / "kotalk-logo-master.eps"),
|
||||
],
|
||||
check=True,
|
||||
cwd=ROOT,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
transparent_svg = svg_document(background=None, left_fill=DARK, right_fill=WARM, chevron_fill=WHITE)
|
||||
mono_svg = svg_document(background=None, left_fill=BLACK, right_fill=BLACK, chevron_fill=BLACK)
|
||||
inverse_svg = svg_document(background=NIGHT, left_fill=PAPER, right_fill=WARM, chevron_fill=NIGHT)
|
||||
|
||||
(WEB_PUBLIC_DIR / "icon.svg").write_text(transparent_svg, encoding="utf-8")
|
||||
(WEB_PUBLIC_DIR / "vs-mark.svg").write_text(transparent_svg, encoding="utf-8")
|
||||
(WEB_PUBLIC_DIR / "mask-icon.svg").write_text(inverse_svg, encoding="utf-8")
|
||||
(WEB_PUBLIC_DIR / "apple-touch-icon.svg").write_text(transparent_svg, encoding="utf-8")
|
||||
|
||||
|
||||
def write_png_assets() -> None:
|
||||
transparent_sizes = [1024, 512, 256, 192, 180, 128, 64, 32, 16]
|
||||
for size in transparent_sizes:
|
||||
transparent = draw_variant(
|
||||
size,
|
||||
background=None,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
)
|
||||
transparent.save(PNG_DIR / f"kotalk-transparent-{size}.png")
|
||||
|
||||
draw_variant(
|
||||
1024,
|
||||
background=WHITE,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
).save(PNG_DIR / "kotalk-white-1024.png")
|
||||
draw_variant(
|
||||
1024,
|
||||
background=None,
|
||||
left_fill=BLACK,
|
||||
right_fill=BLACK,
|
||||
chevron_fill=BLACK,
|
||||
).save(PNG_DIR / "kotalk-mono-black-1024.png")
|
||||
draw_variant(
|
||||
1024,
|
||||
background=None,
|
||||
left_fill=WHITE,
|
||||
right_fill=WHITE,
|
||||
chevron_fill=WHITE,
|
||||
).save(PNG_DIR / "kotalk-mono-white-1024.png")
|
||||
draw_variant(
|
||||
1024,
|
||||
background=NIGHT,
|
||||
left_fill=PAPER,
|
||||
right_fill=WARM,
|
||||
chevron_fill=NIGHT,
|
||||
).save(PNG_DIR / "kotalk-inverse-1024.png")
|
||||
|
||||
draw_variant(
|
||||
512,
|
||||
background=WHITE,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
).save(WEB_PUBLIC_DIR / "icon-512.png")
|
||||
draw_variant(
|
||||
192,
|
||||
background=WHITE,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
).save(WEB_PUBLIC_DIR / "icon-192.png")
|
||||
draw_variant(
|
||||
180,
|
||||
background=WHITE,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
).save(WEB_PUBLIC_DIR / "apple-touch-icon.png")
|
||||
draw_variant(
|
||||
32,
|
||||
background=None,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
).save(WEB_PUBLIC_DIR / "favicon-32x32.png")
|
||||
draw_variant(
|
||||
16,
|
||||
background=None,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
).save(WEB_PUBLIC_DIR / "favicon-16x16.png")
|
||||
draw_variant(
|
||||
128,
|
||||
background=None,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
).save(DESKTOP_ASSETS_DIR / "kotalk-mark-128.png")
|
||||
|
||||
|
||||
def write_ico_assets() -> None:
|
||||
desktop_icon = draw_variant(
|
||||
256,
|
||||
background=None,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
)
|
||||
desktop_icon.save(
|
||||
ICO_DIR / "kotalk.ico",
|
||||
format="ICO",
|
||||
sizes=[(256, 256), (128, 128), (64, 64), (48, 48), (32, 32), (16, 16)],
|
||||
)
|
||||
desktop_icon.save(
|
||||
DESKTOP_ASSETS_DIR / "kotalk.ico",
|
||||
format="ICO",
|
||||
sizes=[(256, 256), (128, 128), (64, 64), (48, 48), (32, 32), (16, 16)],
|
||||
)
|
||||
|
||||
favicon_icon = draw_variant(
|
||||
64,
|
||||
background=None,
|
||||
left_fill=DARK,
|
||||
right_fill=WARM,
|
||||
chevron_fill=WHITE,
|
||||
supersample=6,
|
||||
)
|
||||
favicon_icon.save(
|
||||
ICO_DIR / "favicon.ico",
|
||||
format="ICO",
|
||||
sizes=[(64, 64), (32, 32), (16, 16)],
|
||||
)
|
||||
favicon_icon.save(
|
||||
WEB_PUBLIC_DIR / "favicon.ico",
|
||||
format="ICO",
|
||||
sizes=[(64, 64), (32, 32), (16, 16)],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ensure_dirs()
|
||||
write_text_assets()
|
||||
write_png_assets()
|
||||
write_ico_assets()
|
||||
print("Generated KoTalk brand assets in branding/, src/PhysOn.Web/public/, and src/PhysOn.Desktop/Assets/.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -149,12 +149,8 @@ PY
|
|||
capture_window() {
|
||||
local window_id="$1"
|
||||
local target_path="$2"
|
||||
local root_capture="${target_path%.*}-root.${target_path##*.}"
|
||||
local geometry
|
||||
read -r crop_x crop_y crop_w crop_h < <(wait_for_geometry "$window_id")
|
||||
import -window root "$root_capture"
|
||||
convert "$root_capture" -crop "${crop_w}x${crop_h}+${crop_x}+${crop_y}" +repage "$target_path"
|
||||
rm -f "$root_capture"
|
||||
wait_for_geometry "$window_id" >/dev/null
|
||||
import -window "$window_id" "$target_path"
|
||||
}
|
||||
|
||||
create_conversation_fallback() {
|
||||
|
|
|
|||
|
|
@ -315,9 +315,9 @@ async function captureOnboarding(browser) {
|
|||
window.localStorage.clear()
|
||||
})
|
||||
await page.reload({ waitUntil: 'networkidle2' })
|
||||
await page.screenshot({
|
||||
const app = await page.waitForSelector('.onboarding')
|
||||
await app.screenshot({
|
||||
path: path.join(outputDir, 'vstalk-web-onboarding.png'),
|
||||
fullPage: false,
|
||||
})
|
||||
await page.close()
|
||||
}
|
||||
|
|
@ -327,9 +327,9 @@ async function captureConversationList(browser) {
|
|||
await installSessionMocks(page)
|
||||
await page.goto(baseUrl, { waitUntil: 'networkidle2' })
|
||||
await page.waitForSelector('.conversation-row')
|
||||
await page.screenshot({
|
||||
const app = await page.waitForSelector('.shell')
|
||||
await app.screenshot({
|
||||
path: path.join(outputDir, 'vstalk-web-list.png'),
|
||||
fullPage: false,
|
||||
})
|
||||
await page.close()
|
||||
}
|
||||
|
|
@ -341,9 +341,9 @@ async function captureConversation(browser) {
|
|||
await page.waitForSelector('.conversation-row')
|
||||
await page.click('.conversation-row')
|
||||
await page.waitForSelector('.message-bubble')
|
||||
await page.screenshot({
|
||||
const app = await page.waitForSelector('.shell')
|
||||
await app.screenshot({
|
||||
path: path.join(outputDir, 'vstalk-web-chat.png'),
|
||||
fullPage: false,
|
||||
})
|
||||
await page.close()
|
||||
}
|
||||
|
|
@ -355,9 +355,9 @@ async function captureSearch(browser) {
|
|||
await page.waitForSelector('.bottom-bar')
|
||||
await page.click('.bottom-bar .nav-button:nth-child(2)')
|
||||
await page.waitForSelector('.search-field')
|
||||
await page.screenshot({
|
||||
const app = await page.waitForSelector('.shell')
|
||||
await app.screenshot({
|
||||
path: path.join(outputDir, 'vstalk-web-search.png'),
|
||||
fullPage: false,
|
||||
})
|
||||
await page.close()
|
||||
}
|
||||
|
|
@ -369,9 +369,9 @@ async function captureSaved(browser) {
|
|||
await page.waitForSelector('.bottom-bar')
|
||||
await page.click('.bottom-bar .nav-button:nth-child(3)')
|
||||
await page.waitForSelector('.saved-section')
|
||||
await page.screenshot({
|
||||
const app = await page.waitForSelector('.shell')
|
||||
await app.screenshot({
|
||||
path: path.join(outputDir, 'vstalk-web-saved.png'),
|
||||
fullPage: false,
|
||||
})
|
||||
await page.close()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@ write_platform_version_json() {
|
|||
local body="$2"
|
||||
cat > "$path" <<EOF
|
||||
{
|
||||
"productName": "KoTalk",
|
||||
"publisher": "PHYSIA",
|
||||
"version": "$version",
|
||||
"channel": "$channel",
|
||||
"publishedAt": "$published_at",
|
||||
|
|
@ -202,6 +204,7 @@ if [[ -n "$windows_zip" ]]; then
|
|||
latest_hash_paths+=("windows/$windows_latest_name")
|
||||
|
||||
windows_platform_body="$(cat <<EOF
|
||||
"name": "KoTalk for Windows",
|
||||
"kind": "desktop",
|
||||
"arch": "x64",
|
||||
"latestUrl": "$download_base_url/windows/latest",
|
||||
|
|
@ -252,9 +255,10 @@ if [[ -n "$android_apk" ]]; then
|
|||
latest_hash_paths+=("android/$android_latest_name")
|
||||
|
||||
android_platform_body="$(cat <<EOF
|
||||
"name": "KoTalk for Android",
|
||||
"kind": "mobile",
|
||||
"arch": "universal",
|
||||
"packageName": "kr.physia.vsmessenger",
|
||||
"packageName": "kr.physia.kotalk",
|
||||
"minSdk": 26,
|
||||
"latestUrl": "$download_base_url/android/latest",
|
||||
"apkUrl": "$download_base_url/android/latest/$android_latest_name",
|
||||
|
|
@ -308,6 +312,8 @@ fi
|
|||
|
||||
cat > "$release_root/version.json" <<EOF
|
||||
{
|
||||
"productName": "KoTalk",
|
||||
"publisher": "PHYSIA",
|
||||
"version": "$version",
|
||||
"channel": "$channel",
|
||||
"publishedAt": "$published_at",
|
||||
|
|
|
|||
BIN
src/PhysOn.Desktop/Assets/kotalk-mark-128.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
src/PhysOn.Desktop/Assets/kotalk.ico
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -4,7 +4,18 @@
|
|||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AssemblyName>KoTalk</AssemblyName>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<ApplicationIcon>Assets\kotalk.ico</ApplicationIcon>
|
||||
<Company>PHYSIA</Company>
|
||||
<Authors>PHYSIA</Authors>
|
||||
<Product>KoTalk</Product>
|
||||
<Description>한국어 중심의 차분한 메시징 경험을 다시 설계하는 Windows-first 메신저</Description>
|
||||
<AssemblyTitle>KoTalk</AssemblyTitle>
|
||||
<AssemblyVersion>0.1.0.5</AssemblyVersion>
|
||||
<FileVersion>0.1.0.5</FileVersion>
|
||||
<Version>0.1.0-alpha.5</Version>
|
||||
<InformationalVersion>0.1.0-alpha.5</InformationalVersion>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ public partial class MainWindowViewModel : ViewModelBase, IAsyncDisposable
|
|||
$"desktop-{Environment.MachineName.ToLowerInvariant()}",
|
||||
"windows",
|
||||
Environment.MachineName,
|
||||
"0.1.0-alpha.4"));
|
||||
"0.1.0-alpha.5"));
|
||||
|
||||
var response = await _apiClient.RegisterAlphaQuickAsync(apiBaseUrl, request, CancellationToken.None);
|
||||
ApiBaseUrl = apiBaseUrl;
|
||||
|
|
|
|||
|
|
@ -7,55 +7,55 @@
|
|||
Height="748"
|
||||
MinWidth="340"
|
||||
MinHeight="520"
|
||||
Background="#F3F4F6"
|
||||
Background="#F7F3EE"
|
||||
Title="{Binding ConversationTitle}">
|
||||
|
||||
<Window.Styles>
|
||||
<Style Selector="Border.surface">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB" />
|
||||
<Setter Property="BorderBrush" Value="#E8DDD2" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="Border.muted">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="BorderBrush" Value="#E8EAEE" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="BorderBrush" Value="#ECE1D6" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="Border.bubble">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="9,7" />
|
||||
<Setter Property="Margin" Value="0,0,0,6" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="BorderBrush" Value="#E4E7EB" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="BorderBrush" Value="#E6D8CC" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
</Style>
|
||||
<Style Selector="Border.bubble.mine">
|
||||
<Setter Property="Background" Value="#EEF1F4" />
|
||||
<Setter Property="Background" Value="#F0E5D8" />
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
</Style>
|
||||
<Style Selector="Button.icon">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="8,6" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="BorderBrush" Value="#D9DDE2" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="BorderBrush" Value="#DCCFC4" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="Button.primary">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="11,8" />
|
||||
<Setter Property="Background" Value="#111418" />
|
||||
<Setter Property="Background" Value="#394350" />
|
||||
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.caption">
|
||||
<Setter Property="FontSize" Value="11.5" />
|
||||
<Setter Property="Foreground" Value="#69727D" />
|
||||
<Setter Property="Foreground" Value="#82766D" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.body">
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="Foreground" Value="#111418" />
|
||||
<Setter Property="Foreground" Value="#20242B" />
|
||||
</Style>
|
||||
</Window.Styles>
|
||||
|
||||
|
|
@ -67,14 +67,14 @@
|
|||
VerticalAlignment="Center"
|
||||
Text="{Binding ConversationGlyph}"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#111418" />
|
||||
Foreground="#20242B" />
|
||||
</Border>
|
||||
|
||||
<StackPanel Grid.Column="1" Spacing="2">
|
||||
<TextBlock Text="{Binding ConversationTitle}"
|
||||
FontSize="14.5"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#111418"
|
||||
Foreground="#20242B"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<TextBlock Text="{Binding ConversationSubtitle}"
|
||||
Classes="caption"
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
Padding="9"
|
||||
IsVisible="{Binding HasErrorText}">
|
||||
<TextBlock Text="{Binding ErrorText}"
|
||||
Foreground="#C62828"
|
||||
Foreground="#C9573C"
|
||||
Classes="caption"
|
||||
TextWrapping="Wrap" />
|
||||
</Border>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
Height="900"
|
||||
MinWidth="980"
|
||||
MinHeight="640"
|
||||
Background="#F3F4F6">
|
||||
Background="#F7F3EE">
|
||||
|
||||
<Design.DataContext>
|
||||
<vm:MainWindowViewModel />
|
||||
|
|
@ -24,112 +24,112 @@
|
|||
<Style Selector="Border.surface">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB" />
|
||||
<Setter Property="BorderBrush" Value="#E8DDD2" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="Border.surface-muted">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="BorderBrush" Value="#E8EAEE" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="BorderBrush" Value="#ECE1D6" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="Border.rail-surface">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB" />
|
||||
<Setter Property="BorderBrush" Value="#E8DDD2" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="Border.row-card">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#ECEFF3" />
|
||||
<Setter Property="BorderBrush" Value="#ECE2D8" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="Border.row-card.active">
|
||||
<Setter Property="Background" Value="#F3F5F7" />
|
||||
<Setter Property="BorderBrush" Value="#D7DCE3" />
|
||||
<Setter Property="Background" Value="#F4ECE3" />
|
||||
<Setter Property="BorderBrush" Value="#DCCABA" />
|
||||
</Style>
|
||||
<Style Selector="Border.inline-alert">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#D14B3F" />
|
||||
<Setter Property="BorderBrush" Value="#C9573C" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="Padding" Value="10,8" />
|
||||
</Style>
|
||||
<Style Selector="Border.status-chip">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="BorderBrush" Value="#E4E7EB" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="BorderBrush" Value="#E6D8CC" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="Padding" Value="8,3" />
|
||||
</Style>
|
||||
<Style Selector="Border.unread-badge">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#111418" />
|
||||
<Setter Property="Background" Value="#394350" />
|
||||
<Setter Property="Padding" Value="6,1" />
|
||||
</Style>
|
||||
<Style Selector="Border.message-bubble">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="BorderBrush" Value="#E4E7EB" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="BorderBrush" Value="#E6D8CC" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="MaxWidth" Value="560" />
|
||||
<Setter Property="Margin" Value="0,0,0,6" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
</Style>
|
||||
<Style Selector="Border.message-bubble.mine">
|
||||
<Setter Property="Background" Value="#EEF1F4" />
|
||||
<Setter Property="Background" Value="#F0E5D8" />
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
</Style>
|
||||
<Style Selector="Border.message-bubble.pending">
|
||||
<Setter Property="Opacity" Value="0.72" />
|
||||
</Style>
|
||||
<Style Selector="Border.message-bubble.failed">
|
||||
<Setter Property="BorderBrush" Value="#C9392C" />
|
||||
<Setter Property="BorderBrush" Value="#C9573C" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.display-title">
|
||||
<Setter Property="FontSize" Value="30" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="#111418" />
|
||||
<Setter Property="Foreground" Value="#20242B" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.section-title">
|
||||
<Setter Property="FontSize" Value="15" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="#111418" />
|
||||
<Setter Property="Foreground" Value="#20242B" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.body">
|
||||
<Setter Property="FontSize" Value="12.5" />
|
||||
<Setter Property="Foreground" Value="#1D232B" />
|
||||
<Setter Property="Foreground" Value="#2E3640" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.caption">
|
||||
<Setter Property="FontSize" Value="11.5" />
|
||||
<Setter Property="Foreground" Value="#69727D" />
|
||||
<Setter Property="Foreground" Value="#82766D" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.eyebrow">
|
||||
<Setter Property="FontSize" Value="10.5" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="#69727D" />
|
||||
<Setter Property="Foreground" Value="#8B7B6C" />
|
||||
</Style>
|
||||
<Style Selector="TextBox.input">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="11,8" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#D8DDE4" />
|
||||
<Setter Property="BorderBrush" Value="#DCCFC4" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
</Style>
|
||||
<Style Selector="TextBox.search-input">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="9,7" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="BorderBrush" Value="#E8DDD2" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
</Style>
|
||||
<Style Selector="Button.primary-button">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="12,9" />
|
||||
<Setter Property="Background" Value="#111418" />
|
||||
<Setter Property="Background" Value="#394350" />
|
||||
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
</Style>
|
||||
|
|
@ -137,8 +137,8 @@
|
|||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="10,8" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="Foreground" Value="#1E252C" />
|
||||
<Setter Property="BorderBrush" Value="#D8DDE4" />
|
||||
<Setter Property="Foreground" Value="#394350" />
|
||||
<Setter Property="BorderBrush" Value="#DCCFC4" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
<Style Selector="Button.icon-button">
|
||||
|
|
@ -146,9 +146,9 @@
|
|||
<Setter Property="MinWidth" Value="30" />
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="8,0" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="Foreground" Value="#1E252C" />
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="Foreground" Value="#394350" />
|
||||
<Setter Property="BorderBrush" Value="#E8DDD2" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
</Style>
|
||||
|
|
@ -162,16 +162,16 @@
|
|||
<Style Selector="Button.filter-button">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="9,5" />
|
||||
<Setter Property="Background" Value="#F7F8FA" />
|
||||
<Setter Property="Foreground" Value="#69727D" />
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB" />
|
||||
<Setter Property="Background" Value="#FBF7F2" />
|
||||
<Setter Property="Foreground" Value="#7F736A" />
|
||||
<Setter Property="BorderBrush" Value="#E8DDD2" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
</Style>
|
||||
<Style Selector="Button.filter-button.selected">
|
||||
<Setter Property="Background" Value="#111418" />
|
||||
<Setter Property="Background" Value="#394350" />
|
||||
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#111418" />
|
||||
<Setter Property="BorderBrush" Value="#394350" />
|
||||
</Style>
|
||||
<Style Selector="Button.rail-button">
|
||||
<Setter Property="Width" Value="38" />
|
||||
|
|
@ -179,15 +179,15 @@
|
|||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="Foreground" Value="#1E252C" />
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB" />
|
||||
<Setter Property="Foreground" Value="#394350" />
|
||||
<Setter Property="BorderBrush" Value="#E8DDD2" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
</Style>
|
||||
<Style Selector="Button.rail-button.active">
|
||||
<Setter Property="Background" Value="#111418" />
|
||||
<Setter Property="Background" Value="#394350" />
|
||||
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#111418" />
|
||||
<Setter Property="BorderBrush" Value="#394350" />
|
||||
</Style>
|
||||
<Style Selector="Button.row-button">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
|
|
@ -199,8 +199,8 @@
|
|||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Padding" Value="9,5" />
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="Foreground" Value="#4A5560" />
|
||||
<Setter Property="BorderBrush" Value="#E5E7EB" />
|
||||
<Setter Property="Foreground" Value="#7F736A" />
|
||||
<Setter Property="BorderBrush" Value="#E8DDD2" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="FontSize" Value="11.5" />
|
||||
</Style>
|
||||
|
|
@ -215,13 +215,9 @@
|
|||
<StackPanel Spacing="14">
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="KO · TALK" Classes="eyebrow" />
|
||||
<Border Width="50" Height="50" Classes="surface-muted" HorizontalAlignment="Left">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="KO"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="#111418" />
|
||||
<Border Width="50" Height="50" Classes="surface-muted" HorizontalAlignment="Left" Padding="7">
|
||||
<Image Source="avares://PhysOn.Desktop/Assets/kotalk-mark-128.png"
|
||||
Stretch="Uniform" />
|
||||
</Border>
|
||||
<TextBlock Text="KoTalk" Classes="display-title" />
|
||||
</StackPanel>
|
||||
|
|
@ -250,7 +246,7 @@
|
|||
<Border Classes="inline-alert" IsVisible="{Binding HasErrorText}">
|
||||
<TextBlock Text="{Binding ErrorText}"
|
||||
Classes="caption"
|
||||
Foreground="#C9392C"
|
||||
Foreground="#C9573C"
|
||||
TextWrapping="Wrap" />
|
||||
</Border>
|
||||
|
||||
|
|
@ -273,12 +269,9 @@
|
|||
<Border Grid.Column="0" Classes="rail-surface" Padding="8">
|
||||
<Grid RowDefinitions="Auto,*,Auto">
|
||||
<StackPanel Spacing="8">
|
||||
<Border Width="38" Height="38" Classes="surface-muted">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="KO"
|
||||
FontWeight="Bold"
|
||||
Foreground="#111418" />
|
||||
<Border Width="38" Height="38" Classes="surface-muted" Padding="6">
|
||||
<Image Source="avares://PhysOn.Desktop/Assets/kotalk-mark-128.png"
|
||||
Stretch="Uniform" />
|
||||
</Border>
|
||||
|
||||
<Button Classes="rail-button active" ToolTip.Tip="받은함">
|
||||
|
|
@ -292,7 +285,7 @@
|
|||
VerticalAlignment="Center"
|
||||
Text="{Binding CurrentUserMonogram}"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#1E252C" />
|
||||
Foreground="#394350" />
|
||||
</Border>
|
||||
<Button Classes="rail-button"
|
||||
ToolTip.Tip="로그아웃"
|
||||
|
|
@ -397,7 +390,7 @@
|
|||
VerticalAlignment="Center"
|
||||
Text="{Binding AvatarText}"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#111418" />
|
||||
Foreground="#20242B" />
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
|
|
@ -444,7 +437,7 @@
|
|||
<GridSplitter Grid.Column="2"
|
||||
Width="6"
|
||||
IsVisible="{Binding IsConversationPaneExpanded}"
|
||||
Background="#E5E7EB"
|
||||
Background="#E8DDD2"
|
||||
ResizeDirection="Columns"
|
||||
ShowsPreview="True" />
|
||||
|
||||
|
|
@ -456,7 +449,7 @@
|
|||
VerticalAlignment="Center"
|
||||
Text="{Binding SelectedConversationGlyph}"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#111418" />
|
||||
Foreground="#20242B" />
|
||||
</Border>
|
||||
|
||||
<StackPanel Grid.Column="1" Spacing="2">
|
||||
|
|
@ -503,7 +496,7 @@
|
|||
IsVisible="{Binding HasErrorText}">
|
||||
<TextBlock Text="{Binding ErrorText}"
|
||||
Classes="caption"
|
||||
Foreground="#C9392C"
|
||||
Foreground="#C9573C"
|
||||
TextWrapping="Wrap" />
|
||||
</Border>
|
||||
|
||||
|
|
@ -526,7 +519,7 @@
|
|||
IsVisible="{Binding ShowSenderName}" />
|
||||
<TextBlock Text="{Binding Text}"
|
||||
FontSize="13"
|
||||
Foreground="#111418"
|
||||
Foreground="#20242B"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Text="{Binding MetaText}" Classes="caption" />
|
||||
</StackPanel>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="PhysOn.Desktop.Desktop"/>
|
||||
<assemblyIdentity version="1.0.0.0" name="KoTalk.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="theme-color" content="#101826" />
|
||||
<meta name="theme-color" content="#394350" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="KoTalk" />
|
||||
|
|
@ -11,8 +11,11 @@
|
|||
name="description"
|
||||
content="업무 대화와 일상 대화를 같은 흐름 안에서 가볍게 이어 주는 KoTalk 웹앱입니다."
|
||||
/>
|
||||
<link rel="icon" href="/favicon.ico" sizes="any" />
|
||||
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.svg" />
|
||||
<link rel="icon" href="/favicon-32x32.png" type="image/png" sizes="32x32" />
|
||||
<link rel="icon" href="/favicon-16x16.png" type="image/png" sizes="16x16" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/manifest.webmanifest" />
|
||||
<title>KoTalk</title>
|
||||
</head>
|
||||
|
|
|
|||
4
src/PhysOn.Web/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "physon-web",
|
||||
"version": "0.1.0-alpha.4",
|
||||
"version": "0.1.0-alpha.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "physon-web",
|
||||
"version": "0.1.0-alpha.4",
|
||||
"version": "0.1.0-alpha.5",
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "physon-web",
|
||||
"private": true,
|
||||
"version": "0.1.0-alpha.4",
|
||||
"version": "0.1.0-alpha.5",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host 0.0.0.0",
|
||||
|
|
|
|||
BIN
src/PhysOn.Web/public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -1,5 +1,7 @@
|
|||
<svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="180" height="180" rx="50" fill="#101826"/>
|
||||
<path d="M42 55C42 47.268 48.268 41 56 41H124C131.732 41 138 47.268 138 55V104C138 111.732 131.732 118 124 118H89.285L65.86 136.409C61.252 140.031 54.55 136.752 54.55 130.896V118H56C48.268 118 42 111.732 42 104V55Z" fill="#F6F2EA"/>
|
||||
<path d="M63 77.5L78.363 100.438L92.545 77.727L107.223 100.438L122.5 77.5" stroke="#101826" stroke-width="8.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="none">
|
||||
<path d="M 240.00 312.00 H 780.00 A 22.00 22.00 0 0 1 802.00 334.00 V 892.00 A 22.00 22.00 0 0 1 780.00 914.00 H 240.00 A 22.00 22.00 0 0 1 218.00 892.00 V 334.00 A 22.00 22.00 0 0 1 240.00 312.00 Z" fill="#394350" />
|
||||
<path d="M 304.00 602.00 L 304.00 736.00 L 438.00 602.00 Z" fill="#394350" />
|
||||
<path d="M 468.00 312.00 H 1236.00 A 22.00 22.00 0 0 1 1258.00 334.00 V 892.00 A 22.00 22.00 0 0 1 1236.00 914.00 H 468.00 A 22.00 22.00 0 0 1 446.00 892.00 V 334.00 A 22.00 22.00 0 0 1 468.00 312.00 Z" fill="#F05B2B" />
|
||||
<path d="M 668.00 602.00 L 742.00 602.00 L 742.00 694.00 L 694.00 650.00 Z" fill="#F05B2B" />
|
||||
<path d="M 490.00 328.00 L 582.00 328.00 L 446.00 457.00 L 582.00 586.00 L 490.00 586.00 L 338.00 457.00 Z" fill="#FFFFFF" />
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 562 B After Width: | Height: | Size: 831 B |
BIN
src/PhysOn.Web/public/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 492 B |
BIN
src/PhysOn.Web/public/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 922 B |
BIN
src/PhysOn.Web/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/PhysOn.Web/public/icon-192.png
Normal file
|
After Width: | Height: | Size: 4 KiB |
BIN
src/PhysOn.Web/public/icon-512.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -1,5 +1,7 @@
|
|||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="512" height="512" rx="144" fill="#101826"/>
|
||||
<path d="M120 150C120 127.909 137.909 110 160 110H352C374.091 110 392 127.909 392 150V304C392 326.091 374.091 344 352 344H251.232L184.314 396.674C171.148 407.041 152 397.656 152 380.899V344H160C137.909 344 120 326.091 120 304V150Z" fill="#F6F2EA"/>
|
||||
<path d="M171 201.5L214.894 267L255.4 202.15L297.35 267L341 201.5" stroke="#101826" stroke-width="24" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="none">
|
||||
<path d="M 240.00 312.00 H 780.00 A 22.00 22.00 0 0 1 802.00 334.00 V 892.00 A 22.00 22.00 0 0 1 780.00 914.00 H 240.00 A 22.00 22.00 0 0 1 218.00 892.00 V 334.00 A 22.00 22.00 0 0 1 240.00 312.00 Z" fill="#394350" />
|
||||
<path d="M 304.00 602.00 L 304.00 736.00 L 438.00 602.00 Z" fill="#394350" />
|
||||
<path d="M 468.00 312.00 H 1236.00 A 22.00 22.00 0 0 1 1258.00 334.00 V 892.00 A 22.00 22.00 0 0 1 1236.00 914.00 H 468.00 A 22.00 22.00 0 0 1 446.00 892.00 V 334.00 A 22.00 22.00 0 0 1 468.00 312.00 Z" fill="#F05B2B" />
|
||||
<path d="M 668.00 602.00 L 742.00 602.00 L 742.00 694.00 L 694.00 650.00 Z" fill="#F05B2B" />
|
||||
<path d="M 490.00 328.00 L 582.00 328.00 L 446.00 457.00 L 582.00 586.00 L 490.00 586.00 L 338.00 457.00 Z" fill="#FFFFFF" />
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 570 B After Width: | Height: | Size: 831 B |
|
|
@ -1,24 +1,24 @@
|
|||
{
|
||||
"name": "PhysOn",
|
||||
"short_name": "PhysOn",
|
||||
"name": "KoTalk",
|
||||
"short_name": "KoTalk",
|
||||
"description": "업무 소통과 친근한 대화를 한 손 흐름으로 이어 주는 모바일 중심 메신저 웹앱",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#101826",
|
||||
"theme_color": "#101826",
|
||||
"background_color": "#FFFFFF",
|
||||
"theme_color": "#394350",
|
||||
"lang": "ko-KR",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"src": "/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/mask-icon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "maskable"
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="512" height="512" rx="144" fill="#101826"/>
|
||||
<path d="M120 150C120 127.909 137.909 110 160 110H352C374.091 110 392 127.909 392 150V304C392 326.091 374.091 344 352 344H251.232L184.314 396.674C171.148 407.041 152 397.656 152 380.899V344H160C137.909 344 120 326.091 120 304V150Z" fill="#F6F2EA"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="none">
|
||||
<path d="M 0.00 0.00 H 1024.00 A 0.00 0.00 0 0 1 1024.00 0.00 V 1024.00 A 0.00 0.00 0 0 1 1024.00 1024.00 H 0.00 A 0.00 0.00 0 0 1 0.00 1024.00 V 0.00 A 0.00 0.00 0 0 1 0.00 0.00 Z" fill="#141922" />
|
||||
<path d="M 240.00 312.00 H 780.00 A 22.00 22.00 0 0 1 802.00 334.00 V 892.00 A 22.00 22.00 0 0 1 780.00 914.00 H 240.00 A 22.00 22.00 0 0 1 218.00 892.00 V 334.00 A 22.00 22.00 0 0 1 240.00 312.00 Z" fill="#F7F3EE" />
|
||||
<path d="M 304.00 602.00 L 304.00 736.00 L 438.00 602.00 Z" fill="#F7F3EE" />
|
||||
<path d="M 468.00 312.00 H 1236.00 A 22.00 22.00 0 0 1 1258.00 334.00 V 892.00 A 22.00 22.00 0 0 1 1236.00 914.00 H 468.00 A 22.00 22.00 0 0 1 446.00 892.00 V 334.00 A 22.00 22.00 0 0 1 468.00 312.00 Z" fill="#F05B2B" />
|
||||
<path d="M 668.00 602.00 L 742.00 602.00 L 742.00 694.00 L 694.00 650.00 Z" fill="#F05B2B" />
|
||||
<path d="M 490.00 328.00 L 582.00 328.00 L 446.00 457.00 L 582.00 586.00 L 490.00 586.00 L 338.00 457.00 Z" fill="#141922" />
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 417 B After Width: | Height: | Size: 1 KiB |
|
|
@ -1,5 +1,12 @@
|
|||
const CACHE_NAME = 'vs-talk-shell-v2';
|
||||
const SHELL = ['/manifest.webmanifest', '/icon.svg', '/apple-touch-icon.svg', '/mask-icon.svg'];
|
||||
const CACHE_NAME = 'ko-talk-shell-v3';
|
||||
const SHELL = [
|
||||
'/manifest.webmanifest',
|
||||
'/icon.svg',
|
||||
'/icon-192.png',
|
||||
'/icon-512.png',
|
||||
'/apple-touch-icon.png',
|
||||
'/favicon.ico',
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.addAll(SHELL)));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" fill="none">
|
||||
<rect width="128" height="128" rx="34" fill="#17372F"/>
|
||||
<path d="M27 33h23l14 25 14-25h23L75 95H53L27 33Z" fill="#F6E8D5"/>
|
||||
<path d="M60 39h8v50h-8z" fill="#DDB07B"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="none">
|
||||
<path d="M 240.00 312.00 H 780.00 A 22.00 22.00 0 0 1 802.00 334.00 V 892.00 A 22.00 22.00 0 0 1 780.00 914.00 H 240.00 A 22.00 22.00 0 0 1 218.00 892.00 V 334.00 A 22.00 22.00 0 0 1 240.00 312.00 Z" fill="#394350" />
|
||||
<path d="M 304.00 602.00 L 304.00 736.00 L 438.00 602.00 Z" fill="#394350" />
|
||||
<path d="M 468.00 312.00 H 1236.00 A 22.00 22.00 0 0 1 1258.00 334.00 V 892.00 A 22.00 22.00 0 0 1 1236.00 914.00 H 468.00 A 22.00 22.00 0 0 1 446.00 892.00 V 334.00 A 22.00 22.00 0 0 1 468.00 312.00 Z" fill="#F05B2B" />
|
||||
<path d="M 668.00 602.00 L 742.00 602.00 L 742.00 694.00 L 694.00 650.00 Z" fill="#F05B2B" />
|
||||
<path d="M 490.00 328.00 L 582.00 328.00 L 446.00 457.00 L 582.00 586.00 L 490.00 586.00 L 338.00 457.00 Z" fill="#FFFFFF" />
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 831 B |
|
|
@ -106,6 +106,17 @@
|
|||
fill: currentColor;
|
||||
}
|
||||
|
||||
.brand-mark__image {
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.brand-mark--small .brand-mark__image {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.brand-mark--small {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
|
@ -239,7 +250,7 @@
|
|||
.field input::placeholder,
|
||||
.search-field input::placeholder,
|
||||
.composer textarea::placeholder {
|
||||
color: #a0a7b1;
|
||||
color: #aaa095;
|
||||
}
|
||||
|
||||
.text-action,
|
||||
|
|
@ -411,20 +422,20 @@
|
|||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 2px;
|
||||
background: #9ca3af;
|
||||
background: #b6a292;
|
||||
}
|
||||
|
||||
.status-chip--connecting .status-dot,
|
||||
.status-chip--idle .status-dot {
|
||||
background: #f59e0b;
|
||||
background: #d08a44;
|
||||
}
|
||||
|
||||
.status-chip--connected .status-dot {
|
||||
background: #1f9d55;
|
||||
background: #698869;
|
||||
}
|
||||
|
||||
.status-chip--fallback .status-dot {
|
||||
background: #2563eb;
|
||||
background: #6c84ab;
|
||||
}
|
||||
|
||||
.search-field {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ type IconName =
|
|||
| 'group'
|
||||
|
||||
const DEFAULT_API_BASE_URL = import.meta.env.VITE_API_BASE_URL?.trim() ?? ''
|
||||
const APP_VERSION = 'web-0.1.0-alpha.4'
|
||||
const APP_VERSION = 'web-0.1.0-alpha.5'
|
||||
|
||||
const CONNECTION_LABEL: Record<ConnectionState, string> = {
|
||||
idle: '준비 중',
|
||||
|
|
@ -220,7 +220,15 @@ function Icon({ name }: { name: IconName }) {
|
|||
case 'mark':
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M5 6.5a2.5 2.5 0 0 1 2.5-2.5h9A2.5 2.5 0 0 1 19 6.5v6A2.5 2.5 0 0 1 16.5 15H10l-3.5 3v-3H7.5A2.5 2.5 0 0 1 5 12.5z" />
|
||||
<path
|
||||
fill="#394350"
|
||||
d="M4.2 7.1A1.2 1.2 0 0 1 5.4 5.9h8.4A1.2 1.2 0 0 1 15 7.1v5.8a1.2 1.2 0 0 1-1.2 1.2H10l-2.7 2.7v-2.7H5.4a1.2 1.2 0 0 1-1.2-1.2z"
|
||||
/>
|
||||
<path
|
||||
fill="#F05B2B"
|
||||
d="M9.8 7.1A1.2 1.2 0 0 1 11 5.9h7.6a1.2 1.2 0 0 1 1.2 1.2v5.8a1.2 1.2 0 0 1-1.2 1.2h-1.1v2.2l-1.8-2.2H11a1.2 1.2 0 0 1-1.2-1.2z"
|
||||
/>
|
||||
<path fill="#FFFFFF" d="M11.1 6.8h2L9.8 12l3.3 5.2h-2l-4-5.2z" />
|
||||
</svg>
|
||||
)
|
||||
case 'refresh':
|
||||
|
|
@ -1060,7 +1068,7 @@ function App() {
|
|||
<header className="onboarding__chrome">
|
||||
<div className="brand-lockup">
|
||||
<span className="brand-mark" aria-hidden="true">
|
||||
<Icon name="mark" />
|
||||
<img className="brand-mark__image" src="/vs-mark.svg" alt="" />
|
||||
</span>
|
||||
<div className="brand-lockup__text">
|
||||
<strong>KoTalk</strong>
|
||||
|
|
@ -1159,7 +1167,7 @@ function App() {
|
|||
<header className="appbar">
|
||||
<div className="appbar__leading">
|
||||
<span className="brand-mark brand-mark--small" aria-hidden="true">
|
||||
<Icon name="mark" />
|
||||
<img className="brand-mark__image" src="/vs-mark.svg" alt="" />
|
||||
</span>
|
||||
<div className="appbar__title">
|
||||
<h2>{activeDestinationMeta.title}</h2>
|
||||
|
|
|
|||
|
|
@ -8,25 +8,25 @@
|
|||
sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 500;
|
||||
color: #111111;
|
||||
background: #f5f5f6;
|
||||
color: #20242b;
|
||||
background: #f7f3ee;
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
--surface-page: #f5f5f6;
|
||||
--surface-page: #f7f3ee;
|
||||
--surface-base: #ffffff;
|
||||
--surface-raised: #fcfcfc;
|
||||
--surface-muted: #f6f6f7;
|
||||
--surface-selected: #eef2f6;
|
||||
--surface-chat-mine: #f1f1f2;
|
||||
--border-subtle: #ececef;
|
||||
--border-strong: #d8d8dd;
|
||||
--border-contrast: #18181b;
|
||||
--text-strong: #141416;
|
||||
--text-soft: #333338;
|
||||
--text-muted: #7b7b84;
|
||||
--focus-ring: #1a73e8;
|
||||
--surface-raised: #fdfaf6;
|
||||
--surface-muted: #faf6f1;
|
||||
--surface-selected: #f3ece4;
|
||||
--surface-chat-mine: #f0e5d8;
|
||||
--border-subtle: #e8ddd2;
|
||||
--border-strong: #dbcdbf;
|
||||
--border-contrast: #394350;
|
||||
--text-strong: #20242b;
|
||||
--text-soft: #3b414b;
|
||||
--text-muted: #82766d;
|
||||
--focus-ring: #c07a43;
|
||||
}
|
||||
|
||||
* {
|
||||
|
|
|
|||