Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
portal-apps-manage
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
angular
portal-apps-manage
Commits
419bf0fc
Commit
419bf0fc
authored
Sep 26, 2025
by
sawit
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Permission Management จัดการสิทธิ์พนักงาน และแอป
parent
1d223776
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
3340 additions
and
261 deletions
+3340
-261
permission-appmodule.component.css
...t/permission-appmodule/permission-appmodule.component.css
+1314
-0
permission-appmodule.component.html
.../permission-appmodule/permission-appmodule.component.html
+64
-0
permission-appmodule.component.spec.ts
...rmission-appmodule/permission-appmodule.component.spec.ts
+28
-0
permission-appmodule.component.ts
...nt/permission-appmodule/permission-appmodule.component.ts
+219
-0
permission-employeelist.component.html
...ssion-employeelist/permission-employeelist.component.html
+1
-1
permission-employeelist.component.ts
...mission-employeelist/permission-employeelist.component.ts
+0
-257
permission-menulist.component.css
...ist/permission-menulist/permission-menulist.component.css
+0
-0
permission-menulist.component.html
...st/permission-menulist/permission-menulist.component.html
+3
-0
permission-menulist.component.spec.ts
...permission-menulist/permission-menulist.component.spec.ts
+28
-0
permission-menulist.component.ts
...list/permission-menulist/permission-menulist.component.ts
+20
-0
permission-menumodule.component.css
...permission-menumodule/permission-menumodule.component.css
+1314
-0
permission-menumodule.component.html
...ermission-menumodule/permission-menumodule.component.html
+79
-0
permission-menumodule.component.spec.ts
...ission-menumodule/permission-menumodule.component.spec.ts
+28
-0
permission-menumodule.component.ts
.../permission-menumodule/permission-menumodule.component.ts
+217
-0
permission-management.routes.ts
...age/permission-management/permission-management.routes.ts
+15
-0
page-header.component.html
.../shared/components/page-header/page-header.component.html
+7
-2
page-header.component.ts
...pp/shared/components/page-header/page-header.component.ts
+2
-0
nav.service.ts
src/app/shared/services/nav.service.ts
+1
-1
No files found.
src/app/portal-manage/permission-management/permission-appmodule/permission-appmodule.component.css
0 → 100644
View file @
419bf0fc
.container
{
max-width
:
1400px
;
}
@keyframes
float
{
0
%,
100
%
{
transform
:
translateY
(
0px
)
scale
(
1
);
opacity
:
0.9
;
}
25
%
{
transform
:
translateY
(
-5px
)
scale
(
1.01
);
opacity
:
1
;
}
50
%
{
transform
:
translateY
(
-10px
)
scale
(
1.02
);
opacity
:
1
;
}
75
%
{
transform
:
translateY
(
-5px
)
scale
(
1.01
);
opacity
:
1
;
}
}
@keyframes
pulse-glow
{
0
%,
100
%
{
box-shadow
:
0
0
20px
rgba
(
99
,
102
,
241
,
0.3
);
transform
:
scale
(
1
);
opacity
:
0.8
;
}
25
%
{
box-shadow
:
0
0
25px
rgba
(
99
,
102
,
241
,
0.4
);
transform
:
scale
(
1.02
);
opacity
:
0.9
;
}
50
%
{
box-shadow
:
0
0
30px
rgba
(
99
,
102
,
241
,
0.6
);
transform
:
scale
(
1.05
);
opacity
:
1
;
}
75
%
{
box-shadow
:
0
0
25px
rgba
(
99
,
102
,
241
,
0.5
);
transform
:
scale
(
1.03
);
opacity
:
0.95
;
}
}
@keyframes
slideInFromLeft
{
0
%
{
transform
:
translateX
(
-100px
)
scale
(
0.9
);
opacity
:
0
;
}
50
%
{
transform
:
translateX
(
-20px
)
scale
(
0.95
);
opacity
:
0.5
;
}
100
%
{
transform
:
translateX
(
0
)
scale
(
1
);
opacity
:
1
;
}
}
@keyframes
slideInFromRight
{
0
%
{
transform
:
translateX
(
100px
)
scale
(
0.9
);
opacity
:
0
;
}
50
%
{
transform
:
translateX
(
20px
)
scale
(
0.95
);
opacity
:
0.5
;
}
100
%
{
transform
:
translateX
(
0
)
scale
(
1
);
opacity
:
1
;
}
}
@keyframes
fadeInScale
{
0
%
{
transform
:
scale
(
0.8
)
translateY
(
20px
);
opacity
:
0
;
}
50
%
{
transform
:
scale
(
0.95
)
translateY
(
10px
);
opacity
:
0.7
;
}
100
%
{
transform
:
scale
(
1
)
translateY
(
0
);
opacity
:
1
;
}
}
.glass-effect
{
background
:
rgba
(
255
,
255
,
255
,
0.25
);
-webkit-backdrop-filter
:
blur
(
10px
);
backdrop-filter
:
blur
(
10px
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.18
);
box-shadow
:
0
8px
32px
0
rgba
(
31
,
38
,
135
,
0.37
);
}
.group
{
animation
:
fadeInScale
0.6s
ease-out
;
&:nth-child(1)
{
animation-delay
:
0.1s
;
}
&
:nth-child
(
2
)
{
animation-delay
:
0.2s
;
}
&
:nth-child
(
3
)
{
animation-delay
:
0.3s
;
}
&
:nth-child
(
4
)
{
animation-delay
:
0.4s
;
}
&
:nth-child
(
5
)
{
animation-delay
:
0.5s
;
}
&
:nth-child
(
6
)
{
animation-delay
:
0.6s
;
}
&
:nth-child
(
7
)
{
animation-delay
:
0.7s
;
}
&
:nth-child
(
8
)
{
animation-delay
:
0.8s
;
}
}
.group
:hover
{
animation
:
float
2s
ease-in-out
infinite
;
}
.gradient-text
{
background
:
linear-gradient
(
135deg
,
#667eea
0%
,
#764ba2
100%
);
-webkit-background-clip
:
text
;
-webkit-text-fill-color
:
transparent
;
background-clip
:
text
;
}
button
{
position
:
relative
;
overflow
:
hidden
;
&::before
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
-100%
;
width
:
100%
;
height
:
100%
;
background
:
linear-gradient
(
90deg
,
transparent
,
rgba
(
255
,
255
,
255
,
0.2
),
transparent
);
transition
:
left
0.5s
;
}
&
:hover::before
{
left
:
100%
;
}
}
.bg-white
\
/
80
{
position
:
relative
;
&::before
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
background
:
linear-gradient
(
135deg
,
rgba
(
255
,
255
,
255
,
0.1
),
rgba
(
255
,
255
,
255
,
0.05
));
border-radius
:
inherit
;
pointer-events
:
none
;
}
}
.bg-gradient-to-r
{
position
:
relative
;
overflow
:
hidden
;
&::after
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
0
;
bottom
:
0
;
right
:
0
;
background
:
linear-gradient
(
90deg
,
transparent
,
rgba
(
255
,
255
,
255
,
0.2
),
transparent
);
transform
:
translateX
(
-100%
);
animation
:
shimmer
2s
infinite
;
}
}
@keyframes
shimmer
{
0
%
{
transform
:
translateX
(
-100%
);
}
100
%
{
transform
:
translateX
(
100%
);
}
}
i
{
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
}
.group
:hover
i
{
transform
:
scale
(
1.1
)
rotate
(
5deg
);
}
.inline-flex
{
position
:
relative
;
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
&:hover
{
transform
:
translateY
(
-2px
)
scale
(
1.05
);
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.15
);
}
}
.space-y-4
>
*
{
position
:
relative
;
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
&::before
{
content
:
''
;
position
:
absolute
;
left
:
0
;
top
:
0
;
bottom
:
0
;
width
:
4px
;
background
:
linear-gradient
(
to
bottom
,
#3b82f6
,
#8b5cf6
);
border-radius
:
0
2px
2px
0
;
transform
:
scaleY
(
0
);
transition
:
transform
0.3s
ease
;
}
&
:hover::before
{
transform
:
scaleY
(
1
);
}
&
:hover
{
transform
:
translateX
(
8px
);
box-shadow
:
0
10px
25px
rgba
(
0
,
0
,
0
,
0.1
);
}
}
@media
(
max-width
:
1024px
)
{
.container
{
padding
:
1.5rem
;
}
.grid
{
gap
:
1.5rem
;
}
}
@media
(
max-width
:
768px
)
{
.container
{
padding
:
1rem
;
}
.grid
{
gap
:
1rem
;
}
.text-5xl
{
font-size
:
2.5rem
;
}
.text-6xl
{
font-size
:
3rem
;
}
.text-3xl
{
font-size
:
1.875rem
;
}
.text-2xl
{
font-size
:
1.5rem
;
}
.group
{
padding
:
1.5rem
;
}
}
@media
(
max-width
:
640px
)
{
.flex.justify-between
{
flex-direction
:
column
;
align-items
:
flex-start
;
gap
:
1.5rem
;
}
.text-right
{
text-align
:
left
;
}
.grid-cols-1
{
grid-template-columns
:
1
fr
;
}
.space-y-4
>
*
{
padding
:
1rem
;
}
}
.loading
{
opacity
:
0.6
;
pointer-events
:
none
;
position
:
relative
;
&::after
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
background
:
linear-gradient
(
90deg
,
transparent
,
rgba
(
255
,
255
,
255
,
0.4
),
transparent
);
animation
:
loading
1.5s
infinite
;
}
}
@keyframes
loading
{
0
%
{
transform
:
translateX
(
-100%
);
}
100
%
{
transform
:
translateX
(
100%
);
}
}
.empty-state
{
text-align
:
center
;
padding
:
4rem
2rem
;
color
:
#6b7280
;
position
:
relative
;
&::before
{
content
:
''
;
position
:
absolute
;
top
:
50%
;
left
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
width
:
200px
;
height
:
200px
;
background
:
radial-gradient
(
circle
,
rgba
(
99
,
102
,
241
,
0.1
)
0%
,
transparent
70%
);
border-radius
:
50%
;
animation
:
pulse
2s
infinite
;
}
.text-6xl
{
font-size
:
4rem
;
margin-bottom
:
1rem
;
opacity
:
0.5
;
animation
:
float
3s
ease-in-out
infinite
;
}
}
@keyframes
pulse
{
0
%,
100
%
{
transform
:
translate
(
-50%
,
-50%
)
scale
(
1
);
opacity
:
0.7
;
}
50
%
{
transform
:
translate
(
-50%
,
-50%
)
scale
(
1.1
);
opacity
:
0.3
;
}
}
.group
:focus
{
outline
:
2px
solid
#3b82f6
;
outline-offset
:
4px
;
border-radius
:
1rem
;
}
button
:focus
{
outline
:
2px
solid
#3b82f6
;
outline-offset
:
2px
;
}
::-webkit-scrollbar
{
width
:
8px
;
}
::-webkit-scrollbar-track
{
background
:
rgba
(
0
,
0
,
0
,
0.1
);
border-radius
:
4px
;
}
::-webkit-scrollbar-thumb
{
background
:
linear-gradient
(
135deg
,
#3b82f6
,
#8b5cf6
);
border-radius
:
4px
;
transition
:
background
0.3s
ease
;
}
::-webkit-scrollbar-thumb:hover
{
background
:
linear-gradient
(
135deg
,
#2563eb
,
#7c3aed
);
}
@media
print
{
.ti-btn
,
button
{
display
:
none
;
}
.group
{
break-inside
:
avoid
;
box-shadow
:
none
;
border
:
1px
solid
#000
;
background
:
white
!important
;
}
.bg-gradient-to-r
,
.bg-gradient-to-br
{
background
:
white
!important
;
color
:
black
!important
;
}
}
@media
(
prefers-color-scheme
:
dark
)
{
.bg-white
\
/
80
{
background
:
rgba
(
31
,
41
,
55
,
0.8
);
color
:
white
;
}
.text-gray-800
{
color
:
#f9fafb
;
}
.text-gray-600
{
color
:
#d1d5db
;
}
}
@keyframes
floatUpDown
{
0
%,
100
%
{
transform
:
translateY
(
0px
)
rotate
(
0deg
)
scale
(
1
);
opacity
:
0.8
;
}
25
%
{
transform
:
translateY
(
-15px
)
rotate
(
0.5deg
)
scale
(
1.02
);
opacity
:
0.9
;
}
50
%
{
transform
:
translateY
(
-25px
)
rotate
(
1deg
)
scale
(
1.05
);
opacity
:
1
;
}
75
%
{
transform
:
translateY
(
-10px
)
rotate
(
0.5deg
)
scale
(
1.02
);
opacity
:
0.9
;
}
}
@keyframes
drift
{
0
%
{
transform
:
translateX
(
0px
)
translateY
(
0px
)
scale
(
1
);
opacity
:
0.7
;
}
25
%
{
transform
:
translateX
(
20px
)
translateY
(
-20px
)
scale
(
1.03
);
opacity
:
0.8
;
}
50
%
{
transform
:
translateX
(
35px
)
translateY
(
-35px
)
scale
(
1.05
);
opacity
:
0.9
;
}
75
%
{
transform
:
translateX
(
15px
)
translateY
(
-15px
)
scale
(
1.02
);
opacity
:
0.8
;
}
100
%
{
transform
:
translateX
(
0px
)
translateY
(
0px
)
scale
(
1
);
opacity
:
0.7
;
}
}
@keyframes
rotate
{
0
%
{
transform
:
rotate
(
0deg
)
scale
(
1
);
opacity
:
0.6
;
}
50
%
{
transform
:
rotate
(
180deg
)
scale
(
1.1
);
opacity
:
0.8
;
}
100
%
{
transform
:
rotate
(
360deg
)
scale
(
1
);
opacity
:
0.6
;
}
}
@keyframes
shimmer
{
0
%
{
background-position
:
-200%
0
;
opacity
:
0.5
;
}
50
%
{
background-position
:
0%
0
;
opacity
:
0.8
;
}
100
%
{
background-position
:
200%
0
;
opacity
:
0.5
;
}
}
@keyframes
particleFloat
{
0
%,
100
%
{
transform
:
translateY
(
0px
)
translateX
(
0px
)
scale
(
1
);
opacity
:
0.4
;
}
25
%
{
transform
:
translateY
(
-8px
)
translateX
(
3px
)
scale
(
1.05
);
opacity
:
0.7
;
}
50
%
{
transform
:
translateY
(
-12px
)
translateX
(
-2px
)
scale
(
1.1
);
opacity
:
0.9
;
}
75
%
{
transform
:
translateY
(
-6px
)
translateX
(
4px
)
scale
(
1.03
);
opacity
:
0.6
;
}
}
@keyframes
particleGlow
{
0
%,
100
%
{
box-shadow
:
0
0
5px
currentColor
;
transform
:
scale
(
1
);
}
50
%
{
box-shadow
:
0
0
20px
currentColor
,
0
0
30px
currentColor
;
transform
:
scale
(
1.1
);
}
}
.background-animations
.absolute
{
&:nth-child(1)
{
animation
:
floatUpDown
12s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
2
)
{
animation
:
drift
16s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
3
)
{
animation
:
floatUpDown
14s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
}
.background-animations
.absolute.-top-40
{
animation
:
floatUpDown
20s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
.background-animations
.absolute.top-1
\
/
2
{
animation
:
drift
24s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
.background-animations
.absolute.bottom-0
{
animation
:
floatUpDown
22s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
.background-animations
.border
{
animation
:
rotate
40s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
&:nth-child(2)
{
animation
:
rotate
35s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
3
)
{
animation
:
rotate
45s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
}
@keyframes
particleFloat
{
0
%,
100
%
{
transform
:
translateY
(
0px
)
translateX
(
0px
)
scale
(
1
);
opacity
:
0.4
;
}
25
%
{
transform
:
translateY
(
-10px
)
translateX
(
5px
)
scale
(
1.1
);
opacity
:
0.8
;
}
50
%
{
transform
:
translateY
(
-5px
)
translateX
(
-5px
)
scale
(
0.9
);
opacity
:
0.6
;
}
75
%
{
transform
:
translateY
(
-15px
)
translateX
(
3px
)
scale
(
1.05
);
opacity
:
0.7
;
}
}
@keyframes
particleGlow
{
0
%,
100
%
{
box-shadow
:
0
0
5px
currentColor
;
}
50
%
{
box-shadow
:
0
0
20px
currentColor
,
0
0
30px
currentColor
;
}
}
.absolute.inset-0
.absolute
{
animation
:
particleFloat
8s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
&:nth-child(1)
{
animation
:
particleFloat
10s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
2
)
{
animation
:
particleFloat
9s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
3
)
{
animation
:
particleFloat
11s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
4
)
{
animation
:
particleFloat
8.5s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
5
)
{
animation
:
particleFloat
10.5s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:hover
{
animation
:
particleGlow
3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
,
box-shadow
;
}
}
.backdrop-blur-sm
{
-webkit-backdrop-filter
:
blur
(
8px
);
backdrop-filter
:
blur
(
8px
);
}
.absolute
{
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
will-change
:
transform
,
opacity
;
backface-visibility
:
hidden
;
-webkit-backface-visibility
:
hidden
;
transform-style
:
preserve-3d
;
-webkit-transform-style
:
preserve-3d
;
}
*
{
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
}
.background-animations
,
.background-animations
.absolute
,
.group
,
.absolute.inset-0
.absolute
{
transform
:
translateZ
(
0
);
-webkit-transform
:
translateZ
(
0
);
backface-visibility
:
hidden
;
-webkit-backface-visibility
:
hidden
;
}
.group
{
animation
:
fadeInScale
0.8s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
transform
:
none
;
will-change
:
transform
,
opacity
;
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
&:hover
{
animation
:
float
3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
transform
:
translateY
(
-8px
)
scale
(
1.02
);
will-change
:
transform
,
opacity
;
}
}
.floating-circle-2
{
animation-delay
:
2s
;
}
.floating-circle-3
{
animation-delay
:
4s
;
}
.particle-1
{
animation-delay
:
0s
;
}
.particle-2
{
animation-delay
:
1s
;
}
.particle-3
{
animation-delay
:
2s
;
}
.particle-4
{
animation-delay
:
3s
;
}
.particle-5
{
animation-delay
:
4s
;
}
.grid-pattern
{
background-image
:
radial-gradient
(
circle
at
1px
1px
,
rgba
(
99
,
102
,
241
,
0.15
)
1px
,
transparent
0
);
background-size
:
40px
40px
;
}
.wave-gradient
{
background
:
linear-gradient
(
to
top
,
rgba
(
99
,
102
,
241
,
0.1
),
transparent
);
background-image
:
linear-gradient
(
to
top
,
rgba
(
99
,
102
,
241
,
0.1
),
transparent
);
}
.main-bg-gradient
{
background
:
linear-gradient
(
135deg
,
#e0e7ff
0%
,
#ffffff
50%
,
#ecfeff
100%
);
}
.floating-circle-1
{
background
:
linear-gradient
(
135deg
,
rgba
(
59
,
130
,
246
,
0.2
)
0%
,
rgba
(
147
,
51
,
234
,
0.2
)
100%
);
}
.floating-circle-2
{
background
:
linear-gradient
(
135deg
,
rgba
(
244
,
114
,
182
,
0.2
)
0%
,
rgba
(
249
,
115
,
22
,
0.2
)
100%
);
}
.floating-circle-3
{
background
:
linear-gradient
(
135deg
,
rgba
(
34
,
197
,
94
,
0.2
)
0%
,
rgba
(
20
,
184
,
166
,
0.2
)
100%
);
}
.glassmorphism-overlay
{
background
:
linear-gradient
(
135deg
,
rgba
(
255
,
255
,
255
,
0.1
)
0%
,
rgba
(
255
,
255
,
255
,
0.05
)
100%
);
}
.glass-card
{
background
:
rgba
(
255
,
255
,
255
,
0.8
);
-webkit-backdrop-filter
:
blur
(
8px
);
backdrop-filter
:
blur
(
8px
);
border-radius
:
1rem
;
padding
:
1.5rem
;
box-shadow
:
0
25px
50px
-12px
rgba
(
0
,
0
,
0
,
0.25
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.2
);
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
&:hover
{
box-shadow
:
0
25px
50px
-12px
rgba
(
0
,
0
,
0
,
0.4
);
transform
:
translateY
(
-8px
);
}
}
.glass-status
{
background
:
rgba
(
255
,
255
,
255
,
0.8
);
-webkit-backdrop-filter
:
blur
(
8px
);
backdrop-filter
:
blur
(
8px
);
border-radius
:
9999px
;
padding
:
0.5rem
1rem
;
box-shadow
:
0
8px
32px
0
rgba
(
31
,
38
,
135
,
0.37
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.18
);
}
.bg-white
\
/
80
{
background-color
:
rgba
(
255
,
255
,
255
,
0.8
);
}
.backdrop-blur-sm
{
-webkit-backdrop-filter
:
blur
(
4px
);
backdrop-filter
:
blur
(
4px
);
}
.rounded-2xl
{
border-radius
:
1rem
;
}
.p-6
{
padding
:
1.5rem
;
}
.shadow-xl
{
box-shadow
:
0
25px
50px
-12px
rgba
(
0
,
0
,
0
,
0.25
);
}
.border-white
\
/
20
{
border-color
:
rgba
(
255
,
255
,
255
,
0.2
);
}
.hover
\
:shadow-2xl:hover
{
box-shadow
:
0
25px
50px
-12px
rgba
(
0
,
0
,
0
,
0.4
);
}
.transition-all
{
transition-property
:
all
;
transition-timing-function
:
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
transition-duration
:
150ms
;
}
.duration-300
{
transition-duration
:
300ms
;
}
.transform
{
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.hover
\
:-translate-y-2:hover
{
--tw-translate-y
:
-0.5rem
;
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.w-16
{
width
:
4rem
;
}
.h-16
{
height
:
4rem
;
}
.bg-gradient-to-br
{
background-image
:
linear-gradient
(
to
bottom
right
,
var
(
--tw-gradient-stops
));
}
.from-blue-500
{
--tw-gradient-from
:
#3b82f6
;
--tw-gradient-to
:
rgba
(
59
,
131
,
246
,
0.997
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-blue-600
{
--tw-gradient-to
:
#2563eb
;
}
.flex
{
display
:
flex
;
}
.items-center
{
align-items
:
center
;
}
.justify-center
{
justify-content
:
center
;
}
.text-white
{
color
:
#ffffff
;
}
.text-2xl
{
font-size
:
1.5rem
;
line-height
:
2rem
;
}
.shadow-lg
{
box-shadow
:
0
10px
15px
-3px
rgba
(
0
,
0
,
0
,
0.1
),
0
4px
6px
-2px
rgba
(
0
,
0
,
0
,
0.05
);
}
.group
:hover
.group-hover
\
:scale-110
{
--tw-scale-x
:
1.1
;
--tw-scale-y
:
1.1
;
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.transition-transform
{
transition-property
:
transform
;
transition-timing-function
:
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
transition-duration
:
150ms
;
}
:root
{
--tw-gradient-from
:
#3b82f6
;
--tw-gradient-to
:
rgba
(
59
,
130
,
246
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.from-green-500
{
--tw-gradient-from
:
#10b981
;
--tw-gradient-to
:
rgba
(
16
,
185
,
129
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-green-600
{
--tw-gradient-to
:
#059669
;
}
.from-purple-500
{
--tw-gradient-from
:
#8b5cf6
;
--tw-gradient-to
:
rgba
(
139
,
92
,
246
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-purple-600
{
--tw-gradient-to
:
#7c3aed
;
}
.from-orange-500
{
--tw-gradient-from
:
#f97316
;
--tw-gradient-to
:
rgba
(
249
,
115
,
22
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-orange-600
{
--tw-gradient-to
:
#ea580c
;
}
.from-indigo-500
{
--tw-gradient-from
:
#6366f1
;
--tw-gradient-to
:
rgba
(
24
,
27
,
214
,
0.907
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-indigo-600
{
--tw-gradient-to
:
#4f46e5
;
}
.w-12
{
width
:
3rem
;
}
.h-12
{
height
:
3rem
;
}
.w-20
{
width
:
5rem
;
}
.h-20
{
height
:
5rem
;
}
.w-24
{
width
:
6rem
;
}
.h-24
{
height
:
6rem
;
}
.w-32
{
width
:
8rem
;
}
.h-32
{
height
:
8rem
;
}
.w-40
{
width
:
10rem
;
}
.h-40
{
height
:
10rem
;
}
.w-64
{
width
:
16rem
;
}
.h-64
{
height
:
16rem
;
}
.w-80
{
width
:
20rem
;
}
.h-80
{
height
:
20rem
;
}
.w-96
{
width
:
24rem
;
}
.h-96
{
height
:
24rem
;
}
.company-logo-gradient
{
background
:
linear-gradient
(
180deg
,
#1e40af
0%
,
#3b82f6
25%
,
#ffffff
50%
,
#dc2626
75%
,
#ef4444
100%
);
}
.company-blue-circle
{
background
:
linear-gradient
(
135deg
,
rgba
(
30
,
64
,
175
,
0.3
)
0%
,
rgba
(
59
,
130
,
246
,
0.2
)
100%
);
}
.company-red-circle
{
background
:
linear-gradient
(
135deg
,
rgba
(
220
,
38
,
38
,
0.3
)
0%
,
rgba
(
239
,
68
,
68
,
0.2
)
100%
);
}
.company-blue-light
{
background
:
linear-gradient
(
135deg
,
rgba
(
59
,
130
,
246
,
0.2
)
0%
,
rgba
(
30
,
64
,
175
,
0.1
)
100%
);
}
.company-grid-pattern
{
background-image
:
radial-gradient
(
circle
at
1px
1px
,
rgba
(
30
,
64
,
175
,
0.2
)
1px
,
transparent
0
);
background-size
:
40px
40px
;
}
.company-wave-gradient
{
background
:
linear-gradient
(
to
top
,
rgba
(
30
,
64
,
175
,
0.15
),
transparent
);
background-image
:
linear-gradient
(
to
top
,
rgba
(
30
,
64
,
175
,
0.15
),
transparent
);
}
.company-blue
{
color
:
#1e40af
;
}
.company-red
{
color
:
#dc2626
;
}
.company-blue-bg
{
background-color
:
#1e40af
;
}
.company-red-bg
{
background-color
:
#dc2626
;
}
.company-blue-light-bg
{
background-color
:
#3b82f6
;
}
.company-red-light-bg
{
background-color
:
#ef4444
;
}
.company-title-gradient
{
background
:
linear-gradient
(
135deg
,
#ffffff
0%
,
#3b82f6
25%
,
#e4d2d2
75%
,
#ffffff
100%
);
-webkit-background-clip
:
text
;
background-clip
:
text
;
-webkit-text-fill-color
:
transparent
;
}
.mt-4
{
margin-top
:
1rem
;
}
.w-full
{
width
:
100%
;
}
.bg-gradient-to-r
{
background-image
:
linear-gradient
(
to
right
,
var
(
--tw-gradient-stops
));
}
.from-red-500
{
--tw-gradient-from
:
#ef4444
;
--tw-gradient-to
:
rgba
(
239
,
68
,
68
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-pink-600
{
--tw-gradient-to
:
#db2777
;
}
.hover
\
:from-red-600:hover
{
--tw-gradient-from
:
#dc2626
;
--tw-gradient-to
:
rgba
(
220
,
38
,
38
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.hover
\
:to-pink-700:hover
{
--tw-gradient-to
:
#be185d
;
}
.text-white
{
color
:
#ffffff
;
}
.font-semibold
{
font-weight
:
600
;
}
.py-3
{
padding-top
:
0.75rem
;
padding-bottom
:
0.75rem
;
}
.px-4
{
padding-left
:
1rem
;
padding-right
:
1rem
;
}
.rounded-xl
{
border-radius
:
0.75rem
;
}
.transition-all
{
transition-property
:
all
;
transition-timing-function
:
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
transition-duration
:
150ms
;
}
.duration-300
{
transition-duration
:
300ms
;
}
.transform
{
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.hover
\
:scale-105:hover
{
--tw-scale-x
:
1.05
;
--tw-scale-y
:
1.05
;
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.shadow-lg
{
box-shadow
:
0
10px
15px
-3px
rgba
(
0
,
0
,
0
,
0.1
),
0
4px
6px
-2px
rgba
(
0
,
0
,
0
,
0.05
);
}
.hover
\
:shadow-xl:hover
{
box-shadow
:
0
20px
25px
-5px
rgba
(
0
,
0
,
0
,
0.1
),
0
10px
10px
-5px
rgba
(
0
,
0
,
0
,
0.04
);
}
.flex
{
display
:
flex
;
}
.items-center
{
align-items
:
center
;
}
.justify-center
{
justify-content
:
center
;
}
.space-x-2
>
:not
([
hidden
])
~
:not
([
hidden
])
{
margin-left
:
0.5rem
;
}
.from-red-600
{
--tw-gradient-from
:
#dc2626
;
--tw-gradient-to
:
rgba
(
220
,
38
,
38
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-pink-700
{
--tw-gradient-to
:
#be185d
;
}
:root
{
--tw-gradient-from
:
#ef4444
;
--tw-gradient-to
:
rgba
(
239
,
68
,
68
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.text-lg
{
font-size
:
1.125rem
;
line-height
:
1.75rem
;
}
.text-sm
{
font-size
:
0.875rem
;
line-height
:
1.25rem
;
}
.text-xs
{
font-size
:
0.75rem
;
line-height
:
1rem
;
}
.font-medium
{
font-weight
:
500
;
}
.font-bold
{
font-weight
:
700
;
}
.mb-1
{
margin-bottom
:
0.25rem
;
}
.mb-2
{
margin-bottom
:
0.5rem
;
}
.mb-4
{
margin-bottom
:
1rem
;
}
.mb-6
{
margin-bottom
:
1.5rem
;
}
.mb-8
{
margin-bottom
:
2rem
;
}
.mb-12
{
margin-bottom
:
3rem
;
}
.mr-1
{
margin-right
:
0.25rem
;
}
.mr-2
{
margin-right
:
0.5rem
;
}
.mr-3
{
margin-right
:
0.75rem
;
}
.ml-1
{
margin-left
:
0.25rem
;
}
.ml-2
{
margin-left
:
0.5rem
;
}
.ml-3
{
margin-left
:
0.75rem
;
}
.space-x-1
>
:not
([
hidden
])
~
:not
([
hidden
])
{
margin-left
:
0.25rem
;
}
.space-x-3
>
:not
([
hidden
])
~
:not
([
hidden
])
{
margin-left
:
0.75rem
;
}
.space-x-4
>
:not
([
hidden
])
~
:not
([
hidden
])
{
margin-left
:
1rem
;
}
.rounded-full
{
border-radius
:
9999px
;
}
.rounded-lg
{
border-radius
:
0.5rem
;
}
.rounded-md
{
border-radius
:
0.375rem
;
}
.rounded-sm
{
border-radius
:
0.25rem
;
}
.text-company-blue
{
color
:
#1e40af
;
}
.text-company-blue-light
{
color
:
#3b82f6
;
}
.text-company-blue-dark
{
color
:
#1e3a8a
;
}
.text-gray-800
{
color
:
#1e40af
;
}
.text-company-red
{
color
:
#dc2626
;
}
.text-company-red-light
{
color
:
#ef4444
;
}
.text-gray-600
{
color
:
#3b82f6
;
}
.text-gray-700
{
color
:
#1e40af
;
}
.text-gray-900
{
color
:
#1e3a8a
;
}
.bg-gray-50
{
background-color
:
#eff6ff
;
}
.bg-gray-100
{
background-color
:
#dbeafe
;
}
.bg-gray-200
{
background-color
:
#bfdbfe
;
}
.border-gray-200
{
border-color
:
#bfdbfe
;
}
.border-gray-300
{
border-color
:
#93c5fd
;
}
.ri-module-line
{
font-family
:
"remixicon"
!important
;
font-style
:
normal
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
display
:
inline-block
;
vertical-align
:
middle
;
}
.ri-module-line
::before
{
content
:
"\f1c0"
;
}
[
class
^=
"ri-"
],
[
class
*=
" ri-"
]
{
font-family
:
"remixicon"
!important
;
font-style
:
normal
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
display
:
inline-block
;
vertical-align
:
middle
;
line-height
:
1
;
}
.ri-module-line
:not
([
class
*=
"ri-"
])
::before
{
content
:
"📦"
;
font-family
:
"Apple Color Emoji"
,
"Segoe UI Emoji"
,
"Noto Color Emoji"
,
sans-serif
;
font-size
:
1.2em
;
}
src/app/portal-manage/permission-management/permission-appmodule/permission-appmodule.component.html
0 → 100644
View file @
419bf0fc
<app-page-header
[
title
]="'จัดการสิทธิ์แอปพลิเคชันบริษัท'"
[
activeTitle
]="'ผู้ดูแลระบบ'"
[
title1
]="'จัดการสิทธิ์แอปพลิเคชันบริษัท'"
></app-page-header>
<div
*
ngFor=
"let category of appCategories$ | async"
class=
"mb-12"
>
<div
class=
"flex items-center space-x-4"
>
<div
class=
"w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-xl flex items-center justify-center text-white text-xl shadow-lg"
>
<i
[
class
]="
category
.
icon
"
></i>
</div>
<div>
<h2
class=
"text-3xl font-bold bg-gradient-to-r from-gray-800 to-gray-600 bg-clip-text text-transparent mb-2"
>
{{ category.name }}
</h2>
<p
class=
"text-gray-600"
>
{{ category.description }}
</p>
</div>
</div>
<div
class=
"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 mt-6"
>
<div
*
ngFor=
"let app of category.apps; let i = index"
class=
"relative bg-white/80 backdrop-blur-sm rounded-2xl p-6 shadow-xl border border-white/20 hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-2"
>
<!-- App Icon -->
<div
class=
"relative mb-6"
>
<div
class=
"w-20 h-20 mx-auto bg-gradient-to-br from-indigo-100 to-purple-100 rounded-2xl flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform duration-300"
>
<img
[
src
]="
app
.
icon
"
alt=
"App Icon"
title=
"App Icon"
class=
"w-12 h-12 object-contain rounded-lg"
loading=
"lazy"
/>
</div>
<!-- Online Indicator -->
<div
class=
"absolute -top-1 -right-1 w-6 h-6 bg-green-500 rounded-full border-2 border-white flex items-center justify-center"
>
<div
class=
"w-2 h-2 bg-white rounded-full"
></div>
</div>
</div>
<!-- App Info -->
<div
class=
"text-center mb-4"
>
<h3
class=
"text-xl font-bold text-gray-800 mb-2 group-hover:text-indigo-600 transition-colors duration-300"
>
{{ app.displayName }}
</h3>
<p
class=
"text-gray-600 text-sm leading-relaxed"
>
{{ app.description }}
</p>
</div>
<!-- Action Button -->
<div
class=
"flex items-center justify-center mt-auto pt-4"
(
click
)="
navigateToApp
(
app
)"
>
<div
class=
"inline-flex items-center px-4 py-2 bg-gradient-to-r from-indigo-500 to-purple-600 text-white text-sm font-semibold rounded-xl group-hover:from-indigo-600 group-hover:to-purple-700 transition-all duration-300 transform group-hover:scale-105 cursor-pointer"
>
<span>
กำหนดสิทธิ์
</span>
<i
class=
"ri-arrow-right-line ml-2 group-hover:translate-x-1 transition-transform duration-300"
>
</i>
</div>
</div>
</div>
</div>
</div>
src/app/portal-manage/permission-management/permission-appmodule/permission-appmodule.component.spec.ts
0 → 100644
View file @
419bf0fc
/* tslint:disable:no-unused-variable */
import
{
async
,
ComponentFixture
,
TestBed
}
from
'@angular/core/testing'
;
import
{
By
}
from
'@angular/platform-browser'
;
import
{
DebugElement
}
from
'@angular/core'
;
import
{
PermissionAppmoduleComponent
}
from
'./permission-appmodule.component'
;
describe
(
'PermissionAppmoduleComponent'
,
()
=>
{
let
component
:
PermissionAppmoduleComponent
;
let
fixture
:
ComponentFixture
<
PermissionAppmoduleComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
PermissionAppmoduleComponent
]
})
.
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
PermissionAppmoduleComponent
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
it
(
'should create'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
src/app/portal-manage/permission-management/permission-appmodule/permission-appmodule.component.ts
0 → 100644
View file @
419bf0fc
import
{
CommonModule
}
from
'@angular/common'
;
import
{
Component
,
OnInit
}
from
'@angular/core'
;
import
{
Router
,
RouterModule
}
from
'@angular/router'
;
import
{
SharedModule
}
from
'../../../shared/shared.module'
;
import
{
Observable
,
of
}
from
'rxjs'
;
import
{
TokenService
}
from
'../../../shared/services/token.service'
;
interface
AppModule
{
id
:
string
;
name
:
string
;
displayName
:
string
;
description
:
string
;
icon
:
string
;
path
:
string
;
isVisible
:
boolean
;
category
:
'applications'
|
'services'
|
'system'
;
permissions
:
{
view
:
boolean
;
create
:
boolean
;
edit
:
boolean
;
delete
:
boolean
;
export
:
boolean
;
import
:
boolean
;
};
}
interface
AppCategory
{
id
:
string
;
name
:
string
;
description
:
string
;
icon
:
string
;
apps
:
AppModule
[];
}
@
Component
({
selector
:
'app-permission-appmodule'
,
templateUrl
:
'./permission-appmodule.component.html'
,
styleUrls
:
[
'./permission-appmodule.component.css'
],
standalone
:
true
,
imports
:
[
RouterModule
,
CommonModule
,
SharedModule
]
})
export
class
PermissionAppmoduleComponent
implements
OnInit
{
accessibleApps$
:
Observable
<
AppModule
[]
>
|
undefined
;
appCategories$
:
Observable
<
AppCategory
[]
>
|
undefined
;
constructor
(
private
tokenService
:
TokenService
,
private
router
:
Router
)
{
}
ngOnInit
()
{
this
.
loadAppCategories
();
}
private
loadAppCategories
():
void
{
this
.
appCategories$
=
of
(
this
.
getAppCategories
());
}
private
loadAccessibleApps
():
void
{
// แสดงทุกเมนูก่อน โดยไม่ต้องตรวจสอบสิทธิ์
this
.
accessibleApps$
=
of
(
this
.
getAppModules
());
}
private
getAppCategories
():
AppCategory
[]
{
const
apps
=
this
.
getAppModules
();
return
[
{
id
:
'applications'
,
name
:
'แอปพลิเคชันที่เข้าถึงได้'
,
description
:
'แอปพลิเคชันหลักสำหรับการทำงานประจำวัน'
,
icon
:
'ri-apps-line'
,
apps
:
apps
.
filter
(
app
=>
app
.
category
===
'applications'
)
},
];
}
private
getAppModules
():
AppModule
[]
{
return
[
// แอปพลิเคชันที่เข้าถึงได้
{
id
:
'myhr-plus'
,
name
:
'myhr-plus'
,
displayName
:
'myHR-Plus'
,
description
:
'ระบบจัดการทรัพยากรบุคคลขั้นสูง'
,
icon
:
'./assets/images/logoallHR/myhr-plus.jpg'
,
path
:
'/portal-manage/myhr-plus'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'myhr-lite'
,
name
:
'myhr-lite'
,
displayName
:
'myHR-Lite'
,
description
:
'ระบบจัดการทรัพยากรบุคคลพื้นฐาน'
,
icon
:
'./assets/images/logoallHR/myHR-Lite-logo-new.png'
,
path
:
'/portal-manage/myhr-lite'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'zeeme'
,
name
:
'zeeme'
,
displayName
:
'Zeeme Plus'
,
description
:
'ระบบจัดการเวลาและลงเวลา'
,
icon
:
'./assets/images/logoallHR/zeemePlus.png'
,
path
:
'/portal-manage/zeeme'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'myface'
,
name
:
'myface'
,
displayName
:
'myFace'
,
description
:
'ระบบจัดการใบหน้าและความปลอดภัย'
,
icon
:
'./assets/images/logoallHR/logo_myface.png'
,
path
:
'/portal-manage/myface'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'mylearn'
,
name
:
'mylearn'
,
displayName
:
'myLearn'
,
description
:
'ระบบจัดการการเรียนรู้และฝึกอบรม'
,
icon
:
'./assets/images/logoallHR/mylearn-logo.png'
,
path
:
'/portal-manage/mylearn'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'myjob'
,
name
:
'myjob'
,
displayName
:
'myJob'
,
description
:
'ระบบจัดการงานและโครงการ'
,
icon
:
'./assets/images/logoallHR/logo_myjob.png'
,
path
:
'/portal-manage/myjob'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'myskill-x'
,
name
:
'myskill-x'
,
displayName
:
'mySkill-X'
,
description
:
'ระบบจัดการทักษะและความสามารถ'
,
icon
:
'./assets/images/logoallHR/mySkill-x.png'
,
path
:
'/portal-manage/myskill-x'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'meetingBooking'
,
name
:
'meeting-booking'
,
displayName
:
'Meeting Booking'
,
description
:
'ระบบจองห้องประชุม'
,
icon
:
'./assets/images/logoallHR/booking.png'
,
path
:
'/portal-manage/meeting-booking'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
// การตั้งค่าระบบ
{
id
:
'permissionManagement'
,
name
:
'permission-management'
,
displayName
:
'Permission Management'
,
description
:
'ระบบจัดการสิทธิ์และบทบาท'
,
icon
:
'./assets/images/logoallHR/permission.png'
,
path
:
'/portal-manage/permission-management'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'dashboardManagement'
,
name
:
'dashboard-management'
,
displayName
:
'Dashboard Management'
,
description
:
'ระบบจัดการแดชบอร์ด และคลังวิดเจ็ต'
,
icon
:
'./assets/images/logoallHR/widget.webp'
,
path
:
'/portal-manage/dashboard-management'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'my-portal'
,
name
:
'my-portal'
,
displayName
:
'my-Portal'
,
description
:
'ระบบจัดการเอกสารและเมนูกลางสำหรับแอปพลิเคชันต่างๆ'
,
icon
:
'./assets/images/logoallHR/portal.webp'
,
path
:
'/portal-manage/my-portal'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
}
];
}
navigateToApp
(
app
:
AppModule
)
{
}
onToggleAppVisibility
(
app
:
AppModule
,
event
:
Event
)
{
const
input
=
event
.
target
as
HTMLInputElement
;
app
.
isVisible
=
input
.
checked
;
console
.
log
(
`Toggled
${
app
.
name
}
:
${
app
.
isVisible
}
`
);
// Here you would typically call a service to save this change
}
}
src/app/portal-manage/permission-management/permission-employeelist/permission-employeelist.component.html
View file @
419bf0fc
...
@@ -93,7 +93,7 @@
...
@@ -93,7 +93,7 @@
</td> -->
</td> -->
<td>
<td>
<div
class=
"flex flex-row items-center !gap-2 "
>
<div
class=
"flex flex-row items-center !gap-2 "
>
<a
aria-label=
"anchor"
(
click
)="
view
(
item
)"
data-hs-overlay=
"#modal-detail
"
<a
aria-label=
"anchor"
[
routerLink
]="['../
permission-menumodule
']
"
class=
"ti-btn ti-btn-wave !gap-0 !m-0 bg-info/10 text-info hover:bg-info hover:text-white hover:border-info"
>
class=
"ti-btn ti-btn-wave !gap-0 !m-0 bg-info/10 text-info hover:bg-info hover:text-white hover:border-info"
>
<i
class=
"ri-pencil-line"
></i>
<i
class=
"ri-pencil-line"
></i>
</a>
</a>
...
...
src/app/portal-manage/permission-management/permission-employeelist/permission-employeelist.component.ts
View file @
419bf0fc
...
@@ -5,8 +5,6 @@ import { NgSelectModule } from '@ng-select/ng-select';
...
@@ -5,8 +5,6 @@ import { NgSelectModule } from '@ng-select/ng-select';
import
{
TranslateModule
,
TranslateService
}
from
'@ngx-translate/core'
;
import
{
TranslateModule
,
TranslateService
}
from
'@ngx-translate/core'
;
import
{
SharedModule
}
from
'../../../shared/shared.module'
;
import
{
SharedModule
}
from
'../../../shared/shared.module'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
DomSanitizer
,
SafeHtml
}
from
'@angular/platform-browser'
;
import
{
DomSanitizer
,
SafeHtml
}
from
'@angular/platform-browser'
;
import
swal
from
'sweetalert'
;
import
swal
from
'sweetalert'
;
import
{
MatPaginator
}
from
'@angular/material/paginator'
;
import
{
MatPaginator
}
from
'@angular/material/paginator'
;
...
@@ -110,55 +108,6 @@ export class PermissionEmployeelistComponent implements OnInit {
...
@@ -110,55 +108,6 @@ export class PermissionEmployeelistComponent implements OnInit {
}
}
}
}
// uploadConfig() {
// this.uploaderProfile = new FileUploader({
// url: environment.baseUrl + "/files/upload-image",
// isHTML5: true,
// authToken: this.tokenService.getToken()!,
// });
// this.uploaderProfile.onAfterAddingFile = (fileItem: FileItem) => {
// fileItem.withCredentials = false;
// this.uploadErrorMsg = "";
// while (this.uploaderProfile!.queue.length > 1) {
// this.uploaderProfile!.queue[0].remove();
// }
// if (fileItem.file.size > 5000000) {
// this.uploadErrorMsg = "maximum file size 5mb.";
// swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
// fileItem.isCancel = true;
// return;
// }
// if (fileItem.file.type!.indexOf("image") === -1) {
// this.uploadErrorMsg = "please upload image only.";
// swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
// fileItem.isCancel = true;
// return;
// }
// fileItem.upload();
// };
// this.uploaderProfile.onCompleteItem = (
// item: FileItem,
// response: string,
// status: number,
// headers: ParsedResponseHeaders
// ) => {
// if (item.isSuccess) {
// const res = JSON.parse(response);
// console.log("res", res);
// // this.selectModel.photoGraph = res.resultObject;
// swal(res.message, "บันทึกสำเร็จ", "success");
// } else {
// this.uploadErrorMsg = "cannot upload file.";
// swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
// }
// };
// }
getEmployeeList
()
{
getEmployeeList
()
{
this
.
permissionService
.
getAllEmployeesMini
().
subscribe
(
this
.
permissionService
.
getAllEmployeesMini
().
subscribe
(
...
@@ -190,12 +139,6 @@ export class PermissionEmployeelistComponent implements OnInit {
...
@@ -190,12 +139,6 @@ export class PermissionEmployeelistComponent implements OnInit {
this
.
getEmployeeList
();
this
.
getEmployeeList
();
}
}
// onEmailChange(email: string) {
// const lowerEmail = email.trim().toLowerCase();
// this.isEmailDuplicate = this.existingEmails.some(
// user => user.email && user.email.toLowerCase() === lowerEmail
// );
// }
filter
(
v
:
string
)
{
filter
(
v
:
string
)
{
return
this
.
itemsList
?.
filter
(
return
this
.
itemsList
?.
filter
(
...
@@ -208,26 +151,6 @@ export class PermissionEmployeelistComponent implements OnInit {
...
@@ -208,26 +151,6 @@ export class PermissionEmployeelistComponent implements OnInit {
);
);
}
}
// delete(item: PermissionModel2) {
// swal({
// title: "คุณแน่ใจหรือไม่?",
// text: "คุณจะไม่สามารถกู้คืนข้อมูลนี้ได้!",
// icon: "warning",
// dangerMode: true,
// buttons: ["ยกเลิก", "ใช่, ลบเลย!"],
// })
// .then((willDelete: any) => {
// if (willDelete) {
// this.permissionService.put(item).subscribe(result => {
// swal("ลบสำเร็จ!!", "ลบข้อมูลสำเร็จ", "success");
// this.ngOnInit();
// }, error => {
// console.error("เกิดข้อผิดพลาดในการลบ:", error);
// swal("ข้อผิดพลาด!!", "ไม่สามารถลบข้อมูลได้", "error");
// });
// }
// });
// }
new
()
{
new
()
{
this
.
action
=
'add'
;
this
.
action
=
'add'
;
...
@@ -249,94 +172,6 @@ export class PermissionEmployeelistComponent implements OnInit {
...
@@ -249,94 +172,6 @@ export class PermissionEmployeelistComponent implements OnInit {
this
.
confirmNewPassword
=
''
;
this
.
confirmNewPassword
=
''
;
}
}
view
(
item
:
PermissionModel2
)
{
this
.
action
=
'edit'
;
// this.selectModel = new PermissionModel2(item);
this
.
showPasswordFields
=
false
;
this
.
newPassword
=
''
;
this
.
confirmNewPassword
=
''
;
console
.
log
(
this
.
selectModel
);
}
// save() {
// swal({
// title: "คุณแน่ใจหรือไม่?",
// text: "คุณต้องการบันทึกหรือไม่",
// icon: "warning",
// dangerMode: false,
// buttons: ["ยกเลิก", "ยืนยัน"],
// })
// .then((willSave: any) => {
// if (willSave) {
// if (this.action === 'add') {
// const body = new AuthModel();
// body.username = this.selectModel.email;
// body.password = this.password;
// body.role = new RoleModel({ roleId: 'employer' });
// const rawCompany = { ...this.selectModel };
// body.company = new PermissionModel(rawCompany);
// body.company.status = 1; // Fix status to 1 on creation
// this.userService.registerCompany(body).subscribe({
// next: res => {
// swal("Save Success!!", "บันทึกข้อมูลบริษัท", "success");
// // Optimistic UI Update
// const newCompany = new PermissionModel(this.selectModel, this.translate);
// newCompany.status = 1; // Ensure status is 1 in the UI as well
// this.itemsList.unshift(newCompany);
// this.filterList.unshift(newCompany);
// this.updatePagedItems();
// this.childModal?.nativeElement.click();
// },
// error: err => {
// console.error('Error response:', err);
// const errorMessage = err?.error?.message || err?.message || 'ไม่ทราบสาเหตุ';
// if (errorMessage.includes('email')) {
// swal("Save Failed", "อีเมลซ้ำหรือไม่ถูกต้อง", "warning");
// } else {
// swal("Error", errorMessage, "error");
// }
// }
// });
// } else if (this.action === 'edit') {
// const observables: Observable<any>[] = [];
// // Observable for updating company details
// // observables.push(this.permissionService.saveOrUpdateCompany(this.selectModel));
// // Check if password needs to be updated
// if (this.showPasswordFields && this.newPassword && this.newPassword.length >= 8 && this.newPassword === this.confirmNewPassword) {
// const authData = new AuthModel();
// authData.username = this.selectModel.email;
// authData.password = this.newPassword;
// authData.company = new PermissionModel2({ employeeId: this.selectModel.employeeId });
// // Observable for updating password
// observables.push(this.userService.editPasswordCompany(authData));
// } else if (this.showPasswordFields && (this.newPassword || this.confirmNewPassword)) {
// // If password fields are shown but validation fails, show an error and stop.
// swal("Invalid Password", "Please ensure passwords match and are at least 8 characters long.", "warning");
// return; // Stop the save process
// }
// forkJoin(observables).subscribe({
// next: results => {
// swal("Update Success!!", "บันทึกข้อมูลบริษัทเรียบร้อยแล้ว", "success");
// this.ngOnInit();
// this.childModal?.nativeElement.click();
// },
// error: err => {
// console.error('Update failed:', err);
// swal("Error", "เกิดข้อผิดพลาดในการอัปเดตข้อมูล", "error");
// }
// });
// }
// }
// });
// }
updatePagedItems
()
{
updatePagedItems
()
{
this
.
totalCount
=
this
.
filterList
.
length
;
this
.
totalCount
=
this
.
filterList
.
length
;
...
@@ -364,98 +199,6 @@ export class PermissionEmployeelistComponent implements OnInit {
...
@@ -364,98 +199,6 @@ export class PermissionEmployeelistComponent implements OnInit {
this
.
someSelected
=
this
.
itemsList
.
some
(
item
=>
this
.
selectedItems
.
get
(
item
.
employeeId
));
this
.
someSelected
=
this
.
itemsList
.
some
(
item
=>
this
.
selectedItems
.
get
(
item
.
employeeId
));
}
}
// deleteSelect() {
// let employerInfo = '';
// this.selectedItems.forEach((isSelected, employeeId) => {
// if (isSelected) {
// const com = this.itemsList.find(com => com.employeeId === employeeId);
// if (com) {
// employerInfo += `${this.translate.instant('Fullname')}: ${com.getName()}\n`;
// }
// }
// });
// swal({
// title: "Are you sure?",
// text: employerInfo,
// icon: "warning",
// dangerMode: true,
// buttons: ["Cancel", "Yes, Delete it!"],
// })
// .then((willDelete: any) => {
// if (willDelete) {
// this.selectedItems.forEach((isSelected, employeeId) => {
// if (isSelected) {
// const com = this.itemsList.find(com => com.employeeId === employeeId);
// if (com) {
// this.permissionService.put(com).subscribe(result => {
// swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
// this.ngOnInit();
// });
// }
// }
// });
// }
// });
// }
// adjustSelect(status: number) {
// let title = "คุณแน่ใจหรือไม่?";
// let companyInfo = '';
// const selectedCompanies: PermissionModel2[] = [];
// this.selectedItems.forEach((isSelected, employeeId) => {
// if (isSelected) {
// const company = this.itemsList.find(c => c.employeeId === employeeId);
// if (company) {
// companyInfo += `${this.translate.instant('ชื่อบริษัท')}: ${company.fname}\n`;
// selectedCompanies.push(company);
// }
// }
// });
// if (selectedCompanies.length === 0) {
// swal("ข้อผิดพลาด", "กรุณาเลือกบริษัทที่ต้องการปรับสถานะ", "warning");
// return;
// }
// swal({
// title: title,
// text: companyInfo,
// icon: "warning",
// dangerMode: false,
// buttons: ["ยกเลิก", "ยืนยัน"],
// })
// .then((willAdjust: any) => {
// if (willAdjust) {
// const updatePromises = selectedCompanies.map(company => {
// company.status = status;
// console.log(company);
// const respone = new PermissionModel2(company);
// return this.permissionService.saveOrUpdateCompany(respone).toPromise()
// .then(() => true)
// .catch(error => {
// console.error(`Error updating status for company ${company.employeeId}:`, error);
// return false;
// });
// });
// Promise.all(updatePromises)
// .then(results => {
// const allSuccessful = results.every(success => success);
// if (allSuccessful) {
// swal("บันทึกสำเร็จ!!", "บันทึกข้อมูลสำเร็จ", "success");
// } else {
// swal("สำเร็จบางส่วน/ข้อผิดพลาด!!", "มีการอัปเดตสถานะบางส่วนไม่สำเร็จ หรือมีข้อผิดพลาด", "warning");
// }
// this.ngOnInit();
// this.selectedItems.clear();
// this.allSelected = false;
// this.someSelected = false;
// });
// }
// });
// }
triggerFileInput
():
void
{
triggerFileInput
():
void
{
if
(
this
.
profileChangeInputRef
)
{
if
(
this
.
profileChangeInputRef
)
{
this
.
profileChangeInputRef
.
nativeElement
.
click
();
this
.
profileChangeInputRef
.
nativeElement
.
click
();
...
...
src/app/portal-manage/permission-management/permission-employeelist/permission-menulist/permission-menulist.component.css
0 → 100644
View file @
419bf0fc
src/app/portal-manage/permission-management/permission-employeelist/permission-menulist/permission-menulist.component.html
0 → 100644
View file @
419bf0fc
<p>
permission-menulist works!
</p>
src/app/portal-manage/permission-management/permission-employeelist/permission-menulist/permission-menulist.component.spec.ts
0 → 100644
View file @
419bf0fc
/* tslint:disable:no-unused-variable */
import
{
async
,
ComponentFixture
,
TestBed
}
from
'@angular/core/testing'
;
import
{
By
}
from
'@angular/platform-browser'
;
import
{
DebugElement
}
from
'@angular/core'
;
import
{
PermissionMenulistComponent
}
from
'./permission-menulist.component'
;
describe
(
'PermissionMenulistComponent'
,
()
=>
{
let
component
:
PermissionMenulistComponent
;
let
fixture
:
ComponentFixture
<
PermissionMenulistComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
PermissionMenulistComponent
]
})
.
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
PermissionMenulistComponent
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
it
(
'should create'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
src/app/portal-manage/permission-management/permission-employeelist/permission-menulist/permission-menulist.component.ts
0 → 100644
View file @
419bf0fc
import
{
CommonModule
}
from
'@angular/common'
;
import
{
Component
,
OnInit
}
from
'@angular/core'
;
import
{
RouterModule
}
from
'@angular/router'
;
import
{
SharedModule
}
from
'../../../../shared/shared.module'
;
@
Component
({
selector
:
'app-permission-menulist'
,
templateUrl
:
'./permission-menulist.component.html'
,
styleUrls
:
[
'./permission-menulist.component.css'
],
standalone
:
true
,
imports
:
[
RouterModule
,
CommonModule
,
SharedModule
]
})
export
class
PermissionMenulistComponent
implements
OnInit
{
constructor
()
{
}
ngOnInit
()
{
}
}
src/app/portal-manage/permission-management/permission-employeelist/permission-menumodule/permission-menumodule.component.css
0 → 100644
View file @
419bf0fc
.container
{
max-width
:
1400px
;
}
@keyframes
float
{
0
%,
100
%
{
transform
:
translateY
(
0px
)
scale
(
1
);
opacity
:
0.9
;
}
25
%
{
transform
:
translateY
(
-5px
)
scale
(
1.01
);
opacity
:
1
;
}
50
%
{
transform
:
translateY
(
-10px
)
scale
(
1.02
);
opacity
:
1
;
}
75
%
{
transform
:
translateY
(
-5px
)
scale
(
1.01
);
opacity
:
1
;
}
}
@keyframes
pulse-glow
{
0
%,
100
%
{
box-shadow
:
0
0
20px
rgba
(
99
,
102
,
241
,
0.3
);
transform
:
scale
(
1
);
opacity
:
0.8
;
}
25
%
{
box-shadow
:
0
0
25px
rgba
(
99
,
102
,
241
,
0.4
);
transform
:
scale
(
1.02
);
opacity
:
0.9
;
}
50
%
{
box-shadow
:
0
0
30px
rgba
(
99
,
102
,
241
,
0.6
);
transform
:
scale
(
1.05
);
opacity
:
1
;
}
75
%
{
box-shadow
:
0
0
25px
rgba
(
99
,
102
,
241
,
0.5
);
transform
:
scale
(
1.03
);
opacity
:
0.95
;
}
}
@keyframes
slideInFromLeft
{
0
%
{
transform
:
translateX
(
-100px
)
scale
(
0.9
);
opacity
:
0
;
}
50
%
{
transform
:
translateX
(
-20px
)
scale
(
0.95
);
opacity
:
0.5
;
}
100
%
{
transform
:
translateX
(
0
)
scale
(
1
);
opacity
:
1
;
}
}
@keyframes
slideInFromRight
{
0
%
{
transform
:
translateX
(
100px
)
scale
(
0.9
);
opacity
:
0
;
}
50
%
{
transform
:
translateX
(
20px
)
scale
(
0.95
);
opacity
:
0.5
;
}
100
%
{
transform
:
translateX
(
0
)
scale
(
1
);
opacity
:
1
;
}
}
@keyframes
fadeInScale
{
0
%
{
transform
:
scale
(
0.8
)
translateY
(
20px
);
opacity
:
0
;
}
50
%
{
transform
:
scale
(
0.95
)
translateY
(
10px
);
opacity
:
0.7
;
}
100
%
{
transform
:
scale
(
1
)
translateY
(
0
);
opacity
:
1
;
}
}
.glass-effect
{
background
:
rgba
(
255
,
255
,
255
,
0.25
);
-webkit-backdrop-filter
:
blur
(
10px
);
backdrop-filter
:
blur
(
10px
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.18
);
box-shadow
:
0
8px
32px
0
rgba
(
31
,
38
,
135
,
0.37
);
}
.group
{
animation
:
fadeInScale
0.6s
ease-out
;
&:nth-child(1)
{
animation-delay
:
0.1s
;
}
&
:nth-child
(
2
)
{
animation-delay
:
0.2s
;
}
&
:nth-child
(
3
)
{
animation-delay
:
0.3s
;
}
&
:nth-child
(
4
)
{
animation-delay
:
0.4s
;
}
&
:nth-child
(
5
)
{
animation-delay
:
0.5s
;
}
&
:nth-child
(
6
)
{
animation-delay
:
0.6s
;
}
&
:nth-child
(
7
)
{
animation-delay
:
0.7s
;
}
&
:nth-child
(
8
)
{
animation-delay
:
0.8s
;
}
}
.group
:hover
{
animation
:
float
2s
ease-in-out
infinite
;
}
.gradient-text
{
background
:
linear-gradient
(
135deg
,
#667eea
0%
,
#764ba2
100%
);
-webkit-background-clip
:
text
;
-webkit-text-fill-color
:
transparent
;
background-clip
:
text
;
}
button
{
position
:
relative
;
overflow
:
hidden
;
&::before
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
-100%
;
width
:
100%
;
height
:
100%
;
background
:
linear-gradient
(
90deg
,
transparent
,
rgba
(
255
,
255
,
255
,
0.2
),
transparent
);
transition
:
left
0.5s
;
}
&
:hover::before
{
left
:
100%
;
}
}
.bg-white
\
/
80
{
position
:
relative
;
&::before
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
background
:
linear-gradient
(
135deg
,
rgba
(
255
,
255
,
255
,
0.1
),
rgba
(
255
,
255
,
255
,
0.05
));
border-radius
:
inherit
;
pointer-events
:
none
;
}
}
.bg-gradient-to-r
{
position
:
relative
;
overflow
:
hidden
;
&::after
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
0
;
bottom
:
0
;
right
:
0
;
background
:
linear-gradient
(
90deg
,
transparent
,
rgba
(
255
,
255
,
255
,
0.2
),
transparent
);
transform
:
translateX
(
-100%
);
animation
:
shimmer
2s
infinite
;
}
}
@keyframes
shimmer
{
0
%
{
transform
:
translateX
(
-100%
);
}
100
%
{
transform
:
translateX
(
100%
);
}
}
i
{
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
}
.group
:hover
i
{
transform
:
scale
(
1.1
)
rotate
(
5deg
);
}
.inline-flex
{
position
:
relative
;
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
&:hover
{
transform
:
translateY
(
-2px
)
scale
(
1.05
);
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.15
);
}
}
.space-y-4
>
*
{
position
:
relative
;
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
&::before
{
content
:
''
;
position
:
absolute
;
left
:
0
;
top
:
0
;
bottom
:
0
;
width
:
4px
;
background
:
linear-gradient
(
to
bottom
,
#3b82f6
,
#8b5cf6
);
border-radius
:
0
2px
2px
0
;
transform
:
scaleY
(
0
);
transition
:
transform
0.3s
ease
;
}
&
:hover::before
{
transform
:
scaleY
(
1
);
}
&
:hover
{
transform
:
translateX
(
8px
);
box-shadow
:
0
10px
25px
rgba
(
0
,
0
,
0
,
0.1
);
}
}
@media
(
max-width
:
1024px
)
{
.container
{
padding
:
1.5rem
;
}
.grid
{
gap
:
1.5rem
;
}
}
@media
(
max-width
:
768px
)
{
.container
{
padding
:
1rem
;
}
.grid
{
gap
:
1rem
;
}
.text-5xl
{
font-size
:
2.5rem
;
}
.text-6xl
{
font-size
:
3rem
;
}
.text-3xl
{
font-size
:
1.875rem
;
}
.text-2xl
{
font-size
:
1.5rem
;
}
.group
{
padding
:
1.5rem
;
}
}
@media
(
max-width
:
640px
)
{
.flex.justify-between
{
flex-direction
:
column
;
align-items
:
flex-start
;
gap
:
1.5rem
;
}
.text-right
{
text-align
:
left
;
}
.grid-cols-1
{
grid-template-columns
:
1
fr
;
}
.space-y-4
>
*
{
padding
:
1rem
;
}
}
.loading
{
opacity
:
0.6
;
pointer-events
:
none
;
position
:
relative
;
&::after
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
background
:
linear-gradient
(
90deg
,
transparent
,
rgba
(
255
,
255
,
255
,
0.4
),
transparent
);
animation
:
loading
1.5s
infinite
;
}
}
@keyframes
loading
{
0
%
{
transform
:
translateX
(
-100%
);
}
100
%
{
transform
:
translateX
(
100%
);
}
}
.empty-state
{
text-align
:
center
;
padding
:
4rem
2rem
;
color
:
#6b7280
;
position
:
relative
;
&::before
{
content
:
''
;
position
:
absolute
;
top
:
50%
;
left
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
width
:
200px
;
height
:
200px
;
background
:
radial-gradient
(
circle
,
rgba
(
99
,
102
,
241
,
0.1
)
0%
,
transparent
70%
);
border-radius
:
50%
;
animation
:
pulse
2s
infinite
;
}
.text-6xl
{
font-size
:
4rem
;
margin-bottom
:
1rem
;
opacity
:
0.5
;
animation
:
float
3s
ease-in-out
infinite
;
}
}
@keyframes
pulse
{
0
%,
100
%
{
transform
:
translate
(
-50%
,
-50%
)
scale
(
1
);
opacity
:
0.7
;
}
50
%
{
transform
:
translate
(
-50%
,
-50%
)
scale
(
1.1
);
opacity
:
0.3
;
}
}
.group
:focus
{
outline
:
2px
solid
#3b82f6
;
outline-offset
:
4px
;
border-radius
:
1rem
;
}
button
:focus
{
outline
:
2px
solid
#3b82f6
;
outline-offset
:
2px
;
}
::-webkit-scrollbar
{
width
:
8px
;
}
::-webkit-scrollbar-track
{
background
:
rgba
(
0
,
0
,
0
,
0.1
);
border-radius
:
4px
;
}
::-webkit-scrollbar-thumb
{
background
:
linear-gradient
(
135deg
,
#3b82f6
,
#8b5cf6
);
border-radius
:
4px
;
transition
:
background
0.3s
ease
;
}
::-webkit-scrollbar-thumb:hover
{
background
:
linear-gradient
(
135deg
,
#2563eb
,
#7c3aed
);
}
@media
print
{
.ti-btn
,
button
{
display
:
none
;
}
.group
{
break-inside
:
avoid
;
box-shadow
:
none
;
border
:
1px
solid
#000
;
background
:
white
!important
;
}
.bg-gradient-to-r
,
.bg-gradient-to-br
{
background
:
white
!important
;
color
:
black
!important
;
}
}
@media
(
prefers-color-scheme
:
dark
)
{
.bg-white
\
/
80
{
background
:
rgba
(
31
,
41
,
55
,
0.8
);
color
:
white
;
}
.text-gray-800
{
color
:
#f9fafb
;
}
.text-gray-600
{
color
:
#d1d5db
;
}
}
@keyframes
floatUpDown
{
0
%,
100
%
{
transform
:
translateY
(
0px
)
rotate
(
0deg
)
scale
(
1
);
opacity
:
0.8
;
}
25
%
{
transform
:
translateY
(
-15px
)
rotate
(
0.5deg
)
scale
(
1.02
);
opacity
:
0.9
;
}
50
%
{
transform
:
translateY
(
-25px
)
rotate
(
1deg
)
scale
(
1.05
);
opacity
:
1
;
}
75
%
{
transform
:
translateY
(
-10px
)
rotate
(
0.5deg
)
scale
(
1.02
);
opacity
:
0.9
;
}
}
@keyframes
drift
{
0
%
{
transform
:
translateX
(
0px
)
translateY
(
0px
)
scale
(
1
);
opacity
:
0.7
;
}
25
%
{
transform
:
translateX
(
20px
)
translateY
(
-20px
)
scale
(
1.03
);
opacity
:
0.8
;
}
50
%
{
transform
:
translateX
(
35px
)
translateY
(
-35px
)
scale
(
1.05
);
opacity
:
0.9
;
}
75
%
{
transform
:
translateX
(
15px
)
translateY
(
-15px
)
scale
(
1.02
);
opacity
:
0.8
;
}
100
%
{
transform
:
translateX
(
0px
)
translateY
(
0px
)
scale
(
1
);
opacity
:
0.7
;
}
}
@keyframes
rotate
{
0
%
{
transform
:
rotate
(
0deg
)
scale
(
1
);
opacity
:
0.6
;
}
50
%
{
transform
:
rotate
(
180deg
)
scale
(
1.1
);
opacity
:
0.8
;
}
100
%
{
transform
:
rotate
(
360deg
)
scale
(
1
);
opacity
:
0.6
;
}
}
@keyframes
shimmer
{
0
%
{
background-position
:
-200%
0
;
opacity
:
0.5
;
}
50
%
{
background-position
:
0%
0
;
opacity
:
0.8
;
}
100
%
{
background-position
:
200%
0
;
opacity
:
0.5
;
}
}
@keyframes
particleFloat
{
0
%,
100
%
{
transform
:
translateY
(
0px
)
translateX
(
0px
)
scale
(
1
);
opacity
:
0.4
;
}
25
%
{
transform
:
translateY
(
-8px
)
translateX
(
3px
)
scale
(
1.05
);
opacity
:
0.7
;
}
50
%
{
transform
:
translateY
(
-12px
)
translateX
(
-2px
)
scale
(
1.1
);
opacity
:
0.9
;
}
75
%
{
transform
:
translateY
(
-6px
)
translateX
(
4px
)
scale
(
1.03
);
opacity
:
0.6
;
}
}
@keyframes
particleGlow
{
0
%,
100
%
{
box-shadow
:
0
0
5px
currentColor
;
transform
:
scale
(
1
);
}
50
%
{
box-shadow
:
0
0
20px
currentColor
,
0
0
30px
currentColor
;
transform
:
scale
(
1.1
);
}
}
.background-animations
.absolute
{
&:nth-child(1)
{
animation
:
floatUpDown
12s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
2
)
{
animation
:
drift
16s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
3
)
{
animation
:
floatUpDown
14s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
}
.background-animations
.absolute.-top-40
{
animation
:
floatUpDown
20s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
.background-animations
.absolute.top-1
\
/
2
{
animation
:
drift
24s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
.background-animations
.absolute.bottom-0
{
animation
:
floatUpDown
22s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
.background-animations
.border
{
animation
:
rotate
40s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
&:nth-child(2)
{
animation
:
rotate
35s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
3
)
{
animation
:
rotate
45s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
}
@keyframes
particleFloat
{
0
%,
100
%
{
transform
:
translateY
(
0px
)
translateX
(
0px
)
scale
(
1
);
opacity
:
0.4
;
}
25
%
{
transform
:
translateY
(
-10px
)
translateX
(
5px
)
scale
(
1.1
);
opacity
:
0.8
;
}
50
%
{
transform
:
translateY
(
-5px
)
translateX
(
-5px
)
scale
(
0.9
);
opacity
:
0.6
;
}
75
%
{
transform
:
translateY
(
-15px
)
translateX
(
3px
)
scale
(
1.05
);
opacity
:
0.7
;
}
}
@keyframes
particleGlow
{
0
%,
100
%
{
box-shadow
:
0
0
5px
currentColor
;
}
50
%
{
box-shadow
:
0
0
20px
currentColor
,
0
0
30px
currentColor
;
}
}
.absolute.inset-0
.absolute
{
animation
:
particleFloat
8s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
&:nth-child(1)
{
animation
:
particleFloat
10s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
2
)
{
animation
:
particleFloat
9s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
3
)
{
animation
:
particleFloat
11s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
4
)
{
animation
:
particleFloat
8.5s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
reverse
;
will-change
:
transform
,
opacity
;
}
&
:nth-child
(
5
)
{
animation
:
particleFloat
10.5s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
;
}
&
:hover
{
animation
:
particleGlow
3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
will-change
:
transform
,
opacity
,
box-shadow
;
}
}
.backdrop-blur-sm
{
-webkit-backdrop-filter
:
blur
(
8px
);
backdrop-filter
:
blur
(
8px
);
}
.absolute
{
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
will-change
:
transform
,
opacity
;
backface-visibility
:
hidden
;
-webkit-backface-visibility
:
hidden
;
transform-style
:
preserve-3d
;
-webkit-transform-style
:
preserve-3d
;
}
*
{
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
}
.background-animations
,
.background-animations
.absolute
,
.group
,
.absolute.inset-0
.absolute
{
transform
:
translateZ
(
0
);
-webkit-transform
:
translateZ
(
0
);
backface-visibility
:
hidden
;
-webkit-backface-visibility
:
hidden
;
}
.group
{
animation
:
fadeInScale
0.8s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
transform
:
none
;
will-change
:
transform
,
opacity
;
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
&:hover
{
animation
:
float
3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
)
infinite
;
transform
:
translateY
(
-8px
)
scale
(
1.02
);
will-change
:
transform
,
opacity
;
}
}
.floating-circle-2
{
animation-delay
:
2s
;
}
.floating-circle-3
{
animation-delay
:
4s
;
}
.particle-1
{
animation-delay
:
0s
;
}
.particle-2
{
animation-delay
:
1s
;
}
.particle-3
{
animation-delay
:
2s
;
}
.particle-4
{
animation-delay
:
3s
;
}
.particle-5
{
animation-delay
:
4s
;
}
.grid-pattern
{
background-image
:
radial-gradient
(
circle
at
1px
1px
,
rgba
(
99
,
102
,
241
,
0.15
)
1px
,
transparent
0
);
background-size
:
40px
40px
;
}
.wave-gradient
{
background
:
linear-gradient
(
to
top
,
rgba
(
99
,
102
,
241
,
0.1
),
transparent
);
background-image
:
linear-gradient
(
to
top
,
rgba
(
99
,
102
,
241
,
0.1
),
transparent
);
}
.main-bg-gradient
{
background
:
linear-gradient
(
135deg
,
#e0e7ff
0%
,
#ffffff
50%
,
#ecfeff
100%
);
}
.floating-circle-1
{
background
:
linear-gradient
(
135deg
,
rgba
(
59
,
130
,
246
,
0.2
)
0%
,
rgba
(
147
,
51
,
234
,
0.2
)
100%
);
}
.floating-circle-2
{
background
:
linear-gradient
(
135deg
,
rgba
(
244
,
114
,
182
,
0.2
)
0%
,
rgba
(
249
,
115
,
22
,
0.2
)
100%
);
}
.floating-circle-3
{
background
:
linear-gradient
(
135deg
,
rgba
(
34
,
197
,
94
,
0.2
)
0%
,
rgba
(
20
,
184
,
166
,
0.2
)
100%
);
}
.glassmorphism-overlay
{
background
:
linear-gradient
(
135deg
,
rgba
(
255
,
255
,
255
,
0.1
)
0%
,
rgba
(
255
,
255
,
255
,
0.05
)
100%
);
}
.glass-card
{
background
:
rgba
(
255
,
255
,
255
,
0.8
);
-webkit-backdrop-filter
:
blur
(
8px
);
backdrop-filter
:
blur
(
8px
);
border-radius
:
1rem
;
padding
:
1.5rem
;
box-shadow
:
0
25px
50px
-12px
rgba
(
0
,
0
,
0
,
0.25
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.2
);
transition
:
all
0.3s
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
&:hover
{
box-shadow
:
0
25px
50px
-12px
rgba
(
0
,
0
,
0
,
0.4
);
transform
:
translateY
(
-8px
);
}
}
.glass-status
{
background
:
rgba
(
255
,
255
,
255
,
0.8
);
-webkit-backdrop-filter
:
blur
(
8px
);
backdrop-filter
:
blur
(
8px
);
border-radius
:
9999px
;
padding
:
0.5rem
1rem
;
box-shadow
:
0
8px
32px
0
rgba
(
31
,
38
,
135
,
0.37
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.18
);
}
.bg-white
\
/
80
{
background-color
:
rgba
(
255
,
255
,
255
,
0.8
);
}
.backdrop-blur-sm
{
-webkit-backdrop-filter
:
blur
(
4px
);
backdrop-filter
:
blur
(
4px
);
}
.rounded-2xl
{
border-radius
:
1rem
;
}
.p-6
{
padding
:
1.5rem
;
}
.shadow-xl
{
box-shadow
:
0
25px
50px
-12px
rgba
(
0
,
0
,
0
,
0.25
);
}
.border-white
\
/
20
{
border-color
:
rgba
(
255
,
255
,
255
,
0.2
);
}
.hover
\
:shadow-2xl:hover
{
box-shadow
:
0
25px
50px
-12px
rgba
(
0
,
0
,
0
,
0.4
);
}
.transition-all
{
transition-property
:
all
;
transition-timing-function
:
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
transition-duration
:
150ms
;
}
.duration-300
{
transition-duration
:
300ms
;
}
.transform
{
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.hover
\
:-translate-y-2:hover
{
--tw-translate-y
:
-0.5rem
;
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.w-16
{
width
:
4rem
;
}
.h-16
{
height
:
4rem
;
}
.bg-gradient-to-br
{
background-image
:
linear-gradient
(
to
bottom
right
,
var
(
--tw-gradient-stops
));
}
.from-blue-500
{
--tw-gradient-from
:
#3b82f6
;
--tw-gradient-to
:
rgba
(
59
,
131
,
246
,
0.997
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-blue-600
{
--tw-gradient-to
:
#2563eb
;
}
.flex
{
display
:
flex
;
}
.items-center
{
align-items
:
center
;
}
.justify-center
{
justify-content
:
center
;
}
.text-white
{
color
:
#ffffff
;
}
.text-2xl
{
font-size
:
1.5rem
;
line-height
:
2rem
;
}
.shadow-lg
{
box-shadow
:
0
10px
15px
-3px
rgba
(
0
,
0
,
0
,
0.1
),
0
4px
6px
-2px
rgba
(
0
,
0
,
0
,
0.05
);
}
.group
:hover
.group-hover
\
:scale-110
{
--tw-scale-x
:
1.1
;
--tw-scale-y
:
1.1
;
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.transition-transform
{
transition-property
:
transform
;
transition-timing-function
:
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
transition-duration
:
150ms
;
}
:root
{
--tw-gradient-from
:
#3b82f6
;
--tw-gradient-to
:
rgba
(
59
,
130
,
246
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.from-green-500
{
--tw-gradient-from
:
#10b981
;
--tw-gradient-to
:
rgba
(
16
,
185
,
129
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-green-600
{
--tw-gradient-to
:
#059669
;
}
.from-purple-500
{
--tw-gradient-from
:
#8b5cf6
;
--tw-gradient-to
:
rgba
(
139
,
92
,
246
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-purple-600
{
--tw-gradient-to
:
#7c3aed
;
}
.from-orange-500
{
--tw-gradient-from
:
#f97316
;
--tw-gradient-to
:
rgba
(
249
,
115
,
22
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-orange-600
{
--tw-gradient-to
:
#ea580c
;
}
.from-indigo-500
{
--tw-gradient-from
:
#6366f1
;
--tw-gradient-to
:
rgba
(
24
,
27
,
214
,
0.907
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-indigo-600
{
--tw-gradient-to
:
#4f46e5
;
}
.w-12
{
width
:
3rem
;
}
.h-12
{
height
:
3rem
;
}
.w-20
{
width
:
5rem
;
}
.h-20
{
height
:
5rem
;
}
.w-24
{
width
:
6rem
;
}
.h-24
{
height
:
6rem
;
}
.w-32
{
width
:
8rem
;
}
.h-32
{
height
:
8rem
;
}
.w-40
{
width
:
10rem
;
}
.h-40
{
height
:
10rem
;
}
.w-64
{
width
:
16rem
;
}
.h-64
{
height
:
16rem
;
}
.w-80
{
width
:
20rem
;
}
.h-80
{
height
:
20rem
;
}
.w-96
{
width
:
24rem
;
}
.h-96
{
height
:
24rem
;
}
.company-logo-gradient
{
background
:
linear-gradient
(
180deg
,
#1e40af
0%
,
#3b82f6
25%
,
#ffffff
50%
,
#dc2626
75%
,
#ef4444
100%
);
}
.company-blue-circle
{
background
:
linear-gradient
(
135deg
,
rgba
(
30
,
64
,
175
,
0.3
)
0%
,
rgba
(
59
,
130
,
246
,
0.2
)
100%
);
}
.company-red-circle
{
background
:
linear-gradient
(
135deg
,
rgba
(
220
,
38
,
38
,
0.3
)
0%
,
rgba
(
239
,
68
,
68
,
0.2
)
100%
);
}
.company-blue-light
{
background
:
linear-gradient
(
135deg
,
rgba
(
59
,
130
,
246
,
0.2
)
0%
,
rgba
(
30
,
64
,
175
,
0.1
)
100%
);
}
.company-grid-pattern
{
background-image
:
radial-gradient
(
circle
at
1px
1px
,
rgba
(
30
,
64
,
175
,
0.2
)
1px
,
transparent
0
);
background-size
:
40px
40px
;
}
.company-wave-gradient
{
background
:
linear-gradient
(
to
top
,
rgba
(
30
,
64
,
175
,
0.15
),
transparent
);
background-image
:
linear-gradient
(
to
top
,
rgba
(
30
,
64
,
175
,
0.15
),
transparent
);
}
.company-blue
{
color
:
#1e40af
;
}
.company-red
{
color
:
#dc2626
;
}
.company-blue-bg
{
background-color
:
#1e40af
;
}
.company-red-bg
{
background-color
:
#dc2626
;
}
.company-blue-light-bg
{
background-color
:
#3b82f6
;
}
.company-red-light-bg
{
background-color
:
#ef4444
;
}
.company-title-gradient
{
background
:
linear-gradient
(
135deg
,
#ffffff
0%
,
#3b82f6
25%
,
#e4d2d2
75%
,
#ffffff
100%
);
-webkit-background-clip
:
text
;
background-clip
:
text
;
-webkit-text-fill-color
:
transparent
;
}
.mt-4
{
margin-top
:
1rem
;
}
.w-full
{
width
:
100%
;
}
.bg-gradient-to-r
{
background-image
:
linear-gradient
(
to
right
,
var
(
--tw-gradient-stops
));
}
.from-red-500
{
--tw-gradient-from
:
#ef4444
;
--tw-gradient-to
:
rgba
(
239
,
68
,
68
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-pink-600
{
--tw-gradient-to
:
#db2777
;
}
.hover
\
:from-red-600:hover
{
--tw-gradient-from
:
#dc2626
;
--tw-gradient-to
:
rgba
(
220
,
38
,
38
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.hover
\
:to-pink-700:hover
{
--tw-gradient-to
:
#be185d
;
}
.text-white
{
color
:
#ffffff
;
}
.font-semibold
{
font-weight
:
600
;
}
.py-3
{
padding-top
:
0.75rem
;
padding-bottom
:
0.75rem
;
}
.px-4
{
padding-left
:
1rem
;
padding-right
:
1rem
;
}
.rounded-xl
{
border-radius
:
0.75rem
;
}
.transition-all
{
transition-property
:
all
;
transition-timing-function
:
cubic-bezier
(
0.4
,
0
,
0.2
,
1
);
transition-duration
:
150ms
;
}
.duration-300
{
transition-duration
:
300ms
;
}
.transform
{
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.hover
\
:scale-105:hover
{
--tw-scale-x
:
1.05
;
--tw-scale-y
:
1.05
;
transform
:
translateX
(
var
(
--tw-translate-x
,
0
))
translateY
(
var
(
--tw-translate-y
,
0
))
rotate
(
var
(
--tw-rotate
,
0
))
skewX
(
var
(
--tw-skew-x
,
0
))
skewY
(
var
(
--tw-skew-y
,
0
))
scaleX
(
var
(
--tw-scale-x
,
1
))
scaleY
(
var
(
--tw-scale-y
,
1
));
}
.shadow-lg
{
box-shadow
:
0
10px
15px
-3px
rgba
(
0
,
0
,
0
,
0.1
),
0
4px
6px
-2px
rgba
(
0
,
0
,
0
,
0.05
);
}
.hover
\
:shadow-xl:hover
{
box-shadow
:
0
20px
25px
-5px
rgba
(
0
,
0
,
0
,
0.1
),
0
10px
10px
-5px
rgba
(
0
,
0
,
0
,
0.04
);
}
.flex
{
display
:
flex
;
}
.items-center
{
align-items
:
center
;
}
.justify-center
{
justify-content
:
center
;
}
.space-x-2
>
:not
([
hidden
])
~
:not
([
hidden
])
{
margin-left
:
0.5rem
;
}
.from-red-600
{
--tw-gradient-from
:
#dc2626
;
--tw-gradient-to
:
rgba
(
220
,
38
,
38
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.to-pink-700
{
--tw-gradient-to
:
#be185d
;
}
:root
{
--tw-gradient-from
:
#ef4444
;
--tw-gradient-to
:
rgba
(
239
,
68
,
68
,
0
);
--tw-gradient-stops
:
var
(
--tw-gradient-from
),
var
(
--tw-gradient-to
);
}
.text-lg
{
font-size
:
1.125rem
;
line-height
:
1.75rem
;
}
.text-sm
{
font-size
:
0.875rem
;
line-height
:
1.25rem
;
}
.text-xs
{
font-size
:
0.75rem
;
line-height
:
1rem
;
}
.font-medium
{
font-weight
:
500
;
}
.font-bold
{
font-weight
:
700
;
}
.mb-1
{
margin-bottom
:
0.25rem
;
}
.mb-2
{
margin-bottom
:
0.5rem
;
}
.mb-4
{
margin-bottom
:
1rem
;
}
.mb-6
{
margin-bottom
:
1.5rem
;
}
.mb-8
{
margin-bottom
:
2rem
;
}
.mb-12
{
margin-bottom
:
3rem
;
}
.mr-1
{
margin-right
:
0.25rem
;
}
.mr-2
{
margin-right
:
0.5rem
;
}
.mr-3
{
margin-right
:
0.75rem
;
}
.ml-1
{
margin-left
:
0.25rem
;
}
.ml-2
{
margin-left
:
0.5rem
;
}
.ml-3
{
margin-left
:
0.75rem
;
}
.space-x-1
>
:not
([
hidden
])
~
:not
([
hidden
])
{
margin-left
:
0.25rem
;
}
.space-x-3
>
:not
([
hidden
])
~
:not
([
hidden
])
{
margin-left
:
0.75rem
;
}
.space-x-4
>
:not
([
hidden
])
~
:not
([
hidden
])
{
margin-left
:
1rem
;
}
.rounded-full
{
border-radius
:
9999px
;
}
.rounded-lg
{
border-radius
:
0.5rem
;
}
.rounded-md
{
border-radius
:
0.375rem
;
}
.rounded-sm
{
border-radius
:
0.25rem
;
}
.text-company-blue
{
color
:
#1e40af
;
}
.text-company-blue-light
{
color
:
#3b82f6
;
}
.text-company-blue-dark
{
color
:
#1e3a8a
;
}
.text-gray-800
{
color
:
#1e40af
;
}
.text-company-red
{
color
:
#dc2626
;
}
.text-company-red-light
{
color
:
#ef4444
;
}
.text-gray-600
{
color
:
#3b82f6
;
}
.text-gray-700
{
color
:
#1e40af
;
}
.text-gray-900
{
color
:
#1e3a8a
;
}
.bg-gray-50
{
background-color
:
#eff6ff
;
}
.bg-gray-100
{
background-color
:
#dbeafe
;
}
.bg-gray-200
{
background-color
:
#bfdbfe
;
}
.border-gray-200
{
border-color
:
#bfdbfe
;
}
.border-gray-300
{
border-color
:
#93c5fd
;
}
.ri-module-line
{
font-family
:
"remixicon"
!important
;
font-style
:
normal
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
display
:
inline-block
;
vertical-align
:
middle
;
}
.ri-module-line
::before
{
content
:
"\f1c0"
;
}
[
class
^=
"ri-"
],
[
class
*=
" ri-"
]
{
font-family
:
"remixicon"
!important
;
font-style
:
normal
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
display
:
inline-block
;
vertical-align
:
middle
;
line-height
:
1
;
}
.ri-module-line
:not
([
class
*=
"ri-"
])
::before
{
content
:
"📦"
;
font-family
:
"Apple Color Emoji"
,
"Segoe UI Emoji"
,
"Noto Color Emoji"
,
sans-serif
;
font-size
:
1.2em
;
}
src/app/portal-manage/permission-management/permission-employeelist/permission-menumodule/permission-menumodule.component.html
0 → 100644
View file @
419bf0fc
<app-page-header
[
title
]="'เลือกเมนู'"
[
activeTitle
]="'ผู้ดูแลระบบ'"
[
title1
]="'จัดการสิทธิ์พนักงาน'"
[
title1Link
]="'../
permission-employeelist
'"
[
title2
]="'แอพลิเคชันที่เข้าถึงได้'"
></app-page-header>
<div
*
ngFor=
"let category of appCategories$ | async"
class=
"mb-12"
>
<div
class=
"flex items-center space-x-4"
>
<div
class=
"w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-xl flex items-center justify-center text-white text-xl shadow-lg"
>
<i
[
class
]="
category
.
icon
"
></i>
</div>
<div>
<h2
class=
"text-3xl font-bold bg-gradient-to-r from-gray-800 to-gray-600 bg-clip-text text-transparent mb-2"
>
{{ category.name }}
</h2>
<p
class=
"text-gray-600"
>
{{ category.description }}
</p>
</div>
</div>
<div
class=
"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 mt-6"
>
<div
*
ngFor=
"let app of category.apps; let i = index"
class=
"relative bg-white/80 backdrop-blur-sm rounded-2xl p-6 shadow-xl border border-white/20 hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-2"
>
<!-- Toggle Switch -->
<div
class=
"absolute top-4 right-4 z-10"
(
click
)="$
event
.
stopPropagation
()"
>
<label
class=
"inline-flex items-center cursor-pointer"
>
<input
type=
"checkbox"
[
checked
]="
app
.
isVisible
"
(
change
)="
onToggleAppVisibility
(
app
,
$
event
)"
class=
"sr-only peer"
>
<div
class=
"relative w-11 h-6 bg-gray-300 rounded-full peer peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-300 dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600"
[
ngStyle
]="{
'
background-color
'
:
app
.
isVisible
?
'#
3b82f6
'
:
'#
d1d5db
'
}"
></div>
</label>
</div>
<!-- App Icon -->
<div
class=
"relative mb-6"
>
<div
class=
"w-20 h-20 mx-auto bg-gradient-to-br from-indigo-100 to-purple-100 rounded-2xl flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform duration-300"
>
<img
[
src
]="
app
.
icon
"
alt=
"App Icon"
title=
"App Icon"
class=
"w-12 h-12 object-contain rounded-lg"
loading=
"lazy"
/>
</div>
<!-- Online Indicator -->
<div
class=
"absolute -top-1 -right-1 w-6 h-6 bg-green-500 rounded-full border-2 border-white flex items-center justify-center"
>
<div
class=
"w-2 h-2 bg-white rounded-full"
></div>
</div>
</div>
<!-- App Info -->
<div
class=
"text-center mb-4"
>
<h3
class=
"text-xl font-bold text-gray-800 mb-2 group-hover:text-indigo-600 transition-colors duration-300"
>
{{ app.displayName }}
</h3>
<p
class=
"text-gray-600 text-sm leading-relaxed"
>
{{ app.description }}
</p>
</div>
<!-- Action Button -->
<div
class=
"flex items-center justify-center mt-auto pt-4"
(
click
)="
navigateToApp
(
app
)"
>
<div
class=
"inline-flex items-center px-4 py-2 bg-gradient-to-r from-indigo-500 to-purple-600 text-white text-sm font-semibold rounded-xl group-hover:from-indigo-600 group-hover:to-purple-700 transition-all duration-300 transform group-hover:scale-105 cursor-pointer"
>
<span>
กำหนดสิทธิ์
</span>
<i
class=
"ri-arrow-right-line ml-2 group-hover:translate-x-1 transition-transform duration-300"
>
</i>
</div>
</div>
</div>
</div>
</div>
src/app/portal-manage/permission-management/permission-employeelist/permission-menumodule/permission-menumodule.component.spec.ts
0 → 100644
View file @
419bf0fc
/* tslint:disable:no-unused-variable */
import
{
async
,
ComponentFixture
,
TestBed
}
from
'@angular/core/testing'
;
import
{
By
}
from
'@angular/platform-browser'
;
import
{
DebugElement
}
from
'@angular/core'
;
import
{
PermissionMenumoduleComponent
}
from
'./permission-menumodule.component'
;
describe
(
'PermissionMenumoduleComponent'
,
()
=>
{
let
component
:
PermissionMenumoduleComponent
;
let
fixture
:
ComponentFixture
<
PermissionMenumoduleComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
PermissionMenumoduleComponent
]
})
.
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
PermissionMenumoduleComponent
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
it
(
'should create'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
src/app/portal-manage/permission-management/permission-employeelist/permission-menumodule/permission-menumodule.component.ts
0 → 100644
View file @
419bf0fc
import
{
Component
,
OnInit
}
from
'@angular/core'
;
import
{
Router
,
RouterLink
,
RouterModule
}
from
'@angular/router'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
Observable
,
of
}
from
'rxjs'
;
import
{
SharedModule
}
from
'../../../../shared/shared.module'
;
import
{
TokenService
}
from
'../../../../shared/services/token.service'
;
interface
AppModule
{
id
:
string
;
name
:
string
;
displayName
:
string
;
description
:
string
;
icon
:
string
;
path
:
string
;
isVisible
:
boolean
;
category
:
'applications'
|
'services'
|
'system'
;
permissions
:
{
view
:
boolean
;
create
:
boolean
;
edit
:
boolean
;
delete
:
boolean
;
export
:
boolean
;
import
:
boolean
;
};
}
interface
AppCategory
{
id
:
string
;
name
:
string
;
description
:
string
;
icon
:
string
;
apps
:
AppModule
[];
}
@
Component
({
selector
:
'app-permission-menumodule'
,
templateUrl
:
'./permission-menumodule.component.html'
,
styleUrls
:
[
'./permission-menumodule.component.css'
],
standalone
:
true
,
imports
:
[
RouterModule
,
CommonModule
,
SharedModule
]
})
export
class
PermissionMenumoduleComponent
implements
OnInit
{
accessibleApps$
:
Observable
<
AppModule
[]
>
|
undefined
;
appCategories$
:
Observable
<
AppCategory
[]
>
|
undefined
;
constructor
(
private
tokenService
:
TokenService
,
private
router
:
Router
)
{
}
ngOnInit
()
{
this
.
loadAppCategories
();
}
private
loadAppCategories
():
void
{
this
.
appCategories$
=
of
(
this
.
getAppCategories
());
}
private
loadAccessibleApps
():
void
{
// แสดงทุกเมนูก่อน โดยไม่ต้องตรวจสอบสิทธิ์
this
.
accessibleApps$
=
of
(
this
.
getAppModules
());
}
private
getAppCategories
():
AppCategory
[]
{
const
apps
=
this
.
getAppModules
();
return
[
{
id
:
'applications'
,
name
:
'แอปพลิเคชันที่เข้าถึงได้'
,
description
:
'แอปพลิเคชันหลักสำหรับการทำงานประจำวัน'
,
icon
:
'ri-apps-line'
,
apps
:
apps
.
filter
(
app
=>
app
.
category
===
'applications'
)
},
];
}
private
getAppModules
():
AppModule
[]
{
return
[
// แอปพลิเคชันที่เข้าถึงได้
{
id
:
'myhr-plus'
,
name
:
'myhr-plus'
,
displayName
:
'myHR-Plus'
,
description
:
'ระบบจัดการทรัพยากรบุคคลขั้นสูง'
,
icon
:
'./assets/images/logoallHR/myhr-plus.jpg'
,
path
:
'/portal-manage/myhr-plus'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'myhr-lite'
,
name
:
'myhr-lite'
,
displayName
:
'myHR-Lite'
,
description
:
'ระบบจัดการทรัพยากรบุคคลพื้นฐาน'
,
icon
:
'./assets/images/logoallHR/myHR-Lite-logo-new.png'
,
path
:
'/portal-manage/myhr-lite'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'zeeme'
,
name
:
'zeeme'
,
displayName
:
'Zeeme Plus'
,
description
:
'ระบบจัดการเวลาและลงเวลา'
,
icon
:
'./assets/images/logoallHR/zeemePlus.png'
,
path
:
'/portal-manage/zeeme'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'myface'
,
name
:
'myface'
,
displayName
:
'myFace'
,
description
:
'ระบบจัดการใบหน้าและความปลอดภัย'
,
icon
:
'./assets/images/logoallHR/logo_myface.png'
,
path
:
'/portal-manage/myface'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'mylearn'
,
name
:
'mylearn'
,
displayName
:
'myLearn'
,
description
:
'ระบบจัดการการเรียนรู้และฝึกอบรม'
,
icon
:
'./assets/images/logoallHR/mylearn-logo.png'
,
path
:
'/portal-manage/mylearn'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'myjob'
,
name
:
'myjob'
,
displayName
:
'myJob'
,
description
:
'ระบบจัดการงานและโครงการ'
,
icon
:
'./assets/images/logoallHR/logo_myjob.png'
,
path
:
'/portal-manage/myjob'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'myskill-x'
,
name
:
'myskill-x'
,
displayName
:
'mySkill-X'
,
description
:
'ระบบจัดการทักษะและความสามารถ'
,
icon
:
'./assets/images/logoallHR/mySkill-x.png'
,
path
:
'/portal-manage/myskill-x'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'meetingBooking'
,
name
:
'meeting-booking'
,
displayName
:
'Meeting Booking'
,
description
:
'ระบบจองห้องประชุม'
,
icon
:
'./assets/images/logoallHR/booking.png'
,
path
:
'/portal-manage/meeting-booking'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
// การตั้งค่าระบบ
{
id
:
'permissionManagement'
,
name
:
'permission-management'
,
displayName
:
'Permission Management'
,
description
:
'ระบบจัดการสิทธิ์และบทบาท'
,
icon
:
'./assets/images/logoallHR/permission.png'
,
path
:
'/portal-manage/permission-management'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'dashboardManagement'
,
name
:
'dashboard-management'
,
displayName
:
'Dashboard Management'
,
description
:
'ระบบจัดการแดชบอร์ด และคลังวิดเจ็ต'
,
icon
:
'./assets/images/logoallHR/widget.webp'
,
path
:
'/portal-manage/dashboard-management'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
},
{
id
:
'my-portal'
,
name
:
'my-portal'
,
displayName
:
'my-Portal'
,
description
:
'ระบบจัดการเอกสารและเมนูกลางสำหรับแอปพลิเคชันต่างๆ'
,
icon
:
'./assets/images/logoallHR/portal.webp'
,
path
:
'/portal-manage/my-portal'
,
isVisible
:
true
,
category
:
'applications'
,
permissions
:
{
view
:
true
,
create
:
true
,
edit
:
true
,
delete
:
true
,
export
:
true
,
import
:
true
}
}
];
}
navigateToApp
(
app
:
AppModule
)
{
}
onToggleAppVisibility
(
app
:
AppModule
,
event
:
Event
)
{
const
input
=
event
.
target
as
HTMLInputElement
;
app
.
isVisible
=
input
.
checked
;
console
.
log
(
`Toggled
${
app
.
name
}
:
${
app
.
isVisible
}
`
);
// Here you would typically call a service to save this change
}
}
src/app/portal-manage/permission-management/permission-management.routes.ts
View file @
419bf0fc
...
@@ -13,6 +13,21 @@ export const PERMISSION_ROUTES: Routes = [
...
@@ -13,6 +13,21 @@ export const PERMISSION_ROUTES: Routes = [
loadComponent
:
()
=>
loadComponent
:
()
=>
import
(
'./permission-employeelist/permission-employeelist.component'
).
then
((
m
)
=>
m
.
PermissionEmployeelistComponent
),
import
(
'./permission-employeelist/permission-employeelist.component'
).
then
((
m
)
=>
m
.
PermissionEmployeelistComponent
),
},
},
{
path
:
'permission-menumodule'
,
loadComponent
:
()
=>
import
(
'./permission-employeelist/permission-menumodule/permission-menumodule.component'
).
then
((
m
)
=>
m
.
PermissionMenumoduleComponent
),
},
{
path
:
'permission-menulist'
,
loadComponent
:
()
=>
import
(
'./permission-employeelist/permission-menulist/permission-menulist.component'
).
then
((
m
)
=>
m
.
PermissionMenulistComponent
),
},
{
path
:
'permission-appmodule'
,
loadComponent
:
()
=>
import
(
'./permission-appmodule/permission-appmodule.component'
).
then
((
m
)
=>
m
.
PermissionAppmoduleComponent
),
},
]
]
}
}
];
];
src/app/shared/components/page-header/page-header.component.html
View file @
419bf0fc
...
@@ -9,8 +9,13 @@
...
@@ -9,8 +9,13 @@
<i
class=
"ti ti-chevrons-right flex-shrink-0 text-[#8c9097] dark:text-white/50 px-[0.5rem] overflow-visible rtl:rotate-180"
></i>
<i
class=
"ti ti-chevrons-right flex-shrink-0 text-[#8c9097] dark:text-white/50 px-[0.5rem] overflow-visible rtl:rotate-180"
></i>
</a>
</a>
</li>
</li>
<li
class=
"text-[0.813rem] text-primary font-semibold hover:text-primary dark:text-[#8c9097] dark:text-white/50 "
aria-current=
"page"
>
<li
class=
"text-[0.813rem] text-primary hover:text-primary dark:text-[#8c9097] dark:text-white/50"
>
{{title1 | translate}}
<a
*
ngIf=
"title1Link"
[
routerLink
]="
title1Link
"
class=
"flex items-center"
>
{{title1 | translate}}
</a>
<span
*
ngIf=
"!title1Link"
>
{{title1 | translate}}
</span>
</li>
<li
class=
"text-[0.813rem] text-primary font-semibold hover:text-primary dark:text-[#8c9097] dark:text-white/50 "
aria-current=
"page"
*
ngIf=
"title2"
>
<i
class=
"ti ti-chevrons-right flex-shrink-0 text-[#8c9097] dark:text-white/50 px-[0.5rem] overflow-visible rtl:rotate-180"
></i>
{{title2 | translate}}
</li>
</li>
</ol>
</ol>
</div>
</div>
src/app/shared/components/page-header/page-header.component.ts
View file @
419bf0fc
...
@@ -8,5 +8,7 @@ import { Component, Input } from '@angular/core';
...
@@ -8,5 +8,7 @@ import { Component, Input } from '@angular/core';
export
class
PageHeaderComponent
{
export
class
PageHeaderComponent
{
@
Input
()
title
!
:
string
;
@
Input
()
title
!
:
string
;
@
Input
()
title1
!
:
string
;
@
Input
()
title1
!
:
string
;
@
Input
()
title2
!
:
string
;
@
Input
()
activeTitle
!
:
string
;
@
Input
()
activeTitle
!
:
string
;
@
Input
()
title1Link
!
:
string
;
}
}
src/app/shared/services/nav.service.ts
View file @
419bf0fc
...
@@ -470,7 +470,7 @@ export class NavService implements OnDestroy {
...
@@ -470,7 +470,7 @@ export class NavService implements OnDestroy {
active
:
false
,
active
:
false
,
children
:
[
children
:
[
{
path
:
'/portal-manage/permission-management/permission-employeelist'
,
title
:
'จัดการสิทธิ์และบทบาท'
,
type
:
'link'
},
{
path
:
'/portal-manage/permission-management/permission-employeelist'
,
title
:
'จัดการสิทธิ์และบทบาท'
,
type
:
'link'
},
// { path: '/portal-manage/menu-permission-management', title: 'จัดการสิทธิ์เมนู
', type: 'link' },
{
path
:
'/portal-manage/permission-management/permission-appmodule'
,
title
:
'จัดการสิทธิ์แอปพลิเคชันบริษัท
'
,
type
:
'link'
},
// { path: '/portal-manage/user-role-management', title: 'จัดการผู้ใช้และบทบาท', type: 'link' },
// { path: '/portal-manage/user-role-management', title: 'จัดการผู้ใช้และบทบาท', type: 'link' },
],
],
},
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
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 comment