@@ -9,6 +9,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
99import { MatFormFieldModule } from '@angular/material/form-field' ;
1010import { MatInputModule } from '@angular/material/input' ;
1111import { MatTooltipModule } from '@angular/material/tooltip' ;
12+ import { MatSelectModule } from '@angular/material/select' ;
1213import { FormsModule } from '@angular/forms' ;
1314import { AdminService , ApiDoc } from '../../services/admin.service' ;
1415
@@ -26,22 +27,37 @@ import { AdminService, ApiDoc } from '../../services/admin.service';
2627 MatFormFieldModule ,
2728 MatInputModule ,
2829 MatTooltipModule ,
30+ MatSelectModule ,
2931 FormsModule
3032 ] ,
3133 template : `
3234 <div class="p-6 bg-md-sys-color-surface min-h-screen max-w-6xl mx-auto">
3335 <h1 class="md-typescale-headline-large text-md-sys-color-on-surface mb-6">API 문서</h1>
3436
3537 <div class="flex flex-col md:flex-row gap-4 mb-6">
36- <div class="flex-1 max-w-md">
37- <div class="relative">
38- <input
39- type="text"
40- [(ngModel)]="searchTerm"
41- (input)="filterApis()"
42- placeholder="경로나 설명으로 검색..."
43- class="w-full p-3 pr-12 bg-md-sys-color-surface-container-highest text-md-sys-color-on-surface rounded-xl border border-md-sys-color-outline focus:border-md-sys-color-primary focus:outline-none md-typescale-body-large">
44- <mat-icon class="w-5 h-5 absolute right-3 top-1/2 transform -translate-y-1/2 text-md-sys-color-on-surface-variant">search</mat-icon>
38+ <div class="flex flex-col md:flex-row gap-4 flex-1">
39+ <div class="flex-1 max-w-md">
40+ <div class="relative">
41+ <input
42+ type="text"
43+ [(ngModel)]="searchTerm"
44+ (input)="filterApis()"
45+ placeholder="경로나 설명으로 검색..."
46+ class="w-full p-3 pr-12 bg-md-sys-color-surface-container-highest text-md-sys-color-on-surface rounded-xl border border-md-sys-color-outline focus:border-md-sys-color-primary focus:outline-none md-typescale-body-large">
47+ <mat-icon class="w-5 h-5 absolute right-3 top-1/2 transform -translate-y-1/2 text-md-sys-color-on-surface-variant">search</mat-icon>
48+ </div>
49+ </div>
50+
51+ <div class="w-full md:w-48">
52+ <mat-form-field appearance="outline" class="w-full">
53+ <mat-label>파일 필터</mat-label>
54+ <mat-select [(value)]="selectedFile" (selectionChange)="filterApis()">
55+ <mat-option value="">모든 파일</mat-option>
56+ <mat-option *ngFor="let file of getUniqueFiles()" [value]="file">
57+ {{ file }}
58+ </mat-option>
59+ </mat-select>
60+ </mat-form-field>
4561 </div>
4662 </div>
4763
@@ -101,7 +117,7 @@ import { AdminService, ApiDoc } from '../../services/admin.service';
101117 <div class="grid grid-cols-1 md:grid-cols-3 gap-4 p-4 bg-md-sys-color-surface-container-high rounded-xl">
102118 <div class="flex items-center gap-2">
103119 <span class="md-typescale-body-medium font-medium text-md-sys-color-on-surface-variant">파일:</span>
104- <span class="font-mono md-typescale-body-medium text-md-sys-color-on-surface">{{ doc.file }}.mjs </span>
120+ <span class="font-mono md-typescale-body-medium text-md-sys-color-on-surface">{{ doc.file }}</span>
105121 </div>
106122 <div class="flex items-center gap-2">
107123 <span class="md-typescale-body-medium font-medium text-md-sys-color-on-surface-variant">메소드:</span>
@@ -128,7 +144,7 @@ import { AdminService, ApiDoc } from '../../services/admin.service';
128144 <div *ngFor="let routeParam of doc.routeParams" class="p-3 bg-md-sys-color-primary-container rounded-lg">
129145 <div class="flex items-start justify-between mb-2">
130146 <div class="flex items-center gap-2">
131- <code class="px-2 py-1 bg-md-sys-color-surface-container rounded text-sm font-mono text-md-sys-color-on-surface">: {{ routeParam.name }}</code>
147+ <code class="px-2 py-1 bg-md-sys-color-surface-container rounded text-sm font-mono text-md-sys-color-on-surface">{{ routeParam.name }}</code>
132148 <span class="px-2 py-1 rounded-full text-xs bg-md-sys-color-error-container text-md-sys-color-on-error-container">필수</span>
133149 </div>
134150 <span class="text-sm font-mono text-md-sys-color-on-primary-container">{{ routeParam.type }}</span>
@@ -226,6 +242,7 @@ export class ApiDocsComponent implements OnInit {
226242 apiDocs : ApiDoc [ ] = [ ] ;
227243 filteredDocs : ApiDoc [ ] = [ ] ;
228244 searchTerm = '' ;
245+ selectedFile = '' ;
229246 loading = false ;
230247
231248 constructor ( private adminService : AdminService ) { }
@@ -234,6 +251,11 @@ export class ApiDocsComponent implements OnInit {
234251 this . loadApiDocs ( ) ;
235252 }
236253
254+ getUniqueFiles ( ) : string [ ] {
255+ const files = [ ...new Set ( this . apiDocs . map ( doc => doc . file ) ) ] ;
256+ return files . sort ( ) ;
257+ }
258+
237259
238260 loadApiDocs ( ) {
239261 this . loading = true ;
@@ -258,26 +280,33 @@ export class ApiDocsComponent implements OnInit {
258280 }
259281
260282 filterApis ( ) {
261- if ( ! this . searchTerm . trim ( ) ) {
262- this . filteredDocs = [ ...this . apiDocs ] ;
263- return ;
283+ let filtered = [ ...this . apiDocs ] ;
284+
285+ // File filter
286+ if ( this . selectedFile ) {
287+ filtered = filtered . filter ( doc => doc . file === this . selectedFile ) ;
288+ }
289+
290+ // Search term filter
291+ if ( this . searchTerm . trim ( ) ) {
292+ const term = this . searchTerm . toLowerCase ( ) ;
293+ filtered = filtered . filter ( doc =>
294+ doc . path . toLowerCase ( ) . includes ( term ) ||
295+ doc . name . toLowerCase ( ) . includes ( term ) ||
296+ doc . method . toLowerCase ( ) . includes ( term ) ||
297+ doc . file . toLowerCase ( ) . includes ( term ) ||
298+ ( doc . params && doc . params . some ( param =>
299+ param . name . toLowerCase ( ) . includes ( term ) ||
300+ param . description . toLowerCase ( ) . includes ( term )
301+ ) ) ||
302+ ( doc . routeParams && doc . routeParams . some ( routeParam =>
303+ routeParam . name . toLowerCase ( ) . includes ( term ) ||
304+ routeParam . description . toLowerCase ( ) . includes ( term )
305+ ) )
306+ ) ;
264307 }
265308
266- const term = this . searchTerm . toLowerCase ( ) ;
267- this . filteredDocs = this . apiDocs . filter ( doc =>
268- doc . path . toLowerCase ( ) . includes ( term ) ||
269- doc . name . toLowerCase ( ) . includes ( term ) ||
270- doc . method . toLowerCase ( ) . includes ( term ) ||
271- doc . file . toLowerCase ( ) . includes ( term ) ||
272- ( doc . params && doc . params . some ( param =>
273- param . name . toLowerCase ( ) . includes ( term ) ||
274- param . description . toLowerCase ( ) . includes ( term )
275- ) ) ||
276- ( doc . routeParams && doc . routeParams . some ( routeParam =>
277- routeParam . name . toLowerCase ( ) . includes ( term ) ||
278- routeParam . description . toLowerCase ( ) . includes ( term )
279- ) )
280- ) ;
309+ this . filteredDocs = filtered ;
281310 }
282311
283312 refreshDocs ( ) {
0 commit comments