Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[react-todo-list 미션 step1] 송혜정 미션 제출합니다. #1

Open
wants to merge 17 commits into
base: songhyejeong
Choose a base branch
from

Conversation

Songhyejeong
Copy link

안녕하세요 리뷰어님!
설날 잘 보내셨나요? 새해복 많이 받으세요 🙇🏼
그리고 늦어서 죄송합니다...
벌써 마지막 미션인 TodoList 미션인데 그동안 매번 정성스럽게 리뷰 해주셔서 정말 도움 많이 됐습니다 감사합니다!

느낀점

이번 미션은 사실 step1이라서 기능적으로 구현하는데 어려운 건 없었는데, 제가 처음에 미션 요구사항을 제대로 확인하지 않아서 나중에 컴포넌트를 다 수정하는데 조금 오래 걸렸습니다😂

궁금한 점

  1. 코드에서 todoList의 상태를 App이 관리하고 있어서, 커스텀 훅을 만들까 생각했었는데 한 번쓰이는 훅을 단순히 코드가 깔끔해 보이기 위해서 훅을 만드는게 의미가 있을까 생각했습니다. 이부분에 대해서 리뷰어님의 생각도 궁금합니다!

  2. TodoInsert에서 form을 사용하는데, 이렇게 하면 UX적으로 적절할까요?

새롭게 알게 된점

checkbox가 input이라는 점 Button으로 하면 접근성이 떨어진다고 하네요.. (아직 수정하기 전입니다)

작동 영상

Screen.Recording.2025-02-05.at.12.24.29.AM.mov

Copy link
Member

@wzrabbit wzrabbit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Songhyejeong 👋🏻

새해 복 많이 받으세요!
설날 잘 보내셨나요? 연가 쓰니까 9일 연속 휴가가 되니 좋더군요. 저는 오랜만에 짧게 바다 여행 다녀왔어요. 혜정님은 다녀오신 곳이 있으신가요?

1️⃣ 질문/답변

이번 미션은 사실 step1이라서 기능적으로 구현하는데 어려운 건 없었는데, 제가 처음에 미션 요구사항을 제대로 확인하지 않아서 나중에 컴포넌트를 다 수정하는데 조금 오래 걸렸습니다😂

오 보니까 컴포넌트를 굉장히 잘게 쪼개셨더라고요, 몇몇 컴포넌트들은 아예 공용 컴포넌트(common components)로도 빼낼 수 있을 정도로요. 필요에 따라 이렇게 분리해 주시거나, 이유를 가지고 분리하지 않으시는 연습 해주시면 좋을 것 같습니다 👍🏻

코드에서 todoList의 상태를 App이 관리하고 있어서, 커스텀 훅을 만들까 생각했었는데 한 번쓰이는 훅을 단순히 코드가 깔끔해 보이기 위해서 훅을 만드는게 의미가 있을까 생각했습니다. 이부분에 대해서 리뷰어님의 생각도 궁금합니다!

100% 대응은 어렵지만, 커스텀 훅 또한 함수와 크게 다르지 않아요. 내부에 기능을 지니고 있고, 재사용 및 관심사의 분리가 가능한 친구죠. 그러한 필요성을 느끼신다면 단 한 번만 사용하더라도 분리할 이유는 충분하다고 생각합니다. 함수도 한 번만 사용했더라도 너무 많은 일을 하는 함수라면 여러 개로 쪼갰잖아요? 커스텀 훅도 마찬가지입니다.

UI 파트의 로직과 도메인 파트의 로직을 분리하기에도 좋을 거에요. 컴포넌트가 작다면 상관 없지만 컴포넌트가 커진다면 분리의 필요성을 느끼실 것이라고도 생각되네요.

제가 어떻게 사용하는 지를 물으신다면, 저는 컴포넌트가 간단한 경우가 아니면 거의 항상 분리하며 사용합니다. 이래야 한다는 것은 아니고, 상황에 따라 판단해 보실 문제 같아요.

TodoInsert에서 form을 사용하는데, 이렇게 하면 UX적으로 적절할까요?

저는 좋게 보입니다! 👍🏻

  • <TodoInsert>는 일정 입력창과 등록 버튼만 있는 간단한 구조지만, 엄연히 폼으로써의 성격을 가지고 있어요. 사용자에게 값을 입력받고, 제출하면 처리하는 구조죠.
  • <form> 의 기본 동작을 상황에 따라 이미 적절히 활용하고 계세요. onSubmit 을 통해 제출을 받고 계시고, 값들은 React 내부에서 처리할 것이므로 페이지 이동 관련 기본 동작은 막고, 엔터 키를 누르면 폼이 제출된다는 특징도 잘 활용하고 계세요.
  • <form>의 기능들을 사용하지 않거나 매우 적게 사용할 상황이더라도, 존재 자체로 목적 및 의미를 설명하므로 시멘틱적으로도 좋으며, 접근성 면에서도 사용자가 이것이 폼이라는 것을 더 명확하게 알 수 있습니다.

위의 근거들을 이유로 UX면에서 적절하다고 생각합니다. 다만 <form> 을 생략하더라도 그에 대응하는 적절한 기능들이 뒷받침된다면 썩 나쁜 UI/UX이지는 않다고도 생각합니다. 어쨌든 폼의 값들은 React 상태로 관리하고 있기 때문에 <form> 을 무조건 써야만 할 절실한 상황은 아니에요.

2️⃣ 리뷰

성능 미션이기는 한데, 1단계에서는 애플리케이션을 구현하는 것이 중점인 미션이군요? 그래서 저도 프로젝트 자체를 중심으로 리뷰해 보았어요.

전반적으로 컴포넌트들은 기능에 맞게 잘 분리되어 있었고, 대부분의 이벤트 핸들링 로직 또한 탁월했어요. 주어진 기능들은 잘 구현해내시는 것 같았어요. 여기에 더해 두 가지가 개선되면 정말 완벽할 것 같다는 생각이 들었어요.

  • React에서 발생하는 경고들을 개발자 도구를 통해 꼼꼼하게 확인하기: React가 key 값을 까먹었다고 저에게 알려주더라고요 👂🏻
  • 예외 처리: 별도로 요구사항에 없더라도 만드시는 모든 애플리케이션에서는 예외 처리가 있었으면 좋겠어요. 하지만 구현하고 싶으셨지만 시간이 없으셔서 그랬던 것이라고 생각해요. 시간이 충분했다면 분명 예외 처리도 하셨으리라 굳게 믿어요.

전체적인 기능들은 이제 베테랑처럼 잘 구현해 주시는 것 같아 이번에는 시멘틱 태그접근성 을 주제로 중점적으로 리뷰해 보았어요. 혜정님에게 이 리뷰가 색다르게 다가왔으면 하는 생각이에요.

checkbox가 input이라는 점 Button으로 하면 접근성이 떨어진다고 하네요..

여기에서도 접근성을 신경써주시면서 말씀해주셨는데 왜 그런지도 한 번... 알아보시겠어요? 스크린 리더가 뭐라고 읽어줄 지를 생각해 보신다면 떠올리실 수도 있을 것 같아요.

팀플 준비하느라 바쁘실 텐데, 미션도 구현하시고 수고 많으셨어요~!

