Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
dtd
/
civitas.ui
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 07e41be4
authored
Apr 22, 2025
by
Nabiilah Putri Safa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
edit app view
1 parent
f645776c
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
410 additions
and
130 deletions
views/dstipro/beranda/profile/DosenApp.vue
views/dstipro/beranda/profile/StudentApp.vue
views/dstipro/beranda/profile/DosenApp.vue
View file @
07e41be
...
...
@@ -13,6 +13,17 @@ const applicationTableHeaders = [
{
title
:
'Link'
,
key
:
'link'
},
]
const
viewMode
=
ref
(
'grid'
);
// Set default to 'grid'
const
itemsPerPage
=
ref
(
8
)
// Default rows per page
const
page
=
ref
(
1
)
// Default page number
const
paginatedApplications
=
computed
(()
=>
{
const
start
=
(
page
.
value
-
1
)
*
itemsPerPage
.
value
return
filteredApplications
.
value
.
slice
(
start
,
start
+
itemsPerPage
.
value
)
})
const
applications
=
[
{
logo
:
react
,
...
...
@@ -79,8 +90,29 @@ const filteredApplications = computed(() => {
</
script
>
<
template
>
<VCard
title=
"List Aplikasi untuk Dosen"
class=
"projectList"
>
<!-- 👉 User Project List Table -->
<VCard
class=
"projectList"
>
<!-- Custom Header -->
<div
class=
"d-flex justify-space-between align-center pa-4"
>
<div
class=
"text-h5"
>
List Aplikasi untuk Dosen
</div>
<div
class=
"d-flex gap-2"
>
<VBtn
icon
variant=
"text"
:color=
"viewMode === 'grid' ? 'primary' : 'default'"
@
click=
"viewMode = 'grid'"
>
<VIcon
icon=
"ri-layout-grid-line"
/>
</VBtn>
<VBtn
icon
variant=
"text"
:color=
"viewMode === 'horizontal' ? 'primary' : 'default'"
@
click=
"viewMode = 'horizontal'"
>
<VIcon
icon=
"ri-layout-horizontal-line"
/>
</VBtn>
</div>
</div>
<!-- Search Input -->
<div
class=
"search-container mb-4 pl-2 pr-2"
>
...
...
@@ -89,38 +121,97 @@ const filteredApplications = computed(() => {
clearable
@
click:clear=
"searchQuery = ''"
single-line
hide-details
dense
outlined
/>
</div>
<!-- SECTION Datatable -->
<VDataTable
:headers=
"applicationTableHeaders"
:items=
"filteredApplications"
hide-default-footer
fixed-header
item-value=
"name"
>
<!-- application -->
<template
#
item
.
application=
"
{ item }">
<div
class=
"d-flex align-center gap-x-3"
>
<VAvatar
:size=
"34"
:image=
"item.logo"
/>
<div>
<h6
class=
"text-h6 text-no-wrap"
>
{{
item
.
name
}}
</h6>
<div
class=
"text-body-2"
>
{{
item
.
nameShort
}}
<!-- Search Input -->
<!-- Grid View -->
<VRow
v-if=
"viewMode === 'grid'"
class=
"app-grid"
>
<VCol
v-for=
"app in paginatedApplications"
:key=
"app.name"
cols=
"12"
sm=
"6"
md=
"3"
>
<VCard
class=
"app-card"
:href=
"app.link"
target=
"_blank"
rel=
"noopener"
>
<VImg
:src=
"app.logo"
class=
"app-image"
/>
<VCardText
class=
"app-text"
>
<a
:href=
"app.link"
target=
"_blank"
class=
"app-link"
>
{{
app
.
link
}}
>
</a>
<div
class=
"app-short"
>
{{
app
.
nameShort
}}
</div>
<div
class=
"app-name"
>
{{
app
.
name
}}
</div>
</VCardText>
</VCard>
</VCol>
</VRow>
<!-- SECTION Datatable -->
<VDataTable
v-if=
"viewMode === 'horizontal'"
:headers=
"applicationTableHeaders"
:items=
"paginatedApplications"
hide-default-footer
fixed-header
item-value=
"name"
>
<!-- application -->
<template
#
item
.
application=
"
{ item }">
<div
class=
"d-flex align-center gap-x-3"
>
<VAvatar
:size=
"34"
:image=
"item.logo"
/>
<div>
<h6
class=
"text-h6 text-no-wrap"
>
{{
item
.
name
}}
</h6>
<div
class=
"text-body-2"
>
{{
item
.
nameShort
}}
</div>
</div>
</div>
</div>
</div>
</
template
>
<!-- link -->
<
template
#
item
.
link=
"{ item }"
>
<div
class=
"d-flex align-center gap-3"
>
<div
class=
"text-high-emphasis"
>
<a
:href=
"item.link"
target=
"_blank"
rel=
"noopener"
>
{{
item
.
link
}}
</a>
</div>
</div>
</
template
>
<!-- TODO Refactor this after vuetify provides proper solution for removing default footer -->
<
template
#
bottom
/>
</VDataTable>
<!-- !SECTION -->
</
template
>
<!-- link -->
<
template
#
item
.
link=
"{ item }"
>
<div
class=
"d-flex align-center gap-3"
>
<div
class=
"text-high-emphasis"
>
<a
:href=
"item.link"
target=
"_blank"
rel=
"noopener"
>
{{
item
.
link
}}
</a>
</div>
</div>
</
template
>
<!-- TODO Refactor this after vuetify provides proper solution for removing default footer -->
<
template
#
bottom
/>
</VDataTable>
<!-- !SECTION -->
<div
class=
"pagination-container pt-4 px-4 mb-7"
>
<div
class=
"d-flex flex-wrap align-center justify-space-between gap-4"
>
<VSelect
v-model=
"itemsPerPage"
:items=
"[4, 8, 16, 32]"
label=
"Rows per page:"
variant=
"underlined"
density=
"comfortable"
style=
"max-width: 10rem;"
/>
<VPagination
v-model=
"page"
:total-visible=
"5"
:length=
"Math.ceil(filteredApplications.length / itemsPerPage)"
/>
</div>
</div>
</VCard>
</
template
>
...
...
@@ -147,4 +238,76 @@ const filteredApplications = computed(() => {
display
:
flex
;
justify-content
:
flex-end
;
}
.content-container
{
padding-block
:
0
20px
;
padding-inline
:
20px
;
/* No padding on top */
}
.project-list
{
padding
:
0
;
}
.search-container
{
display
:
flex
;
justify-content
:
flex-end
;
margin-block-end
:
20px
;
}
.app-card
{
display
:
flex
;
overflow
:
hidden
;
flex-direction
:
column
;
block-size
:
100%
;
cursor
:
pointer
;
transition
:
transform
0.2s
ease-in-out
;
}
.app-card
:hover
{
transform
:
scale
(
1.02
);
}
.app-image
{
overflow
:
hidden
;
inline-size
:
100%
;
max-block-size
:
100px
;
object-fit
:
cover
;
}
.app-text
{
display
:
flex
;
flex-direction
:
column
;
flex-grow
:
1
;
justify-content
:
space-between
;
padding-block
:
8px
;
padding-inline
:
12px
;
}
.app-link
{
display
:
block
;
color
:
rgb
(
var
(
--v-global-theme-primary
));
font-size
:
14px
;
text-decoration
:
none
;
}
.app-name
{
overflow
:
hidden
;
color
:
gray
;
font-size
:
14px
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.app-card
:hover
.app-name
{
overflow
:
visible
;
text-overflow
:
unset
;
white-space
:
normal
;
}
.app-short
{
font-size
:
16px
;
font-weight
:
bold
;
margin-block-start
:
4px
;
}
</
style
>
views/dstipro/beranda/profile/StudentApp.vue
View file @
07e41be
...
...
@@ -6,123 +6,240 @@ import react from '@images/icons/project-icons/react.png'
import
sketch
from
'@images/icons/project-icons/sketch.png'
import
vue
from
'@images/icons/project-icons/vue.png'
import
xamarin
from
'@images/icons/project-icons/xamarin.png'
import
{
computed
,
ref
}
from
'vue'
const
applications
=
[
{
logo
:
react
,
name
:
'Human Resource Information System Universitas Indonesia'
,
nameShort
:
'HRIS UI'
,
link
:
'https://hris.ui.ac.id/'
},
{
logo
:
figma
,
name
:
'Sistem Informasi Akademik NextGeneration'
,
nameShort
:
'SIAKNG'
,
link
:
'https://academic.ui.ac.id/'
},
{
logo
:
figma
,
name
:
'E-learning Management System'
,
nameShort
:
'EMAS-2'
,
link
:
'https://emas2.ui.ac.id/'
},
{
logo
:
vue
,
name
:
'Dashboard App'
,
nameShort
:
'Vuejs Project'
,
link
:
'#'
},
{
logo
:
xamarin
,
name
:
'Foodista mobile app'
,
nameShort
:
'Xamarin Project'
,
link
:
'#'
},
{
logo
:
python
,
name
:
'Dojo Email App'
,
nameShort
:
'Python Project'
,
link
:
'#'
},
{
logo
:
sketch
,
name
:
'Blockchain App'
,
nameShort
:
'Sketch Project'
,
link
:
'#'
},
{
logo
:
html5
,
name
:
'Hoffman App'
,
nameShort
:
'HTML Project'
,
link
:
'#'
},
// Project Table Header
const
applicationTableHeaders
=
[
{
title
:
'UI App'
,
key
:
'application'
},
{
title
:
'Link'
,
key
:
'link'
},
]
const
searchQuery
=
ref
(
''
)
const
viewMode
=
ref
(
'grid'
);
// Set default to 'grid'
const
itemsPerPage
=
ref
(
8
)
// Default rows per page
const
page
=
ref
(
1
)
// Default page number
// Filtered applications based on search query
const
filteredApplications
=
computed
(()
=>
{
const
query
=
searchQuery
.
value
.
toLowerCase
()
return
applications
.
filter
(
app
=>
[
app
.
name
,
app
.
nameShort
,
app
.
link
].
some
(
field
=>
field
.
toLowerCase
().
includes
(
query
),
),
)
})
// Paginate the filtered applications
const
paginatedApplications
=
computed
(()
=>
{
const
start
=
(
page
.
value
-
1
)
*
itemsPerPage
.
value
return
filteredApplications
.
value
.
slice
(
start
,
start
+
itemsPerPage
.
value
)
})
const
applications
=
[
{
logo
:
react
,
name
:
'Human Resource Information System Universitas Indonesia'
,
nameShort
:
'HRIS UI'
,
link
:
'https://hris.ui.ac.id/'
,
},
{
logo
:
figma
,
name
:
'Sistem Informasi Akademik NextGeneration'
,
nameShort
:
'SIAKNG'
,
link
:
'https://academic.ui.ac.id/'
,
},
{
logo
:
figma
,
name
:
'E-learning Management System'
,
nameShort
:
'EMAS-2'
,
link
:
'https://emas2.ui.ac.id/'
,
},
{
logo
:
vue
,
name
:
'Dashboard App'
,
nameShort
:
'Vuejs Project'
,
link
:
'#'
,
},
{
logo
:
xamarin
,
name
:
'Foodista mobile app'
,
nameShort
:
'Xamarin Project'
,
link
:
'#'
,
},
{
logo
:
python
,
name
:
'Dojo Email App'
,
nameShort
:
'Python Project'
,
link
:
'#'
,
},
{
logo
:
sketch
,
name
:
'Blockchain App'
,
nameShort
:
'Sketch Project'
,
link
:
'#'
,
},
{
logo
:
html5
,
name
:
'Hoffman App'
,
nameShort
:
'HTML Project'
,
link
:
'#'
,
},
]
// Search query state
const
searchQuery
=
ref
(
''
);
// Filter aplikasi berdasarkan pencarian
const
filteredApplications
=
computed
(()
=>
{
const
query
=
searchQuery
.
value
.
toLowerCase
();
return
applications
.
filter
((
app
)
=>
[
app
.
name
,
app
.
nameShort
,
app
.
link
].
some
((
field
)
=>
field
.
toLowerCase
().
includes
(
query
)
)
);
});
</
script
>
<
template
>
<VCard
title=
"List Aplikasi untuk Mahasiswa"
class=
"project-list"
>
<div
class=
"content-container"
>
<!-- Search Input -->
<div
class=
"search-container"
>
<VTextField
v-model=
"searchQuery"
label=
"Search"
placeholder=
"Search ..."
append-inner-icon=
"ri-search-line"
clearable
single-line
hide-details
dense
outlined
@
click:clear=
"searchQuery = ''"
/>
</div>
<!-- Applications Grid -->
<VRow
class=
"app-grid"
>
<VCol
v-for=
"app in paginatedApplications"
:key=
"app.name"
cols=
"12"
sm=
"6"
md=
"3"
>
<VCard
class=
"app-card"
:href=
"app.link"
target=
"_blank"
rel=
"noopener"
<VCard
class=
"projectList"
>
<!-- Custom Header -->
<div
class=
"d-flex justify-space-between align-center pa-4"
>
<div
class=
"text-h5"
>
List Aplikasi untuk Mahasiswa
</div>
<div
class=
"d-flex gap-2"
>
<VBtn
icon
variant=
"text"
:color=
"viewMode === 'grid' ? 'primary' : 'default'"
@
click=
"viewMode = 'grid'"
>
<VIcon
icon=
"ri-layout-grid-line"
/>
</VBtn>
<VBtn
icon
variant=
"text"
:color=
"viewMode === 'horizontal' ? 'primary' : 'default'"
@
click=
"viewMode = 'horizontal'"
>
<VIcon
icon=
"ri-layout-horizontal-line"
/>
</VBtn>
</div>
</div>
<!-- Search Input -->
<div
class=
"search-container mb-4 pl-2 pr-2"
>
<!--
<VTextField
v-model=
"searchQuery"
label=
"Search"
clearable
variant=
"outlined"
density=
"comfortable"
/>
-->
<VTextField
v-model=
"searchQuery"
label=
"Search"
placeholder=
"Search ..."
append-inner-icon=
"ri-search-line"
clearable
@
click:clear=
"searchQuery = ''"
single-line
hide-details
dense
outlined
/>
</div>
<!-- Search Input -->
<!-- Grid View -->
<VRow
v-if=
"viewMode === 'grid'"
class=
"app-grid"
>
<VCol
v-for=
"app in paginatedApplications"
:key=
"app.name"
cols=
"12"
sm=
"6"
md=
"3"
>
<VImg
:src=
"app.logo"
class=
"app-image"
/>
<VCardText
class=
"app-text"
>
<a
:href=
"app.link"
target=
"_blank"
class=
"app-link"
>
{{
app
.
link
}}
>
</a>
<div
class=
"app-short"
>
{{
app
.
nameShort
}}
<VCard
class=
"app-card"
:href=
"app.link"
target=
"_blank"
rel=
"noopener"
>
<VImg
:src=
"app.logo"
class=
"app-image"
/>
<VCardText
class=
"app-text"
>
<a
:href=
"app.link"
target=
"_blank"
class=
"app-link"
>
{{
app
.
link
}}
>
</a>
<div
class=
"app-short"
>
{{
app
.
nameShort
}}
</div>
<div
class=
"app-name"
>
{{
app
.
name
}}
</div>
</VCardText>
</VCard>
</VCol>
</VRow>
<!-- SECTION Datatable -->
<VDataTable
v-if=
"viewMode === 'horizontal'"
:headers=
"applicationTableHeaders"
:items=
"paginatedApplications"
hide-default-footer
fixed-header
item-value=
"name"
>
<!-- application -->
<template
#
item
.
application=
"
{ item }">
<div
class=
"d-flex align-center gap-x-3"
>
<VAvatar
:size=
"34"
:image=
"item.logo"
/>
<div>
<h6
class=
"text-h6 text-no-wrap"
>
{{
item
.
name
}}
</h6>
<div
class=
"text-body-2"
>
{{
item
.
nameShort
}}
</div>
</div>
<div
class=
"app-name"
>
{{
app
.
name
}}
</div>
</
template
>
<!-- link -->
<
template
#
item
.
link=
"{ item }"
>
<div
class=
"d-flex align-center gap-3"
>
<div
class=
"text-high-emphasis"
>
<a
:href=
"item.link"
target=
"_blank"
rel=
"noopener"
>
{{
item
.
link
}}
</a>
</div>
</VCardText>
</VCard>
</VCol>
</VRow>
<!-- Pagination Controls -->
<div
class=
"pt-2"
>
<div
class=
"d-flex flex-wrap justify-center justify-sm-space-between gap-y-2 mt-2"
>
<VSelect
v-model=
"itemsPerPage"
:items=
"[4, 8, 16, 32]"
label=
"Rows per page:"
variant=
"underlined"
style=
"max-inline-size: 8rem; min-inline-size: 5rem;"
/>
<VPagination
v-model=
"page"
:total-visible=
"3"
:length=
"Math.ceil(filteredApplications.length / itemsPerPage)"
/>
</div>
</div>
</div>
</div>
</
template
>
<!-- TODO Refactor this after vuetify provides proper solution for removing default footer -->
<
template
#
bottom
/>
</VDataTable>
<!-- !SECTION -->
<div
class=
"pagination-container pt-4 px-4 mb-7"
>
<div
class=
"d-flex flex-wrap align-center justify-space-between gap-4"
>
<VSelect
v-model=
"itemsPerPage"
:items=
"[4, 8, 16, 32]"
label=
"Rows per page:"
variant=
"underlined"
density=
"comfortable"
style=
"max-width: 10rem;"
/>
<VPagination
v-model=
"page"
:total-visible=
"5"
:length=
"Math.ceil(filteredApplications.length / itemsPerPage)"
/>
</div>
</div>
</VCard>
</
template
>
<
style
scoped
>
<
style
lang=
"scss"
>
.projectList
{
.v-table
{
&--density-default
{
.v-table__wrapper
{
table
{
tbody
{
tr
{
td
{
block-size
:
56px
;
}
}
}
}
}
}
}
}
.search-container
{
display
:
flex
;
justify-content
:
flex-end
;
}
.content-container
{
padding-block
:
0
20px
;
padding-inline
:
20px
;
/* No padding on top */
...
...
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment