-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: フロントエンド開発 #81
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
Merged
Merged
Changes from 7 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
9f29e62
refactor: フロントエンドのルーティングの責務を明文化
umekikazuya f5f86c6
feat: テーマ設定
umekikazuya 7b6805d
feat: リクエストの整理
umekikazuya b97e366
feat: リアーキ
umekikazuya 102bfc9
Merge branch 'develop' into refactor/front-context
umekikazuya db98466
refactor: 責務見直し
umekikazuya 4d30a99
feat: コンポーネント設計を見直し
umekikazuya 12f9307
feat: コンポーネント設計
umekikazuya e39866b
feat: レイヤ設計を見直し
umekikazuya a94647a
fix: フォーマット設定
umekikazuya 2cac241
fix: レビュー対応
umekikazuya 1248d41
feat: コンポーネント設計
umekikazuya bd5c0fb
feat: コンポーネント設計
umekikazuya File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 148 additions & 0 deletions
148
frontend/src/components/admin/profile/me-profile-certifications-editor.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| import { css, html, LitElement } from 'lit' | ||
| import { customElement, property } from 'lit/decorators.js' | ||
| import { adminFormStyles } from '../../../admin/admin-form-styles.js' | ||
| import type { MeCertification } from '../../../admin/types.js' | ||
| import '../ui/me-admin-panel.js' | ||
| import '../ui/me-admin-section.js' | ||
| import '../ui/me-text-input.js' | ||
|
|
||
| @customElement('me-profile-certifications-editor') | ||
| export class MeProfileCertificationsEditor extends LitElement { | ||
| @property({ type: Array }) certifications: MeCertification[] = [] | ||
|
|
||
| private dispatchChange(next: MeCertification[]) { | ||
| this.dispatchEvent( | ||
| new CustomEvent<MeCertification[]>('change', { | ||
| detail: next, | ||
| bubbles: true, | ||
| composed: true, | ||
| }), | ||
| ) | ||
| } | ||
|
|
||
| private addItem = () => { | ||
| const next = [ | ||
| ...this.certifications, | ||
| { name: '', issuer: '', year: new Date().getFullYear() }, | ||
| ] | ||
| this.dispatchChange(next) | ||
| } | ||
|
|
||
| private removeItem(index: number) { | ||
| const next = this.certifications.filter((_, i) => i !== index) | ||
| this.dispatchChange(next) | ||
| } | ||
|
|
||
| private updateItem(index: number, patch: Partial<MeCertification>) { | ||
| const next = [...this.certifications] | ||
| next[index] = { ...next[index], ...patch } | ||
| this.dispatchChange(next) | ||
| } | ||
|
|
||
| render() { | ||
| return html` | ||
| <me-admin-section | ||
| title="Certifications" | ||
| description="month は任意です。年だけでも掲載できます。" | ||
| > | ||
| <button | ||
| slot="header-actions" | ||
| type="button" | ||
| class="subtle" | ||
| @click=${this.addItem} | ||
| > | ||
| 資格を追加 | ||
| </button> | ||
|
|
||
| <div class="stack"> | ||
| ${ | ||
| this.certifications.length === 0 | ||
| ? html`<p class="empty-text">資格がまだありません。</p>` | ||
| : this.certifications.map( | ||
| (cert, index) => html` | ||
| <me-admin-panel title="資格 ${index + 1}"> | ||
| <button | ||
| slot="header-actions" | ||
| type="button" | ||
| class="subtle danger" | ||
| @click=${() => this.removeItem(index)} | ||
| > | ||
| 削除 | ||
| </button> | ||
|
|
||
| <div class="grid"> | ||
| <me-text-input | ||
| label="資格名" | ||
| .value=${cert.name} | ||
| @change=${(e: CustomEvent) => | ||
| this.updateItem(index, { name: e.detail })} | ||
| ></me-text-input> | ||
|
|
||
| <me-text-input | ||
| label="Issuer" | ||
| .value=${cert.issuer} | ||
| @change=${(e: CustomEvent) => | ||
| this.updateItem(index, { issuer: e.detail })} | ||
| ></me-text-input> | ||
|
|
||
| <me-text-input | ||
| label="Year" | ||
| type="number" | ||
| .value=${String(cert.year)} | ||
| @change=${(e: CustomEvent) => | ||
| this.updateItem(index, { | ||
| year: Number(e.detail || '0'), | ||
| })} | ||
| ></me-text-input> | ||
|
|
||
| <me-text-input | ||
| label="Month" | ||
| type="number" | ||
| .value=${cert.month ? String(cert.month) : ''} | ||
| @change=${(e: CustomEvent) => | ||
| this.updateItem(index, { | ||
| month: e.detail ? Number(e.detail) : undefined, | ||
| })} | ||
| ></me-text-input> | ||
| </div> | ||
| </me-admin-panel> | ||
| `, | ||
| ) | ||
| } | ||
| </div> | ||
| </me-admin-section> | ||
| ` | ||
| } | ||
|
|
||
| static styles = [ | ||
| adminFormStyles, | ||
| css` | ||
| :host { | ||
| display: block; | ||
| } | ||
|
|
||
| .stack { | ||
| display: grid; | ||
| gap: 20px; | ||
| } | ||
|
|
||
| .grid { | ||
| display: grid; | ||
| gap: 16px; | ||
| grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); | ||
| } | ||
|
|
||
| .empty-text { | ||
| color: var(--color-text-tertiary); | ||
| font-size: 14px; | ||
| font-style: italic; | ||
| } | ||
| `, | ||
| ] | ||
| } | ||
|
|
||
| declare global { | ||
| interface HTMLElementTagNameMap { | ||
| 'me-profile-certifications-editor': MeProfileCertificationsEditor | ||
| } | ||
| } | ||
149 changes: 149 additions & 0 deletions
149
frontend/src/components/admin/profile/me-profile-experiences-editor.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| import { css, html, LitElement } from 'lit' | ||
| import { customElement, property } from 'lit/decorators.js' | ||
| import { adminFormStyles } from '../../../admin/admin-form-styles.js' | ||
| import type { MeExperience } from '../../../admin/types.js' | ||
| import '../ui/me-admin-panel.js' | ||
| import '../ui/me-admin-section.js' | ||
| import '../ui/me-text-input.js' | ||
|
|
||
| @customElement('me-profile-experiences-editor') | ||
| export class MeProfileExperiencesEditor extends LitElement { | ||
| @property({ type: Array }) experiences: MeExperience[] = [] | ||
|
|
||
| private dispatchChange(next: MeExperience[]) { | ||
| this.dispatchEvent( | ||
| new CustomEvent<MeExperience[]>('change', { | ||
| detail: next, | ||
| bubbles: true, | ||
| composed: true, | ||
| }), | ||
| ) | ||
| } | ||
|
|
||
| private addItem = () => { | ||
| const next = [ | ||
| ...this.experiences, | ||
| { company: '', url: '', startYear: new Date().getFullYear() }, | ||
| ] | ||
| this.dispatchChange(next) | ||
| } | ||
|
|
||
| private removeItem(index: number) { | ||
| const next = this.experiences.filter((_, i) => i !== index) | ||
| this.dispatchChange(next) | ||
| } | ||
|
|
||
| private updateItem(index: number, patch: Partial<MeExperience>) { | ||
| const next = [...this.experiences] | ||
| next[index] = { ...next[index], ...patch } | ||
| this.dispatchChange(next) | ||
| } | ||
|
|
||
| render() { | ||
| return html` | ||
| <me-admin-section | ||
| title="Experiences" | ||
| description="endYear を空にすると、継続中の経歴として扱えます。" | ||
| > | ||
| <button | ||
| slot="header-actions" | ||
| type="button" | ||
| class="subtle" | ||
| @click=${this.addItem} | ||
| > | ||
| 経歴を追加 | ||
| </button> | ||
|
|
||
| <div class="stack"> | ||
| ${ | ||
| this.experiences.length === 0 | ||
| ? html`<p class="empty-text">経歴がまだありません。</p>` | ||
| : this.experiences.map( | ||
| (exp, index) => html` | ||
| <me-admin-panel title="経歴 ${index + 1}"> | ||
| <button | ||
| slot="header-actions" | ||
| type="button" | ||
| class="subtle danger" | ||
| @click=${() => this.removeItem(index)} | ||
| > | ||
| 削除 | ||
| </button> | ||
|
|
||
| <div class="grid"> | ||
| <me-text-input | ||
| label="Company" | ||
| .value=${exp.company} | ||
| @change=${(e: CustomEvent) => | ||
| this.updateItem(index, { company: e.detail })} | ||
| ></me-text-input> | ||
|
|
||
| <me-text-input | ||
| label="URL" | ||
| type="url" | ||
| .value=${exp.url} | ||
| @change=${(e: CustomEvent) => | ||
| this.updateItem(index, { url: e.detail })} | ||
| ></me-text-input> | ||
|
|
||
| <me-text-input | ||
| label="Start year" | ||
| type="number" | ||
| .value=${String(exp.startYear)} | ||
| @change=${(e: CustomEvent) => | ||
| this.updateItem(index, { | ||
| startYear: Number(e.detail || '0'), | ||
| })} | ||
| ></me-text-input> | ||
|
Comment on lines
+108
to
+116
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. startYearが空の場合に0が設定されます。
🛡️ 修正案 <me-text-input
label="Start year"
type="number"
.value=${String(exp.startYear)}
`@change`=${(e: CustomEvent) =>
this.updateItem(index, {
- startYear: Number(e.detail || '0'),
+ startYear: e.detail ? Number(e.detail) : new Date().getFullYear(),
})}
></me-text-input>🤖 Prompt for AI Agents |
||
|
|
||
| <me-text-input | ||
| label="End year" | ||
| type="number" | ||
| .value=${exp.endYear ? String(exp.endYear) : ''} | ||
| @change=${(e: CustomEvent) => | ||
| this.updateItem(index, { | ||
| endYear: e.detail ? Number(e.detail) : undefined, | ||
| })} | ||
| ></me-text-input> | ||
| </div> | ||
| </me-admin-panel> | ||
| `, | ||
| ) | ||
| } | ||
| </div> | ||
| </me-admin-section> | ||
| ` | ||
| } | ||
|
|
||
| static styles = [ | ||
| adminFormStyles, | ||
| css` | ||
| :host { | ||
| display: block; | ||
| } | ||
|
|
||
| .stack { | ||
| display: grid; | ||
| gap: 20px; | ||
| } | ||
|
|
||
| .grid { | ||
| display: grid; | ||
| gap: 16px; | ||
| grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); | ||
| } | ||
|
|
||
| .empty-text { | ||
| color: var(--color-text-tertiary); | ||
| font-size: 14px; | ||
| font-style: italic; | ||
| } | ||
| `, | ||
| ] | ||
| } | ||
|
|
||
| declare global { | ||
| interface HTMLElementTagNameMap { | ||
| 'me-profile-experiences-editor': MeProfileExperiencesEditor | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
年が空の場合に0が設定される可能性があります。
e.detail || '0'により、ユーザーが年を空にした場合にyear: 0が設定されます。これは意図した動作でしょうか?バリデーションエラーとして扱うか、undefinedを許容する方が適切かもしれません。🛡️ 修正案: 空の場合は現在年をフォールバックとして使用
<me-text-input label="Year" type="number" .value=${String(cert.year)} `@change`=${(e: CustomEvent) => this.updateItem(index, { - year: Number(e.detail || '0'), + year: e.detail ? Number(e.detail) : new Date().getFullYear(), })} ></me-text-input>📝 Committable suggestion
🤖 Prompt for AI Agents