-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
* {
box-sizing: border-box;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

box-sizing: border-box; 는 무엇일까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

box-sizing 속성은 요소의 width와 height의 속성을 어떻게 계산할지를 지정합니다.
content-box는 테두리와 안쪽 여백을 주었을 때 width, height 속성은 테두리 안쪽 여백을 포함한 값입니다. border-box는 width, height 값은 고정되고 테두리와 안쪽 여백까지 요소의 크기로 포함되어 콘텐츠 영역 값이 고정됩니다.
css를 reset할 때,box-sizing: border-box;를 작성하는 이유는 테두리나, 안쪽 여백 같은 속성을 주었을 때도, 총 width나 height가 고정되므로 스타일을 줄 때 예측하기 쉽게 해주기 때문입니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정확하네요 ㅎㅎ 저도 요소의 width, height 를 예측하기 쉬워서 이 속성은 항상 넣고 있어요

src/index.css Outdated
transition: border-color 0.25s;
background-color: transparent;
border: none;
outline: none;
Copy link
Member

@wzrabbit wzrabbit Feb 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

접근성을 소중하게 생각하신다면, outline: none 사용에 대해서도 고민해 볼 점으로 보여요 🤔

별다른 대안 없이 outline: none 속성을 사용하는 경우에는 스크린 리더 사용자들 뿐만 아니라 키보드를 이용해 웹을 탐색하는 사용자들이 어려움을 느낄 수 있어 보여요, 그래서 추천드리고 싶지 않고, 글로벌 스타일이면 더더욱 추천드리고 싶지 않은 속성이에요.

프로젝트에서 [Tab] 키를 누름에 따라 버튼, 인풋 등 선택 가능한 요소들을 차례로 탐색하게 될 거에요. 무슨 요소를 선택했는지를 명확하게 알기 어려운 상황이라면 접근성이 부족할 수 있음을 의미하는 신호입니다.

겉으로 보았을 때는 border 와 비슷해 보이는데 outline 이 무슨 역할을 하는지, 이번 미션에서 한 번 조사해 보시겠어요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outline: none 사용이 문제를 일으키는지 몰랐네요.. 조사하고 여기에 정리해보겠습니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

border는 요소의 테두리를 나타내며 요소의 크기에 포함된다. outline은 요소 콘텐츠의 밖에 그려지며 절대 공간을 차지하지 않는다.

기능 차이

  • outline은 **포커스(focus) 상태에서 시각적 피드백을 주기 위해 사용된다.
  • border는 단순한 디자인 요소이므로 포커스 상태와 직접적인 연관이 없다.

outline에 0또는 none 값을 지정하면, 기본 포커스 스타일이 사라짐. 접근성을 고려한다면, 이 방법 대신 다른 방법을 생각해봐야한다.
<'outline-color'>,<'outline-style'>,<'outline-width'> 이런 스타일 주는 방법도 있음.

Comment on lines 12 to 16
const handleSubmit = (e) => {
e.preventDefault();
onAddTodo(text);
setText('');
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래의 상황들에는 어떻게 대응해 볼 수 있을까요?

image

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다음과 같은 상황에서는 input에 maxlength 속성을 지정해줘서, 사용자가 입력하는 글자가 특정 길이를 넘어간다면, 더이상 입력이 되지않게 하거나 경고 메세지를 아래 띄울 수 도 있을 것 같아요! 🙂

Comment on lines 20 to 25
<form onSubmit={handleSubmit}>
<StyledTodoInsertLabel>
<TodoInputField text={text} setText={setText} />
<TodoAddButton />
</StyledTodoInsertLabel>
</form>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오, <form> 좋네요 👍🏻 제출 시에도 onSubmit 이벤트와 event.preventDefault 를 잘 활용하셨네요

Comment on lines 9 to 15
<TodoListItem
id={todo.id}
checked={todo.checked}
text={todo.text}
onDeleteTodo={onDeleteTodo}
onCheckTodo={onCheckTodo}
/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key prop을 넣는 것을 항상 잊지 말아주세요 😉 개발자 도구에서도 React가 key 값을 빼먹었다면 친절하게 알려주니 개발자 도구의 콘솔을 자주 확인해 주시면 좋겠어요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앞으로 개발자 도구 콘솔을 자주 보는 습관을 들여야겠네요..

src/App.jsx Outdated
Comment on lines 37 to 43
const handleCheckTodo = (id) => {
setTodoList((prev) =>
prev.map((todo) =>
todo.id === id ? { ...todo, checked: !todo.checked } : todo
)
);
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

불변성 유지, functional update의 적절한 사용이 돋보이는 깔끔한 코드네요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/App.jsx Outdated
setTodoList((prev) => prev.filter((todo) => todo.id !== id));
};

const handleCheckTodo = (id) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 이름도 충분히 좋지만, handleCheckTodo 의 경우 마치 새롭게 체크를 활성화하는 의미로도 들릴 수 있다는 느낌이 조금 들었는데, 토글한다는 의미를 넣는다면 어떨 것 같나요!?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

토글한다는 의미를 넣으면 더 확실하게 어떤 역할을 하는 함수인지 알 수 있을 것 같아요!

Comment on lines 21 to 24
<StyledTodoInsertLabel>
<TodoInputField text={text} setText={setText} />
<TodoAddButton />
</StyledTodoInsertLabel>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

입력 창과 "+" 버튼을 <label> 로 감싸신 이유가 있으신가요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스타일을 "+"까지 적용하기 위해서 감쌌던 거 같은데 label안에 버튼이 들어가는 구조가 조금 이상해 보이네요.
수정해보겠습니다!

@@ -0,0 +1,14 @@
import styled from 'styled-components';

export const TodoListLayout = styled.div`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<TodoListLayout>, <TodoListItem> 은 각각 투두 리스트의 목록, 그리고 목록 항목 에 대응되는 컴포넌트들이죠?
<div> 의 사용은 무난하지만, 목록목록 항목 에 대응하는 의미를 더 잘 지니는 <ul>(Unordered List), <li> (List Item) 태그를 어쩌면 활용할 수도 있어 보여요. 텍스트뿐만 아니라 다른 요소들도 목록 관련 의미를 지닌다면 충분히 이 태그 안에 들어갈 수 있는 녀석들이랍니다, 어떠신가요? 견해가 갈리는 부분이고, 오히려 복잡한 구조를 싫어하시는 분들도 계셔서 의견만 공유해보아요 😄

스크린 리더에서는 아래와 같이 읽게 됩니다(예시):

  • 목록 n개 포함 목록 항목
  • 목록 항목

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컴포넌트의 의미와 목적을 명확하게 하는게 좋을 것 같네요
다음 미션까지 고려하게 된다면 div의 깊이가 많이 깊어질 것 같은데 의천님께서 말씀하신대로 <ul>(Unordered List), <li>(List Item) 태그를 사용 한다면 깊이를 아는데 유용하기도 하고 이 컴포넌트가 목록이라는 형식임을 짐작할 수 있겠네요!

Comment on lines 10 to 12
border-radius: 0.75rem;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shorthand로 쓴다면 이렇게 쓸 수도 있는데, 이건 취향 따라서 적용해 보셔도 되고 그대로 두셔도 됩니다

border-radius: 0.75rem 0.75rem 0 0;

『왼쪽 위 모서리 → 오른쪽 위 모서리 → 오른쪽 아래 모서리 → 왼쪽 아래 모서리』 순서에요! 시계방향이죠.

image

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이렇게 쓰면 훨씬 깔끔하게 적용할 수 있겠네요! 감사합니다

@Songhyejeong
Copy link
Author

@wzrabbit
의천님 안녕하세요! 리뷰 감사합니다.
저는 설날 일주일 동안 시골에 내려갔었어요! 겨울 바다 여행 저도 가고 싶네요.. 이번 리뷰는 의천님께서 말씀해주신대로 색달랐어요! 시멘틱 태그와 접근성에 대해서 덕분에 많은 정보 알아갈 수 있었던 거 같아요!
리뷰 남겨주신거 최대한 반영해서 리팩터링 진행해보았습니다~

답변

100% 대응은 어렵지만, 커스텀 훅 또한 함수와 크게 다르지 않아요. 내부에 기능을 지니고 있고, 재사용 및 관심사의 분리가 가능한 친구죠. 그러한 필요성을 느끼신다면 단 한 번만 사용하더라도 분리할 이유는 충분하다고 생각합니다. 함수도 한 번만 사용했더라도 너무 많은 일을 하는 함수라면 여러 개로 쪼갰잖아요? 커스텀 훅도 마찬가지입니다.

함수와 커스텀훅을 비슷하게 생각해보면 이해하기 쉽겠네요!
한 번만 사용하더라도 그 부피가 커지면 쪼개는게 좋을 것 같다는 의견에 동감합니다. 커스텀 훅도 그렇게 접근하면 더 깔끔하게 유지할 수 있을 것 같아요! 그리고 UI와 도메인 로직을 분리한다는 관점으로는 처음 생각해봤는데, 이런 관점으로 보면 유지보수가 더 용이해질 것 같아요. 좋은 의견 공유해주셔서 감사합니다.☺️

위의 근거들을 이유로 UX면에서 적절하다고 생각합니다. 다만 

 을 생략하더라도 그에 대응하는 적절한 기능들이 뒷받침된다면 썩 나쁜 UI/UX이지는 않다고도 생각합니다. 어쨌든 폼의 값들은 React 상태로 관리하고 있기 때문에  을 무조건 써야만 할 절실한 상황은 아니에요.

좋은 의견 감사힙니다! <form> 사용 근거를 읽어보니, 필요성이 와닿네요. <form>에서 기본으로 제공되는 기능들을 활용하고, 목적과 의미를 다시 생각해보니 저도 적절하다는 생각이 듭니다.

예외처리
처음 미션 구현할 때 예외처리를 신경쓰지 못했는데, 리뷰 남겨주신 내용을 참고하여 예외 처리 부분을 추가해봤습니다. 예외처리는 입력창에 아무것도 입력하지 않을 경우와, 입력한 글자의 길이가 30이 넘을 경우 각각 추가해보았습니다!

checkbox
그리고 checkbox에서 input type = "checkbox"가 기본 표준이기 때문만이 아니라, 스크린 리더를 확인해보니 버튼은 그냥 버튼이 클릭 된 사실만 알 수 있다면 input 요소가 스크린 리더에서 체크 박스의 상태를 읽어주네요.
Screenshot 2025-02-08 at 9 57 33 PM

매번 꼼꼼하게 리뷰해주셔서 감사합니다!

Copy link
Member

@wzrabbit wzrabbit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 의견 감사힙니다!

사용 근거를 읽어보니, 필요성이 와닿네요. 에서 기본으로 제공되는 기능들을 활용하고, 목적과 의미를 다시 생각해보니 저도 적절하다는 생각이 듭니다.

<form> 사용에 대해 이제 확신을 느끼시는 것 같습니다, 좋네요 👍🏻

checkbox
그리고 checkbox에서 input type = "checkbox"가 기본 표준이기 때문만이 아니라, 스크린 리더를 확인해보니 버튼은 그냥 버튼이 클릭 된 사실만 알 수 있다면 input 요소가 스크린 리더에서 체크 박스의 상태를 읽어주네요.

그럼요, 스크린 리더가 직접 이게 체크박스라는 것을 설명할 뿐만 아니라, 체크박스가 선택되었는지도 알려주기 때문에 중요합니다.

저는 Chrome VOX를 스크린 리더로 사용하는데, Chrome VOX에서는 체크박스 선택/선택 해제 시 특유의 전용 효과음이 재생되고, "체크 박스 선택됨." "체크 박스 선택 안 함." 과 같이 브리핑을 해 준답니다. 미션을 진행하시면서 스크린 리더를 사용하기까지 하셨다면 정말 뜻깊게 미션을 수행하신 것 같아요

리뷰 반영은 모두 확인했고, 대부분 잘 수행해주신 것 같습니다, 각각에 대해서는 코멘트를 달아드렸습니다.

이제 정말 마지막 미션 하나만 남았네요, 다른 동아리보다 훨씬 힘들고 빡센 과정을 견디시느라 수고 많으셨고, 마지막까지 잘 해내 봅시다!

@@ -9,5 +9,4 @@ export const StyledTodoInput = styled.input`
background-color: white;
border: none;
border-radius: 0.5rem;
outline: none;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

만약 이후 윤곽선이 못생겨서 만약 outline: none 를 쓰고 싶으시다면, 전체 스타일로써 적용하기보다는 특정 컴포넌트에 적용해 보시되, 이를 대체할 다른 디자인 (이 요소가 선택되었다는 것을 알기 쉬운 디자인) 을 추천드려 봅니다 ✏️

-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
* {
box-sizing: border-box;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정확하네요 ㅎㅎ 저도 요소의 width, height 를 예측하기 쉬워서 이 속성은 항상 넣고 있어요

Comment on lines +1 to +6
const colors = {
green: '#027355',
amber: '#F7F7F2',
grey: '#8E8E93',
lightGrey: '#EBF0EB',
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

간단한 상황이라면 충분히 개발자의 취향에 따라 갈릴 것 같아요! 색상이 적은 횟수로 사용된다면 하드코딩도 충분히 가능한 방법 중 하나라고 생각해요 ✅ 만약 IDE에서 HEX코드만 적더라도 바로 색상을 보여주는 기능까지 있다면 변수로 둘 필요성은 더욱 내려갈 수도 있을 것 같아보이는군요

만약 저라면 적은 횟수로 사용되더라도 저는 변수로 선언해서 관리할 것 같아요, 하드코딩된 HEX값들은 매직 넘버와 비슷한 위치에 있다고 생각하거든요, 많이 쓰이면 GlobalStyle로 두고, 한 모듈에서 사용된다면 그 모듈에서 색상 변수를 두고 관리할 것 같은 생각? 이 정도 드네요

상황에 따라 혜정님만의 방법을 사용해보시죠 💪🏻


const TodoButton = ({ onClick, icon: Icon, iconColor, ariaLabel, title }) => {
return (
<StyledButton onClick={onClick} aria-label={ariaLabel} title={title}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aria-label 👍🏻 스크린 리더도 혹시 깔아서 확인해 보셨나요?

type="text"
name="todo"
value={text}
maxLength="30"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋네요 👍🏻 비어있는 경우는 required 로 처리해 주셨군요

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants